@sincpro/mobile-ui 0.7.2 → 1.1.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/README.md +575 -230
- package/dist/Actions/Actions.Button.d.ts +98 -93
- package/dist/Actions/Actions.Button.js +58 -52
- package/dist/Actions/Actions.FAB.d.ts +3 -1
- package/dist/Actions/Actions.FAB.js +12 -8
- package/dist/Actions/Actions.FilterButton.d.ts +10 -2
- package/dist/Actions/Actions.FilterButton.js +23 -8
- package/dist/Actions/Actions.IconButton.d.ts +36 -33
- package/dist/Actions/Actions.IconButton.js +10 -6
- package/dist/Actions/index.d.ts +12 -12
- package/dist/Actions/index.js +6 -6
- package/dist/Dialog/BottomSheet/BottomSheet.Root.js +1 -1
- package/dist/Dialog/BottomSheet/index.d.ts +1 -1
- package/dist/Dialog/BottomSheet/index.js +1 -1
- package/dist/Dialog/Confirmation.context.js +3 -3
- package/dist/Dialog/Dialog.ActionSheet.d.ts +2 -1
- package/dist/Dialog/Dialog.ActionSheet.js +19 -9
- package/dist/Dialog/Dialog.Confirmation.js +7 -7
- package/dist/Dialog/Dialog.EditValue.js +4 -4
- package/dist/Dialog/Dialog.NativeSheet.d.ts +10 -0
- package/dist/Dialog/Dialog.NativeSheet.js +21 -0
- package/dist/Dialog/Dialog.Sheet.d.ts +5 -1
- package/dist/Dialog/Dialog.Sheet.js +19 -11
- package/dist/Dialog/index.d.ts +5 -5
- package/dist/Dialog/index.js +5 -5
- package/dist/Display/Display.Accordion.js +5 -5
- package/dist/Display/Display.Avatar.d.ts +30 -30
- package/dist/Display/Display.Avatar.js +2 -2
- package/dist/Display/Display.AvatarGroup.js +3 -3
- package/dist/Display/Display.Badge.d.ts +3 -3
- package/dist/Display/Display.Badge.js +1 -1
- package/dist/Display/Display.Card.d.ts +15 -15
- package/dist/Display/Display.Card.js +4 -4
- package/dist/Display/Display.Carousel.js +2 -2
- package/dist/Display/Display.Chip.d.ts +3 -3
- package/dist/Display/Display.Chip.js +12 -12
- package/dist/Display/Display.CircleButton.d.ts +1 -1
- package/dist/Display/Display.CircleButton.js +3 -3
- package/dist/Display/Display.CopyableText.d.ts +9 -2
- package/dist/Display/Display.CopyableText.js +76 -8
- package/dist/Display/Display.CountRecords.js +2 -2
- package/dist/Display/Display.DataTable.js +2 -2
- package/dist/Display/Display.Date.d.ts +1 -1
- package/dist/Display/Display.Date.js +5 -5
- package/dist/Display/Display.Divider.d.ts +24 -24
- package/dist/Display/Display.Divider.js +1 -1
- package/dist/Display/Display.GradientSurface.d.ts +58 -39
- package/dist/Display/Display.GradientSurface.js +31 -15
- package/dist/Display/Display.Icon.d.ts +1 -1
- package/dist/Display/Display.Icon.js +2 -1
- package/dist/Display/Display.IconBadge.js +3 -3
- package/dist/Display/Display.Image.js +4 -4
- package/dist/Display/Display.KeyValue.d.ts +11 -4
- package/dist/Display/Display.KeyValue.js +8 -6
- package/dist/Display/Display.ListGroup.d.ts +23 -0
- package/dist/Display/Display.ListGroup.js +17 -0
- package/dist/Display/Display.ListItem.d.ts +16 -2
- package/dist/Display/Display.ListItem.js +29 -12
- package/dist/Display/Display.Logo.d.ts +3 -3
- package/dist/Display/Display.Logo.js +2 -2
- package/dist/Display/Display.MediaCard.js +4 -4
- package/dist/Display/Display.MediaEmbed.js +7 -7
- package/dist/Display/Display.MenuButton.d.ts +4 -4
- package/dist/Display/Display.MenuButton.js +6 -6
- package/dist/Display/Display.MenuCard.d.ts +1 -1
- package/dist/Display/Display.MenuCard.js +3 -3
- package/dist/Display/Display.MenuGrid.d.ts +1 -1
- package/dist/Display/Display.MenuGrid.js +1 -1
- package/dist/Display/Display.Monetary.d.ts +1 -1
- package/dist/Display/Display.Monetary.js +2 -2
- package/dist/Display/Display.Pattern.d.ts +33 -12
- package/dist/Display/Display.Pattern.js +60 -14
- package/dist/Display/Display.PriceTag.js +2 -2
- package/dist/Display/Display.ProductCard.js +7 -7
- package/dist/Display/Display.Rating.js +3 -3
- package/dist/Display/Display.SearchHistory.js +6 -6
- package/dist/Display/Display.SectionHeader.d.ts +11 -1
- package/dist/Display/Display.SectionHeader.js +14 -5
- package/dist/Display/Display.Stat.js +2 -2
- package/dist/Display/Display.StatCard.js +4 -4
- package/dist/Display/Display.StatusDot.js +3 -3
- package/dist/Display/Display.Story.js +3 -3
- package/dist/Display/Display.StoryTray.js +5 -5
- package/dist/Display/Display.StoryViewer.js +4 -4
- package/dist/Display/Display.SwipeableRow.d.ts +3 -1
- package/dist/Display/Display.SwipeableRow.js +7 -7
- package/dist/Display/Display.Tag.js +2 -2
- package/dist/Display/Display.Timeline.js +4 -4
- package/dist/Display/Display.Tooltip.js +3 -3
- package/dist/Display/index.d.ts +49 -45
- package/dist/Display/index.js +44 -42
- package/dist/Feedback/ErrorBoundary.d.ts +1 -1
- package/dist/Feedback/ErrorBoundary.js +1 -1
- package/dist/Feedback/Feedback.Banner.d.ts +3 -3
- package/dist/Feedback/Feedback.Banner.js +6 -6
- package/dist/Feedback/Feedback.DomainSplashScreen.js +5 -4
- package/dist/Feedback/Feedback.Empty.js +3 -3
- package/dist/Feedback/Feedback.EmptyState.d.ts +2 -1
- package/dist/Feedback/Feedback.EmptyState.js +7 -7
- package/dist/Feedback/Feedback.Error.d.ts +3 -1
- package/dist/Feedback/Feedback.Error.js +7 -6
- package/dist/Feedback/Feedback.Loading.d.ts +1 -1
- package/dist/Feedback/Feedback.Loading.js +2 -2
- package/dist/Feedback/Feedback.PermissionCard.js +5 -5
- package/dist/Feedback/Feedback.Progress.js +2 -2
- package/dist/Feedback/Feedback.ProgressCircle.js +1 -1
- package/dist/Feedback/Feedback.Skeleton.js +2 -2
- package/dist/Feedback/Feedback.Spinner.js +3 -3
- package/dist/Feedback/Feedback.Splash.d.ts +1 -1
- package/dist/Feedback/Feedback.Splash.js +7 -6
- package/dist/Feedback/Toast.context.js +7 -7
- package/dist/Feedback/index.d.ts +13 -13
- package/dist/Feedback/index.js +13 -13
- package/dist/Form/Form.Button.d.ts +2 -2
- package/dist/Form/Form.Button.js +1 -1
- package/dist/Form/Form.Checkbox.d.ts +4 -1
- package/dist/Form/Form.Checkbox.js +5 -5
- package/dist/Form/Form.ControlledCheckbox.js +1 -1
- package/dist/Form/Form.ControlledInput.js +1 -1
- package/dist/Form/Form.ControlledMonetaryInput.js +1 -1
- package/dist/Form/Form.ControlledRadioButton.js +1 -1
- package/dist/Form/Form.DatePicker.d.ts +2 -1
- package/dist/Form/Form.DatePicker.js +8 -7
- package/dist/Form/Form.Dropdown.js +7 -7
- package/dist/Form/Form.FAB.d.ts +2 -2
- package/dist/Form/Form.FAB.js +1 -1
- package/dist/Form/Form.FilterButton.d.ts +2 -2
- package/dist/Form/Form.FilterButton.js +1 -1
- package/dist/Form/Form.FractionalQuantityInput.js +4 -4
- package/dist/Form/Form.IconButton.d.ts +2 -2
- package/dist/Form/Form.IconButton.js +1 -1
- package/dist/Form/Form.Input.d.ts +5 -3
- package/dist/Form/Form.Input.js +5 -5
- package/dist/Form/Form.InputField.d.ts +1 -1
- package/dist/Form/Form.InputField.js +3 -3
- package/dist/Form/Form.KeyboardForm.d.ts +11 -0
- package/dist/Form/Form.KeyboardForm.js +9 -0
- package/dist/Form/Form.KeyboardToolbar.d.ts +21 -0
- package/dist/Form/Form.KeyboardToolbar.js +70 -0
- package/dist/Form/Form.MonetaryInput.js +5 -4
- package/dist/Form/Form.PasswordInput.d.ts +1 -1
- package/dist/Form/Form.PasswordInput.js +3 -3
- package/dist/Form/Form.PinInput.js +5 -5
- package/dist/Form/Form.QuantitySelector.js +3 -3
- package/dist/Form/Form.RadioButton.js +4 -4
- package/dist/Form/Form.SearchBar.js +4 -4
- package/dist/Form/Form.Select.d.ts +3 -1
- package/dist/Form/Form.Select.js +27 -14
- package/dist/Form/Form.Slider.js +3 -3
- package/dist/Form/Form.Switch.js +4 -4
- package/dist/Form/Form.TextInput.js +3 -3
- package/dist/Form/index.d.ts +33 -27
- package/dist/Form/index.js +29 -25
- package/dist/Navigation/Navigation.AppBar.d.ts +11 -6
- package/dist/Navigation/Navigation.AppBar.js +16 -16
- package/dist/Navigation/Navigation.BottomNav.d.ts +4 -2
- package/dist/Navigation/Navigation.BottomNav.js +34 -21
- package/dist/Navigation/Navigation.CollapsingHeader.d.ts +1 -1
- package/dist/Navigation/Navigation.CollapsingHeader.js +3 -3
- package/dist/Navigation/Navigation.FloatingBar.js +2 -2
- package/dist/Navigation/Navigation.Header.js +6 -6
- package/dist/Navigation/Navigation.HeaderToolbar.js +5 -5
- package/dist/Navigation/Navigation.Menu.js +6 -6
- package/dist/Navigation/Navigation.MenuSection.js +2 -2
- package/dist/Navigation/Navigation.RowItem.d.ts +2 -2
- package/dist/Navigation/Navigation.RowItem.js +4 -4
- package/dist/Navigation/Navigation.SearchBar.d.ts +6 -1
- package/dist/Navigation/Navigation.SearchBar.js +33 -12
- package/dist/Navigation/Navigation.SearchSuggestions.d.ts +14 -0
- package/dist/Navigation/Navigation.SearchSuggestions.js +7 -0
- package/dist/Navigation/Navigation.SegmentedControl.d.ts +3 -1
- package/dist/Navigation/Navigation.SegmentedControl.js +6 -5
- package/dist/Navigation/Navigation.Steps.js +5 -5
- package/dist/Navigation/Navigation.TabIcon.js +2 -2
- package/dist/Navigation/Navigation.TabItem.js +2 -2
- package/dist/Navigation/Navigation.Tabs.js +5 -5
- package/dist/Navigation/index.d.ts +23 -19
- package/dist/Navigation/index.js +17 -15
- package/dist/Typography/Typography.Heading.d.ts +1 -1
- package/dist/Typography/Typography.Heading.js +2 -2
- package/dist/Typography/Typography.SelectableText.d.ts +10 -0
- package/dist/Typography/Typography.SelectableText.js +16 -0
- package/dist/Typography/Typography.Text.d.ts +2 -2
- package/dist/Typography/Typography.Text.js +5 -19
- package/dist/Typography/index.d.ts +5 -2
- package/dist/Typography/index.js +5 -2
- package/dist/branding.d.ts +22 -0
- package/dist/branding.js +20 -3
- package/dist/icons/AddItemIcon.d.ts +1 -1
- package/dist/icons/ArrangeCircle.d.ts +1 -1
- package/dist/icons/ArrowDownIcon.d.ts +1 -1
- package/dist/icons/ArrowUpIcon.d.ts +1 -1
- package/dist/icons/BoxIcon.d.ts +1 -1
- package/dist/icons/BoxTimeIcon.d.ts +1 -1
- package/dist/icons/CalendarIcon.d.ts +1 -1
- package/dist/icons/CardIcon.d.ts +1 -1
- package/dist/icons/CashierIcon.d.ts +1 -1
- package/dist/icons/DuoIcon.d.ts +1 -1
- package/dist/icons/HomeIcon.d.ts +1 -1
- package/dist/icons/HomeIconOutlined.d.ts +1 -1
- package/dist/icons/LogoIcon.d.ts +1 -1
- package/dist/icons/MoneyReceiveIcon.d.ts +1 -1
- package/dist/icons/PinIcon.d.ts +1 -1
- package/dist/icons/PrinterIcon.d.ts +1 -1
- package/dist/icons/ProfileIcon.d.ts +1 -1
- package/dist/icons/SettingsIcon.d.ts +1 -1
- package/dist/icons/SinpeIcon.d.ts +1 -1
- package/dist/icons/ToggleOffIcon.d.ts +1 -1
- package/dist/icons/WalletMoneyIcon.d.ts +1 -1
- package/dist/index.d.ts +24 -23
- package/dist/index.js +26 -24
- package/dist/layouts/AuthContainer.d.ts +9 -3
- package/dist/layouts/AuthContainer.js +8 -8
- package/dist/layouts/Container.js +1 -1
- package/dist/layouts/GradientContainer.js +1 -1
- package/dist/layouts/ScrollContainer.js +1 -1
- package/dist/layouts/TabNavigatorLayout.js +4 -4
- package/dist/primitives/AspectRatio.js +1 -1
- package/dist/primitives/BaseButton.d.ts +92 -87
- package/dist/primitives/BaseButton.js +52 -54
- package/dist/primitives/Box.js +1 -1
- package/dist/primitives/Pressable.js +1 -1
- package/dist/primitives/Row.js +1 -1
- package/dist/primitives/Stack.js +1 -1
- package/dist/primitives/index.d.ts +6 -6
- package/dist/primitives/index.js +6 -6
- package/dist/theme/active.d.ts +1 -1
- package/dist/theme/active.js +14 -1
- package/dist/theme/build.d.ts +33 -0
- package/dist/theme/build.js +118 -0
- package/dist/theme/color.d.ts +26 -0
- package/dist/theme/color.js +109 -0
- package/dist/theme/components/index.d.ts +1 -1
- package/dist/theme/components/index.js +1 -1
- package/dist/theme/contrast.d.ts +29 -0
- package/dist/theme/contrast.js +57 -0
- package/dist/theme/css-vars.d.ts +3 -1
- package/dist/theme/css-vars.js +29 -3
- package/dist/theme/dark.d.ts +3 -4
- package/dist/theme/dark.js +91 -48
- package/dist/theme/default.d.ts +5 -1
- package/dist/theme/default.js +89 -41
- package/dist/theme/define.d.ts +4 -1
- package/dist/theme/define.js +4 -1
- package/dist/theme/globals.css +61 -46
- package/dist/theme/index.d.ts +14 -10
- package/dist/theme/index.js +13 -9
- package/dist/theme/theme.d.ts +1 -1
- package/dist/theme/theme.js +2 -2
- package/dist/theme/types.d.ts +77 -16
- package/dist/theme/types.js +13 -3
- package/dist/theme/typography.d.ts +19 -4
- package/dist/theme/typography.js +45 -28
- package/dist/theme/useTheme.d.ts +1 -1
- package/dist/theme/useTheme.js +1 -1
- package/dist/theme/validate.d.ts +16 -0
- package/dist/theme/validate.js +200 -0
- package/dist/tokens/index.d.ts +2 -2
- package/dist/tokens/index.js +2 -2
- package/dist/utils/criteria.d.ts +56 -0
- package/dist/utils/criteria.js +99 -0
- package/dist/utils/reorder.d.ts +4 -0
- package/dist/utils/reorder.js +32 -0
- package/dist/views/AppSplashView.d.ts +2 -2
- package/dist/views/AppSplashView.js +3 -3
- package/dist/views/AuthFormView.d.ts +5 -2
- package/dist/views/AuthFormView.js +5 -5
- package/dist/views/FormViewV2.d.ts +9 -4
- package/dist/views/FormViewV2.js +44 -25
- package/dist/views/ListViewV2.d.ts +12 -9
- package/dist/views/ListViewV2.js +49 -36
- package/dist/views/Wizard/Wizard.context.js +1 -1
- package/dist/views/Wizard/Wizard.d.ts +1 -1
- package/dist/views/Wizard/Wizard.js +1 -1
- package/dist/views/Wizard/index.d.ts +4 -4
- package/dist/views/Wizard/index.js +2 -2
- package/dist/views/types/IFormView.d.ts +1 -1
- package/dist/views/types/IListView.d.ts +1 -1
- package/dist/widgets/CircleButton.d.ts +2 -2
- package/dist/widgets/CircleButton.js +1 -1
- package/dist/widgets/CollectionOptions.d.ts +15 -0
- package/dist/widgets/CollectionOptions.js +127 -0
- package/dist/widgets/FilterBar.d.ts +21 -0
- package/dist/widgets/FilterBar.js +14 -0
- package/dist/widgets/FilterBuilder.d.ts +10 -0
- package/dist/widgets/FilterBuilder.js +115 -0
- package/dist/widgets/GeoPermissionCard.js +3 -3
- package/dist/widgets/HomeHeader.js +3 -3
- package/dist/widgets/JSONViewer.js +2 -2
- package/dist/widgets/MenuCard.d.ts +2 -2
- package/dist/widgets/MenuCard.js +1 -1
- package/dist/widgets/MenuGrid.d.ts +3 -3
- package/dist/widgets/MenuGrid.js +1 -1
- package/dist/widgets/MenuSection.d.ts +2 -2
- package/dist/widgets/MenuSection.js +1 -1
- package/dist/widgets/PromoBanner.js +3 -3
- package/dist/widgets/PromoModal.js +3 -3
- package/dist/widgets/QueryChoice.d.ts +10 -0
- package/dist/widgets/QueryChoice.js +13 -0
- package/dist/widgets/QuickActions.js +3 -3
- package/dist/widgets/ReorderableList.d.ts +51 -0
- package/dist/widgets/ReorderableList.js +138 -0
- package/dist/widgets/ScreenHeader.js +2 -2
- package/dist/widgets/TimeZoneSelector.d.ts +1 -1
- package/dist/widgets/TimeZoneSelector.js +4 -4
- package/dist/widgets/TimeZoneSelectorModal.d.ts +1 -1
- package/dist/widgets/TimeZoneSelectorModal.js +5 -5
- package/dist/widgets/index.d.ts +20 -16
- package/dist/widgets/index.js +13 -10
- package/package.json +70 -50
- package/tailwind.preset.js +19 -0
- package/dist/icons/icon_getters.d.ts +0 -6
- package/dist/icons/icon_getters.js +0 -23
package/dist/theme/typography.js
CHANGED
|
@@ -1,32 +1,42 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { IBMPlexMono_400Regular, IBMPlexMono_500Medium, } from "@expo-google-fonts/ibm-plex-mono";
|
|
2
|
+
import { IBMPlexSans_300Light, IBMPlexSans_400Regular, IBMPlexSans_500Medium, IBMPlexSans_600SemiBold, IBMPlexSans_700Bold, useFonts, } from "@expo-google-fonts/ibm-plex-sans";
|
|
3
3
|
const DEFAULT_FONT_FAMILIES = {
|
|
4
|
-
light: "
|
|
5
|
-
regular: "
|
|
6
|
-
medium: "
|
|
7
|
-
semiBold: "
|
|
8
|
-
extraBold: "
|
|
9
|
-
mono: "
|
|
10
|
-
monoMedium: "
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
titleBlack: "Inter_800ExtraBold",
|
|
4
|
+
light: "IBMPlexSans_300Light",
|
|
5
|
+
regular: "IBMPlexSans_400Regular",
|
|
6
|
+
medium: "IBMPlexSans_500Medium",
|
|
7
|
+
semiBold: "IBMPlexSans_600SemiBold",
|
|
8
|
+
extraBold: "IBMPlexSans_700Bold",
|
|
9
|
+
mono: "IBMPlexMono_400Regular",
|
|
10
|
+
monoMedium: "IBMPlexMono_500Medium",
|
|
11
|
+
titleRegular: "IBMPlexSans_400Regular",
|
|
12
|
+
titleMedium: "IBMPlexSans_500Medium",
|
|
13
|
+
title: "IBMPlexSans_600SemiBold",
|
|
14
|
+
titleBlack: "IBMPlexSans_700Bold",
|
|
16
15
|
};
|
|
17
16
|
export const fontFamilies = { ...DEFAULT_FONT_FAMILIES };
|
|
18
17
|
/**
|
|
19
18
|
* Override DS font family names (role → already-loaded family name).
|
|
20
19
|
* Mutates the singleton in-place so components pick up the change at render time.
|
|
21
|
-
* Example: `configureFonts({ title: "
|
|
20
|
+
* Example: `configureFonts({ title: "YourBrandTitle-Bold", titleBlack: "YourBrandDisplay-Black" })`.
|
|
22
21
|
*/
|
|
23
22
|
export function configureFonts(overrides) {
|
|
24
23
|
Object.assign(fontFamilies, overrides);
|
|
25
24
|
}
|
|
26
|
-
/** Reset all font roles to the defaults (
|
|
25
|
+
/** Reset all font roles to the defaults (IBM Plex Sans + IBM Plex Mono). Useful in tests and stories. */
|
|
27
26
|
export function resetFonts() {
|
|
28
27
|
Object.assign(fontFamilies, DEFAULT_FONT_FAMILIES);
|
|
29
28
|
}
|
|
29
|
+
export function resolveTextFontFamily(variant, bold = false, semibold = false) {
|
|
30
|
+
const variantFamily = fontFamilies[variantFontRole[variant]] ?? typographyVariants[variant].fontFamily;
|
|
31
|
+
const isBrandedFace = !variantFamily.startsWith("Inter_") && !variantFamily.startsWith("IBMPlexSans_");
|
|
32
|
+
return isBrandedFace
|
|
33
|
+
? variantFamily
|
|
34
|
+
: bold
|
|
35
|
+
? fontFamilies.extraBold
|
|
36
|
+
: semibold
|
|
37
|
+
? fontFamilies.semiBold
|
|
38
|
+
: variantFamily;
|
|
39
|
+
}
|
|
30
40
|
export const fontWeights = {
|
|
31
41
|
light: "300",
|
|
32
42
|
regular: "400",
|
|
@@ -75,7 +85,7 @@ export const letterSpacing = {
|
|
|
75
85
|
};
|
|
76
86
|
/* -------------------- Typography Variants -------------------- */
|
|
77
87
|
export const typographyVariants = {
|
|
78
|
-
// Display (
|
|
88
|
+
// Display (titleBlack role — typically the brand display typeface)
|
|
79
89
|
display: {
|
|
80
90
|
fontSize: fontSizes["7xl"],
|
|
81
91
|
fontFamily: fontFamilies.titleBlack,
|
|
@@ -83,7 +93,7 @@ export const typographyVariants = {
|
|
|
83
93
|
lineHeight: fontSizes["7xl"] * lineHeights.tight,
|
|
84
94
|
letterSpacing: letterSpacing.tight,
|
|
85
95
|
},
|
|
86
|
-
// Headings (
|
|
96
|
+
// Headings (title role)
|
|
87
97
|
h1: {
|
|
88
98
|
fontSize: fontSizes["5xl"],
|
|
89
99
|
fontFamily: fontFamilies.title,
|
|
@@ -127,6 +137,13 @@ export const typographyVariants = {
|
|
|
127
137
|
letterSpacing: letterSpacing.normal,
|
|
128
138
|
},
|
|
129
139
|
// Body
|
|
140
|
+
bodyReadable: {
|
|
141
|
+
fontSize: 17,
|
|
142
|
+
fontFamily: fontFamilies.regular,
|
|
143
|
+
fontWeight: fontWeights.regular,
|
|
144
|
+
lineHeight: 17 * lineHeights.normal,
|
|
145
|
+
letterSpacing: letterSpacing.normal,
|
|
146
|
+
},
|
|
130
147
|
bodyLarge: {
|
|
131
148
|
fontSize: fontSizes.lg,
|
|
132
149
|
fontFamily: fontFamilies.regular,
|
|
@@ -252,6 +269,7 @@ export const variantFontRole = {
|
|
|
252
269
|
h4: "medium",
|
|
253
270
|
h5: "medium",
|
|
254
271
|
h6: "medium",
|
|
272
|
+
bodyReadable: "regular",
|
|
255
273
|
bodyLarge: "regular",
|
|
256
274
|
body: "regular",
|
|
257
275
|
bodySmall: "regular",
|
|
@@ -290,18 +308,17 @@ export const createCustomTextStyle = (fontSize, fontFamily, options) => {
|
|
|
290
308
|
* depending directly on expo-font — it's already a transitive dep via this package. */
|
|
291
309
|
export { useFonts };
|
|
292
310
|
/* -------------------- Font Loader (optional, convenience) ------------------
|
|
293
|
-
* Loads
|
|
294
|
-
*
|
|
295
|
-
* via `configureFonts` — the DS never bundles font files. */
|
|
311
|
+
* Loads IBM Plex Sans and IBM Plex Mono, the same faces web UI uses.
|
|
312
|
+
* An app can still point a role at another loaded family with `configureFonts`. */
|
|
296
313
|
export const useAppFonts = () => {
|
|
297
314
|
const [loaded] = useFonts({
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
315
|
+
IBMPlexMono_400Regular,
|
|
316
|
+
IBMPlexMono_500Medium,
|
|
317
|
+
IBMPlexSans_300Light,
|
|
318
|
+
IBMPlexSans_400Regular,
|
|
319
|
+
IBMPlexSans_500Medium,
|
|
320
|
+
IBMPlexSans_600SemiBold,
|
|
321
|
+
IBMPlexSans_700Bold,
|
|
305
322
|
});
|
|
306
323
|
return loaded;
|
|
307
324
|
};
|
package/dist/theme/useTheme.d.ts
CHANGED
package/dist/theme/useTheme.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getActiveTheme, getThemeVersion, subscribeTheme, } from "
|
|
1
|
+
import { getActiveTheme, getThemeVersion, subscribeTheme, } from "./active.js";
|
|
2
2
|
import { useSyncExternalStore } from "react";
|
|
3
3
|
export function useTheme() {
|
|
4
4
|
useSyncExternalStore(subscribeTheme, getThemeVersion, getThemeVersion);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ThemeTokens } from "./types.js";
|
|
2
|
+
type Issue = {
|
|
3
|
+
path: string;
|
|
4
|
+
message: string;
|
|
5
|
+
};
|
|
6
|
+
/**
|
|
7
|
+
* Lightweight sanity checks on a theme. Returns a list of issues; empty array means OK.
|
|
8
|
+
* Not a hard validator — we don't want to over-constrain creative themes — just guards
|
|
9
|
+
* against the common silent failures (typos in hex, negative sizes, missing primary,
|
|
10
|
+
* WCAG P0 contrast violations on the key on-color pairs, semantic token collisions).
|
|
11
|
+
*
|
|
12
|
+
* Triggered automatically by `setActiveTheme` in dev mode (skipped under Node, since
|
|
13
|
+
* tests intentionally pass partial themes). Can also be called directly.
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateTheme(theme: Partial<ThemeTokens>): Issue[];
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { contrastRatio, resolveOnColor } from "./contrast.js";
|
|
2
|
+
/**
|
|
3
|
+
* Lightweight sanity checks on a theme. Returns a list of issues; empty array means OK.
|
|
4
|
+
* Not a hard validator — we don't want to over-constrain creative themes — just guards
|
|
5
|
+
* against the common silent failures (typos in hex, negative sizes, missing primary,
|
|
6
|
+
* WCAG P0 contrast violations on the key on-color pairs, semantic token collisions).
|
|
7
|
+
*
|
|
8
|
+
* Triggered automatically by `setActiveTheme` in dev mode (skipped under Node, since
|
|
9
|
+
* tests intentionally pass partial themes). Can also be called directly.
|
|
10
|
+
*/
|
|
11
|
+
export function validateTheme(theme) {
|
|
12
|
+
const issues = [];
|
|
13
|
+
if (typeof theme.name !== "string" || theme.name.trim() === "") {
|
|
14
|
+
issues.push({ path: "name", message: "Theme must have a non-empty `name`." });
|
|
15
|
+
}
|
|
16
|
+
if (!isHex(theme.primary)) {
|
|
17
|
+
issues.push({ path: "primary", message: `Invalid hex color: ${String(theme.primary)}` });
|
|
18
|
+
}
|
|
19
|
+
if (!isHex(theme.accent)) {
|
|
20
|
+
issues.push({ path: "accent", message: `Invalid hex color: ${String(theme.accent)}` });
|
|
21
|
+
}
|
|
22
|
+
if (!isHex(theme.bg?.page)) {
|
|
23
|
+
issues.push({ path: "bg.page", message: `Invalid hex color: ${String(theme.bg?.page)}` });
|
|
24
|
+
}
|
|
25
|
+
if (!isHex(theme.text?.primary)) {
|
|
26
|
+
issues.push({
|
|
27
|
+
path: "text.primary",
|
|
28
|
+
message: `Invalid hex color: ${String(theme.text?.primary)}`,
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
if (theme.pattern) {
|
|
32
|
+
if (!isFiniteSize(theme.pattern.size)) {
|
|
33
|
+
issues.push({
|
|
34
|
+
path: "pattern.size",
|
|
35
|
+
message: `Tile size must be > 0 (got ${String(theme.pattern.size)}).`,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (theme.shadow) {
|
|
40
|
+
issues.push(...validateShadow("shadow.sm", theme.shadow.sm));
|
|
41
|
+
issues.push(...validateShadow("shadow.md", theme.shadow.md));
|
|
42
|
+
issues.push(...validateShadow("shadow.lg", theme.shadow.lg));
|
|
43
|
+
}
|
|
44
|
+
issues.push(...validateContrast(theme));
|
|
45
|
+
issues.push(...validateSemanticDistinct(theme));
|
|
46
|
+
return issues;
|
|
47
|
+
}
|
|
48
|
+
function isHex(value) {
|
|
49
|
+
return typeof value === "string" && /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(value.trim());
|
|
50
|
+
}
|
|
51
|
+
function isFiniteSize(n) {
|
|
52
|
+
return typeof n === "number" && Number.isFinite(n) && n > 0;
|
|
53
|
+
}
|
|
54
|
+
function validateShadow(path, s) {
|
|
55
|
+
const out = [];
|
|
56
|
+
if (typeof s.shadowColor !== "string" || s.shadowColor.trim() === "") {
|
|
57
|
+
out.push({ path: `${path}.shadowColor`, message: "shadowColor must be a string." });
|
|
58
|
+
}
|
|
59
|
+
if (typeof s.shadowOpacity !== "number" || s.shadowOpacity < 0 || s.shadowOpacity > 1) {
|
|
60
|
+
out.push({
|
|
61
|
+
path: `${path}.shadowOpacity`,
|
|
62
|
+
message: `shadowOpacity must be in [0, 1] (got ${s.shadowOpacity}).`,
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* WCAG 2.1 contrast validation. Checks the P0 on-color pairs that every consumer
|
|
69
|
+
* relies on (CTA text/bg, focus ring, body text on surfaces). Flags any pair below the
|
|
70
|
+
* AA minimum (3:1 for UI/non-text, 4.5:1 for body text). Returns warnings as Issue[]
|
|
71
|
+
* entries — never throws — so the dev-mode warning stays non-fatal.
|
|
72
|
+
*/
|
|
73
|
+
function validateContrast(theme) {
|
|
74
|
+
const issues = [];
|
|
75
|
+
const checks = [
|
|
76
|
+
{
|
|
77
|
+
fg: theme.text?.onPrimary,
|
|
78
|
+
bg: theme.primary,
|
|
79
|
+
min: 4.5,
|
|
80
|
+
label: "text.onPrimary on primary (CTA)",
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
fg: theme.text?.onSecondary,
|
|
84
|
+
bg: theme.secondary,
|
|
85
|
+
min: 4.5,
|
|
86
|
+
label: "text.onSecondary on secondary",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
fg: theme.text?.onAccent,
|
|
90
|
+
bg: theme.accent,
|
|
91
|
+
min: 4.5,
|
|
92
|
+
label: "text.onAccent on accent",
|
|
93
|
+
},
|
|
94
|
+
{ fg: theme.border?.focus, bg: theme.bg?.page, min: 3, label: "border.focus on bg.page" },
|
|
95
|
+
{ fg: theme.border?.focus, bg: theme.bg?.card, min: 3, label: "border.focus on bg.card" },
|
|
96
|
+
{
|
|
97
|
+
fg: theme.text?.onDanger,
|
|
98
|
+
bg: theme.danger,
|
|
99
|
+
min: 4.5,
|
|
100
|
+
label: "text.onDanger on danger",
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
fg: theme.text?.onSuccess,
|
|
104
|
+
bg: theme.success,
|
|
105
|
+
min: 4.5,
|
|
106
|
+
label: "text.onSuccess on success",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
fg: theme.text?.accent,
|
|
110
|
+
bg: theme.bg?.card,
|
|
111
|
+
min: 4.5,
|
|
112
|
+
label: "text.accent on bg.card (brand text)",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
fg: theme.text?.accent,
|
|
116
|
+
bg: theme.bg?.page,
|
|
117
|
+
min: 4.5,
|
|
118
|
+
label: "text.accent on bg.page (brand text)",
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
fg: theme.container?.onPrimary,
|
|
122
|
+
bg: theme.container?.primary,
|
|
123
|
+
min: 4.5,
|
|
124
|
+
label: "container.onPrimary on container.primary",
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
fg: theme.container?.onSuccess,
|
|
128
|
+
bg: theme.container?.success,
|
|
129
|
+
min: 4.5,
|
|
130
|
+
label: "container.onSuccess on container.success",
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
fg: theme.container?.onDanger,
|
|
134
|
+
bg: theme.container?.danger,
|
|
135
|
+
min: 4.5,
|
|
136
|
+
label: "container.onDanger on container.danger",
|
|
137
|
+
},
|
|
138
|
+
];
|
|
139
|
+
for (const c of checks) {
|
|
140
|
+
if (!isHex(c.fg) || !isHex(c.bg))
|
|
141
|
+
continue;
|
|
142
|
+
const ratio = contrastRatio(c.fg, c.bg);
|
|
143
|
+
if (ratio < c.min) {
|
|
144
|
+
let message = `Contrast ratio ${ratio.toFixed(2)}:1 is below WCAG AA minimum ${c.min}:1 for body/UI text.`;
|
|
145
|
+
if (c.label.includes("onPrimary") && isHex(theme.primary)) {
|
|
146
|
+
const suggested = resolveOnColor(theme.primary);
|
|
147
|
+
message += ` Use resolveOnColor(primary) → ${suggested}.`;
|
|
148
|
+
}
|
|
149
|
+
issues.push({ path: c.label, message });
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return issues;
|
|
153
|
+
}
|
|
154
|
+
/** Roles that must stay visually distinct for maintainable state semantics. */
|
|
155
|
+
function validateSemanticDistinct(theme) {
|
|
156
|
+
const issues = [];
|
|
157
|
+
const pairs = [
|
|
158
|
+
["bg.disabled vs bg.muted", theme.bg?.disabled, theme.bg?.muted],
|
|
159
|
+
["text.disabled vs text.muted", theme.text?.disabled, theme.text?.muted],
|
|
160
|
+
["icon.disabled vs icon.secondary", theme.icon?.disabled, theme.icon?.secondary],
|
|
161
|
+
];
|
|
162
|
+
for (const [label, a, b] of pairs) {
|
|
163
|
+
if (!isHex(a) || !isHex(b))
|
|
164
|
+
continue;
|
|
165
|
+
if (a.trim().toLowerCase() === b.trim().toLowerCase()) {
|
|
166
|
+
issues.push({
|
|
167
|
+
path: label,
|
|
168
|
+
message: `Tokens share the same hex (${a}). Keep roles distinct so disabled/muted states stay maintainable.`,
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
if (theme.state) {
|
|
173
|
+
for (const key of ["hover", "press", "focus", "drag"]) {
|
|
174
|
+
const v = theme.state[key];
|
|
175
|
+
if (typeof v !== "number" || v < 0 || v > 1) {
|
|
176
|
+
issues.push({
|
|
177
|
+
path: `state.${key}`,
|
|
178
|
+
message: `State layer opacity must be in [0, 1] (got ${String(v)}).`,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
if (theme.material) {
|
|
184
|
+
if (typeof theme.material.opacity === "number" &&
|
|
185
|
+
(theme.material.opacity < 0 || theme.material.opacity > 1)) {
|
|
186
|
+
issues.push({
|
|
187
|
+
path: "material.opacity",
|
|
188
|
+
message: `material.opacity must be in [0, 1] (got ${theme.material.opacity}).`,
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
if (typeof theme.material.blur === "number" &&
|
|
192
|
+
(!Number.isFinite(theme.material.blur) || theme.material.blur < 0)) {
|
|
193
|
+
issues.push({
|
|
194
|
+
path: "material.blur",
|
|
195
|
+
message: `material.blur must be ≥ 0 (got ${theme.material.blur}).`,
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return issues;
|
|
200
|
+
}
|
package/dist/tokens/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { motion } from "
|
|
2
|
-
export { duration, type DurationToken, easing, type EasingToken, spring, type SpringToken, } from "
|
|
1
|
+
export { motion } from "./motion.js";
|
|
2
|
+
export { duration, type DurationToken, easing, type EasingToken, spring, type SpringToken, } from "./motion.js";
|
package/dist/tokens/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { motion } from "
|
|
2
|
-
export { duration, easing, spring, } from "
|
|
1
|
+
export { motion } from "./motion.js";
|
|
2
|
+
export { duration, easing, spring, } from "./motion.js";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export type CriteriaValue = string | number | boolean;
|
|
2
|
+
export interface CriteriaOperator {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
arity: "none" | "one" | "range";
|
|
6
|
+
}
|
|
7
|
+
export interface CriteriaField {
|
|
8
|
+
id: string;
|
|
9
|
+
label: string;
|
|
10
|
+
type: "text" | "number" | "date" | "choice";
|
|
11
|
+
operators: readonly CriteriaOperator[];
|
|
12
|
+
options?: readonly {
|
|
13
|
+
label: string;
|
|
14
|
+
value: CriteriaValue;
|
|
15
|
+
}[];
|
|
16
|
+
}
|
|
17
|
+
export interface CriteriaCondition {
|
|
18
|
+
kind: "condition";
|
|
19
|
+
field: string;
|
|
20
|
+
operator: string;
|
|
21
|
+
values: readonly CriteriaValue[];
|
|
22
|
+
}
|
|
23
|
+
export interface CriteriaGroup {
|
|
24
|
+
kind: "group";
|
|
25
|
+
join: "all" | "any" | "none";
|
|
26
|
+
children: readonly CriteriaNode[];
|
|
27
|
+
}
|
|
28
|
+
export type CriteriaNode = CriteriaCondition | CriteriaGroup;
|
|
29
|
+
export interface CollectionSort {
|
|
30
|
+
field: string;
|
|
31
|
+
direction: "asc" | "desc";
|
|
32
|
+
}
|
|
33
|
+
export interface CollectionQuery {
|
|
34
|
+
search: string;
|
|
35
|
+
filter: CriteriaGroup;
|
|
36
|
+
sort: readonly CollectionSort[];
|
|
37
|
+
groupBy: readonly string[];
|
|
38
|
+
}
|
|
39
|
+
export interface CollectionField {
|
|
40
|
+
id: string;
|
|
41
|
+
label: string;
|
|
42
|
+
ascLabel?: string;
|
|
43
|
+
descLabel?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface SavedCollectionQuery {
|
|
46
|
+
id: string;
|
|
47
|
+
label: string;
|
|
48
|
+
query: CollectionQuery;
|
|
49
|
+
}
|
|
50
|
+
export declare function parseCriteriaDate(value: CriteriaValue | undefined): Date | null;
|
|
51
|
+
export declare function criteriaAt(root: CriteriaNode, path: readonly number[]): CriteriaNode;
|
|
52
|
+
export declare function replaceCriteria(root: CriteriaGroup, path: readonly number[], replacement: CriteriaNode | null): CriteriaGroup;
|
|
53
|
+
export declare function describeCriteria(node: CriteriaNode, fields: readonly CriteriaField[]): string;
|
|
54
|
+
export declare function validateCondition(condition: CriteriaCondition, fields: readonly CriteriaField[]): string | undefined;
|
|
55
|
+
export declare function validateCriteria(group: CriteriaGroup, fields: readonly CriteriaField[]): string | undefined;
|
|
56
|
+
export declare function moveCollectionEntry<T>(items: readonly T[], index: number, direction: -1 | 1): T[];
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
export function parseCriteriaDate(value) {
|
|
2
|
+
if (typeof value !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(value))
|
|
3
|
+
return null;
|
|
4
|
+
const date = new Date(`${value}T00:00:00Z`);
|
|
5
|
+
if (!Number.isFinite(date.getTime()) || date.toISOString().slice(0, 10) !== value)
|
|
6
|
+
return null;
|
|
7
|
+
return new Date(`${value}T12:00:00`);
|
|
8
|
+
}
|
|
9
|
+
export function criteriaAt(root, path) {
|
|
10
|
+
let node = root;
|
|
11
|
+
for (const index of path) {
|
|
12
|
+
if (node.kind !== "group" || !node.children[index])
|
|
13
|
+
throw new Error("Invalid criteria path");
|
|
14
|
+
node = node.children[index];
|
|
15
|
+
}
|
|
16
|
+
return node;
|
|
17
|
+
}
|
|
18
|
+
export function replaceCriteria(root, path, replacement) {
|
|
19
|
+
if (path.length === 0) {
|
|
20
|
+
if (replacement?.kind !== "group")
|
|
21
|
+
throw new Error("Criteria root must remain a group");
|
|
22
|
+
return replacement;
|
|
23
|
+
}
|
|
24
|
+
const [index, ...rest] = path;
|
|
25
|
+
const child = root.children[index];
|
|
26
|
+
if (!child)
|
|
27
|
+
throw new Error("Invalid criteria path");
|
|
28
|
+
if (rest.length && child.kind !== "group")
|
|
29
|
+
throw new Error("Invalid criteria path");
|
|
30
|
+
const next = rest.length && child.kind === "group"
|
|
31
|
+
? replaceCriteria(child, rest, replacement)
|
|
32
|
+
: replacement;
|
|
33
|
+
return {
|
|
34
|
+
...root,
|
|
35
|
+
children: root.children.flatMap((item, position) => position !== index ? [item] : next ? [next] : []),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
export function describeCriteria(node, fields) {
|
|
39
|
+
if (node.kind === "group") {
|
|
40
|
+
if (!node.children.length)
|
|
41
|
+
return "Sin condiciones";
|
|
42
|
+
const join = { all: "Todas", any: "Cualquiera", none: "Ninguna" }[node.join];
|
|
43
|
+
return `${join}: (${node.children.map((child) => describeCriteria(child, fields)).join("; ")})`;
|
|
44
|
+
}
|
|
45
|
+
const field = fields.find((item) => item.id === node.field);
|
|
46
|
+
const operator = field?.operators.find((item) => item.id === node.operator);
|
|
47
|
+
const values = node.values.map((value) => field?.options?.find((option) => option.value === value)?.label ?? String(value));
|
|
48
|
+
return `${field?.label ?? node.field} ${operator?.label ?? node.operator}${values.length ? ` ${values.join(" — ")}` : ""}`;
|
|
49
|
+
}
|
|
50
|
+
export function validateCondition(condition, fields) {
|
|
51
|
+
const field = fields.find((item) => item.id === condition.field);
|
|
52
|
+
if (!field)
|
|
53
|
+
return "El campo ya no está disponible.";
|
|
54
|
+
const operator = field.operators.find((item) => item.id === condition.operator);
|
|
55
|
+
if (!operator)
|
|
56
|
+
return "El operador no está disponible para este campo.";
|
|
57
|
+
const count = { none: 0, one: 1, range: 2 }[operator.arity];
|
|
58
|
+
if (condition.values.length !== count)
|
|
59
|
+
return "Completa los valores de la condición.";
|
|
60
|
+
for (const value of condition.values) {
|
|
61
|
+
if (field.type === "number" && (typeof value !== "number" || !Number.isFinite(value)))
|
|
62
|
+
return "Introduce un número válido.";
|
|
63
|
+
if (field.type === "text" && (typeof value !== "string" || !value.trim()))
|
|
64
|
+
return "Introduce un texto.";
|
|
65
|
+
if (field.type === "date" && !parseCriteriaDate(value))
|
|
66
|
+
return "Introduce una fecha válida (AAAA-MM-DD).";
|
|
67
|
+
if (field.type === "choice" && !field.options?.some((option) => option.value === value))
|
|
68
|
+
return "Selecciona un valor disponible.";
|
|
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;
|
|
79
|
+
}
|
|
80
|
+
export function validateCriteria(group, fields) {
|
|
81
|
+
for (const child of group.children) {
|
|
82
|
+
if (child.kind === "group" && !child.children.length)
|
|
83
|
+
return "Completa o elimina el grupo vacío.";
|
|
84
|
+
const error = child.kind === "group"
|
|
85
|
+
? validateCriteria(child, fields)
|
|
86
|
+
: validateCondition(child, fields);
|
|
87
|
+
if (error)
|
|
88
|
+
return error;
|
|
89
|
+
}
|
|
90
|
+
return undefined;
|
|
91
|
+
}
|
|
92
|
+
export function moveCollectionEntry(items, index, direction) {
|
|
93
|
+
const target = index + direction;
|
|
94
|
+
if (index < 0 || index >= items.length || target < 0 || target >= items.length)
|
|
95
|
+
throw new Error("Invalid collection reorder");
|
|
96
|
+
const next = [...items];
|
|
97
|
+
[next[index], next[target]] = [next[target], next[index]];
|
|
98
|
+
return next;
|
|
99
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export declare function reorderKeys<T>(items: readonly T[], keyExtractor: (item: T) => string): string[];
|
|
2
|
+
export declare function sameOrder(left: readonly string[], right: readonly string[]): boolean;
|
|
3
|
+
export declare function moveReorderItem<T>(items: readonly T[], fromIndex: number, toIndex: number): T[];
|
|
4
|
+
export declare function applyReorder<T>(items: readonly T[], keyExtractor: (item: T) => string, order: readonly string[]): T[];
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export function reorderKeys(items, keyExtractor) {
|
|
2
|
+
const keys = items.map(keyExtractor);
|
|
3
|
+
if (keys.some((key) => typeof key !== "string" || !key.trim()) ||
|
|
4
|
+
new Set(keys).size !== keys.length)
|
|
5
|
+
throw new Error("ReorderableList requires unique, non-empty string keys.");
|
|
6
|
+
return keys;
|
|
7
|
+
}
|
|
8
|
+
export function sameOrder(left, right) {
|
|
9
|
+
return left.length === right.length && left.every((key, index) => key === right[index]);
|
|
10
|
+
}
|
|
11
|
+
export function moveReorderItem(items, fromIndex, toIndex) {
|
|
12
|
+
if (!Number.isInteger(fromIndex) ||
|
|
13
|
+
!Number.isInteger(toIndex) ||
|
|
14
|
+
fromIndex < 0 ||
|
|
15
|
+
fromIndex >= items.length ||
|
|
16
|
+
toIndex < 0 ||
|
|
17
|
+
toIndex >= items.length)
|
|
18
|
+
throw new Error("ReorderableList received an invalid move.");
|
|
19
|
+
const next = [...items];
|
|
20
|
+
const [item] = next.splice(fromIndex, 1);
|
|
21
|
+
next.splice(toIndex, 0, item);
|
|
22
|
+
return next;
|
|
23
|
+
}
|
|
24
|
+
export function applyReorder(items, keyExtractor, order) {
|
|
25
|
+
const keys = reorderKeys(items, keyExtractor);
|
|
26
|
+
const indices = new Map(keys.map((key, index) => [key, index]));
|
|
27
|
+
if (order.length !== keys.length ||
|
|
28
|
+
new Set(order).size !== order.length ||
|
|
29
|
+
order.some((key) => !indices.has(key)))
|
|
30
|
+
throw new Error("ReorderableList received an order that does not match the current items.");
|
|
31
|
+
return order.map((key) => items[indices.get(key)]);
|
|
32
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { type SpinnerVariant } from "../Feedback/Feedback.Spinner";
|
|
2
|
-
import type { AppBarBackground } from "../Navigation/Navigation.AppBar";
|
|
1
|
+
import { type SpinnerVariant } from "../Feedback/Feedback.Spinner.js";
|
|
2
|
+
import type { AppBarBackground } from "../Navigation/Navigation.AppBar.js";
|
|
3
3
|
import type { ReactNode } from "react";
|
|
4
4
|
import { type ImageSourcePropType, type ViewStyle } from "react-native";
|
|
5
5
|
export interface AppSplashViewProps {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
-
import GradientSurface from "../Display/Display.GradientSurface";
|
|
3
|
-
import { Pattern } from "../Display/Display.Pattern";
|
|
4
|
-
import Spinner from "../Feedback/Feedback.Spinner";
|
|
2
|
+
import GradientSurface from "../Display/Display.GradientSurface.js";
|
|
3
|
+
import { Pattern } from "../Display/Display.Pattern.js";
|
|
4
|
+
import Spinner from "../Feedback/Feedback.Spinner.js";
|
|
5
5
|
import { Image, View } from "react-native";
|
|
6
6
|
export function AppSplashView({ background, logo, loadingVariant = "dots", loader, style, }) {
|
|
7
7
|
return (_jsxs(GradientSurface, { className: "flex-1", colors: background?.colors, end: background?.end, padding: "none", preset: background?.surface ?? "night-green", radius: "none", start: background?.start, style: { flex: 1, ...style }, children: [background?.pattern ? (_jsx(Pattern, { color: background.patternColor ?? "#FFFFFF", kind: background.pattern, opacity: background.patternOpacity ?? 0.18 })) : null, _jsxs(View, { style: { flex: 1, alignItems: "center", justifyContent: "center" }, children: [logo ? (_jsx(Image, { source: logo, style: { width: 140, height: 140, resizeMode: "contain", marginBottom: 40 } })) : null, loader ?? (_jsx(Spinner, { color: "rgba(255,255,255,0.9)", size: "large", variant: loadingVariant }))] })] }));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { KeyboardFormProps } from "../Form/Form.KeyboardForm.js";
|
|
2
|
+
import type { AppBarBackground } from "../Navigation/Navigation.AppBar.js";
|
|
2
3
|
import { ReactNode } from "react";
|
|
3
4
|
import { type ImageSourcePropType } from "react-native";
|
|
4
5
|
interface AuthFormProps {
|
|
@@ -8,6 +9,8 @@ interface AuthFormProps {
|
|
|
8
9
|
onBack?: () => void;
|
|
9
10
|
FormNode: ReactNode;
|
|
10
11
|
background?: AppBarBackground;
|
|
12
|
+
keyboardToolbar?: boolean;
|
|
13
|
+
keyboardFormProps?: Omit<KeyboardFormProps, "children" | "toolbar">;
|
|
11
14
|
}
|
|
12
|
-
declare function AuthFormView({ title, description, logoSource, onBack, FormNode, background, }: AuthFormProps): import("react").JSX.Element;
|
|
15
|
+
declare function AuthFormView({ title, description, logoSource, onBack, FormNode, background, keyboardToolbar, keyboardFormProps, }: AuthFormProps): import("react").JSX.Element;
|
|
13
16
|
export default AuthFormView;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "nativewind/jsx-runtime";
|
|
2
|
-
import { Display } from "../Display";
|
|
3
|
-
import AuthContainer from "../layouts/AuthContainer";
|
|
4
|
-
import { Typography } from "../Typography";
|
|
2
|
+
import { Display } from "../Display/index.js";
|
|
3
|
+
import AuthContainer from "../layouts/AuthContainer.js";
|
|
4
|
+
import { Typography } from "../Typography/index.js";
|
|
5
5
|
import { View } from "react-native";
|
|
6
6
|
const Logo = Display.Logo;
|
|
7
7
|
const Text = Typography.Text;
|
|
8
|
-
function AuthFormView({ title, description, logoSource, onBack, FormNode, background, }) {
|
|
8
|
+
function AuthFormView({ title, description, logoSource, onBack, FormNode, background, keyboardToolbar, keyboardFormProps, }) {
|
|
9
9
|
const renderTitle = () => {
|
|
10
10
|
if (!title)
|
|
11
11
|
return null;
|
|
@@ -16,6 +16,6 @@ function AuthFormView({ title, description, logoSource, onBack, FormNode, backgr
|
|
|
16
16
|
return null;
|
|
17
17
|
return _jsx(Text, { variant: "body", children: description });
|
|
18
18
|
};
|
|
19
|
-
return (_jsx(AuthContainer, { background: background, header: _jsx(Logo, { size: "large", source: logoSource }), onBackPress: onBack, children: _jsxs(View, { className: "m-4", children: [_jsxs(View, { className: "mb-5", children: [renderTitle(), renderDescription()] }), FormNode] }) }));
|
|
19
|
+
return (_jsx(AuthContainer, { background: background, header: _jsx(Logo, { size: "large", source: logoSource }), keyboardFormProps: keyboardFormProps, keyboardToolbar: keyboardToolbar, onBackPress: onBack, children: _jsxs(View, { className: "m-4", children: [_jsxs(View, { className: "mb-5", children: [renderTitle(), renderDescription()] }), FormNode] }) }));
|
|
20
20
|
}
|
|
21
21
|
export default AuthFormView;
|