@gaozh1024/rn-kit 0.3.4 → 0.4.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 +272 -3
- package/dist/index.d.mts +249 -12
- package/dist/index.d.ts +249 -12
- package/dist/index.js +2419 -798
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2351 -739
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -33,6 +33,7 @@ __export(index_exports, {
|
|
|
33
33
|
ActionIcons: () => ActionIcons,
|
|
34
34
|
Alert: () => Alert,
|
|
35
35
|
AppButton: () => AppButton,
|
|
36
|
+
AppErrorBoundary: () => AppErrorBoundary,
|
|
36
37
|
AppFocusedStatusBar: () => AppFocusedStatusBar,
|
|
37
38
|
AppHeader: () => AppHeader,
|
|
38
39
|
AppImage: () => AppImage,
|
|
@@ -60,13 +61,18 @@ __export(index_exports, {
|
|
|
60
61
|
FormItem: () => FormItem,
|
|
61
62
|
GradientView: () => GradientView,
|
|
62
63
|
Icon: () => Icon,
|
|
64
|
+
KeyboardDismissView: () => KeyboardDismissView,
|
|
65
|
+
LOG_LEVEL_WEIGHT: () => LOG_LEVEL_WEIGHT,
|
|
63
66
|
Loading: () => Loading,
|
|
67
|
+
LogOverlay: () => LogOverlay,
|
|
68
|
+
LoggerProvider: () => LoggerProvider,
|
|
64
69
|
MemoryStorage: () => MemoryStorage,
|
|
65
70
|
NavigationContainer: () => import_native6.NavigationContainer,
|
|
66
71
|
NavigationIcons: () => NavigationIcons,
|
|
67
72
|
NavigationProvider: () => NavigationProvider,
|
|
68
73
|
OverlayProvider: () => OverlayProvider,
|
|
69
74
|
PageDrawer: () => PageDrawer,
|
|
75
|
+
Picker: () => Picker,
|
|
70
76
|
Progress: () => Progress,
|
|
71
77
|
Radio: () => Radio,
|
|
72
78
|
RadioGroup: () => RadioGroup,
|
|
@@ -88,7 +94,10 @@ __export(index_exports, {
|
|
|
88
94
|
clsx: () => import_clsx.clsx,
|
|
89
95
|
cn: () => cn,
|
|
90
96
|
createAPI: () => createAPI,
|
|
97
|
+
createApiLoggerTransport: () => createApiLoggerTransport,
|
|
98
|
+
createConsoleTransport: () => createConsoleTransport,
|
|
91
99
|
createDrawerScreens: () => createDrawerScreens,
|
|
100
|
+
createLogEntry: () => createLogEntry,
|
|
92
101
|
createNavigationTheme: () => createNavigationTheme,
|
|
93
102
|
createStackScreens: () => createStackScreens,
|
|
94
103
|
createTabScreens: () => createTabScreens,
|
|
@@ -97,10 +106,12 @@ __export(index_exports, {
|
|
|
97
106
|
enhanceError: () => enhanceError,
|
|
98
107
|
formatCurrency: () => formatCurrency,
|
|
99
108
|
formatDate: () => formatDate,
|
|
109
|
+
formatLogTime: () => formatLogTime,
|
|
100
110
|
formatNumber: () => formatNumber,
|
|
101
111
|
formatPercent: () => formatPercent,
|
|
102
112
|
formatRelativeTime: () => formatRelativeTime,
|
|
103
113
|
generateColorPalette: () => generateColorPalette,
|
|
114
|
+
getGlobalLogger: () => getGlobalLogger,
|
|
104
115
|
getThemeColors: () => getThemeColors,
|
|
105
116
|
getValidationErrors: () => getValidationErrors,
|
|
106
117
|
hexToRgb: () => hexToRgb,
|
|
@@ -108,11 +119,16 @@ __export(index_exports, {
|
|
|
108
119
|
isValidEmail: () => isValidEmail,
|
|
109
120
|
isValidPhone: () => isValidPhone,
|
|
110
121
|
mapHttpStatus: () => mapHttpStatus,
|
|
122
|
+
normalizeConsoleArgs: () => normalizeConsoleArgs,
|
|
111
123
|
omit: () => omit,
|
|
112
124
|
pick: () => pick,
|
|
113
125
|
rgbToHex: () => rgbToHex,
|
|
126
|
+
serializeLogEntries: () => serializeLogEntries,
|
|
127
|
+
setGlobalLogger: () => setGlobalLogger,
|
|
128
|
+
shouldLog: () => shouldLog,
|
|
114
129
|
slugify: () => slugify,
|
|
115
130
|
storage: () => storage,
|
|
131
|
+
stringifyLogData: () => stringifyLogData,
|
|
116
132
|
truncate: () => truncate,
|
|
117
133
|
twMerge: () => import_tailwind_merge.twMerge,
|
|
118
134
|
useAlert: () => useAlert,
|
|
@@ -127,6 +143,7 @@ __export(index_exports, {
|
|
|
127
143
|
useIsFocused: () => import_native5.useIsFocused,
|
|
128
144
|
useKeyboard: () => useKeyboard,
|
|
129
145
|
useLoading: () => useLoading,
|
|
146
|
+
useLogger: () => useLogger,
|
|
130
147
|
useMemoizedFn: () => useMemoizedFn,
|
|
131
148
|
useMutation: () => import_react_query.useMutation,
|
|
132
149
|
useNavigation: () => useNavigation,
|
|
@@ -406,6 +423,11 @@ var import_react2 = require("react");
|
|
|
406
423
|
function getThemeColors(theme, isDark) {
|
|
407
424
|
return {
|
|
408
425
|
primary: theme.colors.primary?.[500] || "#f38b32",
|
|
426
|
+
success: theme.colors.success?.[500] || "#22c55e",
|
|
427
|
+
warning: theme.colors.warning?.[500] || "#f59e0b",
|
|
428
|
+
error: theme.colors.error?.[500] || "#ef4444",
|
|
429
|
+
info: theme.colors.info?.[500] || theme.colors.secondary?.[500] || "#3b82f6",
|
|
430
|
+
muted: isDark ? "#9ca3af" : "#6b7280",
|
|
409
431
|
primarySurface: isDark ? theme.colors.primary?.[900] || "#7c2d12" : theme.colors.primary?.[50] || "#fff7ed",
|
|
410
432
|
background: theme.colors.background?.[500] || (isDark ? "#0a0a0a" : "#ffffff"),
|
|
411
433
|
card: theme.colors.card?.[500] || (isDark ? "#1f2937" : "#ffffff"),
|
|
@@ -502,6 +524,189 @@ function useAsyncState() {
|
|
|
502
524
|
|
|
503
525
|
// src/core/api/create-api.ts
|
|
504
526
|
var import_zod = require("zod");
|
|
527
|
+
|
|
528
|
+
// src/core/logger/utils.ts
|
|
529
|
+
var LOG_LEVEL_WEIGHT = {
|
|
530
|
+
debug: 10,
|
|
531
|
+
info: 20,
|
|
532
|
+
warn: 30,
|
|
533
|
+
error: 40
|
|
534
|
+
};
|
|
535
|
+
function shouldLog(currentLevel, nextLevel) {
|
|
536
|
+
return LOG_LEVEL_WEIGHT[nextLevel] >= LOG_LEVEL_WEIGHT[currentLevel];
|
|
537
|
+
}
|
|
538
|
+
function createLogEntry(input) {
|
|
539
|
+
return {
|
|
540
|
+
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
541
|
+
level: input.level,
|
|
542
|
+
message: input.message,
|
|
543
|
+
data: input.data,
|
|
544
|
+
namespace: input.namespace,
|
|
545
|
+
timestamp: Date.now(),
|
|
546
|
+
source: input.source ?? "logger"
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
function formatLogTime(timestamp) {
|
|
550
|
+
const date = new Date(timestamp);
|
|
551
|
+
const hh = String(date.getHours()).padStart(2, "0");
|
|
552
|
+
const mm = String(date.getMinutes()).padStart(2, "0");
|
|
553
|
+
const ss = String(date.getSeconds()).padStart(2, "0");
|
|
554
|
+
return `${hh}:${mm}:${ss}`;
|
|
555
|
+
}
|
|
556
|
+
function stringifyLogData(data) {
|
|
557
|
+
if (data === void 0) return "";
|
|
558
|
+
if (typeof data === "string") return data;
|
|
559
|
+
try {
|
|
560
|
+
return JSON.stringify(data, null, 2);
|
|
561
|
+
} catch {
|
|
562
|
+
return String(data);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
function normalizeConsoleArgs(args) {
|
|
566
|
+
if (args.length === 0) {
|
|
567
|
+
return { message: "", data: void 0 };
|
|
568
|
+
}
|
|
569
|
+
const [first, ...rest] = args;
|
|
570
|
+
if (typeof first === "string") {
|
|
571
|
+
return {
|
|
572
|
+
message: first,
|
|
573
|
+
data: rest.length === 0 ? void 0 : rest.length === 1 ? rest[0] : rest
|
|
574
|
+
};
|
|
575
|
+
}
|
|
576
|
+
return {
|
|
577
|
+
message: stringifyLogData(first),
|
|
578
|
+
data: args.length === 1 ? first : args
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
function serializeLogEntries(entries) {
|
|
582
|
+
return JSON.stringify(
|
|
583
|
+
entries.map((entry) => ({
|
|
584
|
+
id: entry.id,
|
|
585
|
+
level: entry.level,
|
|
586
|
+
message: entry.message,
|
|
587
|
+
namespace: entry.namespace,
|
|
588
|
+
timestamp: entry.timestamp,
|
|
589
|
+
source: entry.source,
|
|
590
|
+
data: entry.data
|
|
591
|
+
})),
|
|
592
|
+
null,
|
|
593
|
+
2
|
|
594
|
+
);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// src/core/logger/transports.ts
|
|
598
|
+
var ANSI_COLORS = {
|
|
599
|
+
debug: "\x1B[90m",
|
|
600
|
+
info: "\x1B[36m",
|
|
601
|
+
warn: "\x1B[33m",
|
|
602
|
+
error: "\x1B[31m",
|
|
603
|
+
reset: "\x1B[0m"
|
|
604
|
+
};
|
|
605
|
+
function supportsAnsiColors() {
|
|
606
|
+
return typeof process !== "undefined" && Boolean(process.stdout?.isTTY);
|
|
607
|
+
}
|
|
608
|
+
function resolveConsoleMethod(consoleRef, entry) {
|
|
609
|
+
const target = consoleRef ?? console;
|
|
610
|
+
if (entry.level === "debug" && typeof target.debug === "function") return target.debug.bind(target);
|
|
611
|
+
if (entry.level === "info" && typeof target.info === "function") return target.info.bind(target);
|
|
612
|
+
if (entry.level === "warn" && typeof target.warn === "function") return target.warn.bind(target);
|
|
613
|
+
if (entry.level === "error" && typeof target.error === "function") return target.error.bind(target);
|
|
614
|
+
return target.log.bind(target);
|
|
615
|
+
}
|
|
616
|
+
function createConsoleTransport(options = {}) {
|
|
617
|
+
const useAnsiColors = options.useAnsiColors ?? supportsAnsiColors();
|
|
618
|
+
return (entry) => {
|
|
619
|
+
if (entry.source === "console") return;
|
|
620
|
+
const method = resolveConsoleMethod(options.consoleRef, entry);
|
|
621
|
+
const time = formatLogTime(entry.timestamp);
|
|
622
|
+
const basePrefix = `[${time}] [${entry.level.toUpperCase()}]${entry.namespace ? ` [${entry.namespace}]` : ""}`;
|
|
623
|
+
const prefix = useAnsiColors ? `${ANSI_COLORS[entry.level]}${basePrefix}${ANSI_COLORS.reset}` : basePrefix;
|
|
624
|
+
if (entry.data === void 0) {
|
|
625
|
+
method(`${prefix} ${entry.message}`);
|
|
626
|
+
return;
|
|
627
|
+
}
|
|
628
|
+
method(`${prefix} ${entry.message}`, entry.data);
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
// src/core/logger/registry.ts
|
|
633
|
+
var globalLogger = null;
|
|
634
|
+
function setGlobalLogger(logger) {
|
|
635
|
+
globalLogger = logger;
|
|
636
|
+
}
|
|
637
|
+
function getGlobalLogger() {
|
|
638
|
+
return globalLogger;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// src/core/api/observability.ts
|
|
642
|
+
function defaultSanitize(value, sanitize, stage, field) {
|
|
643
|
+
if (!sanitize) return value;
|
|
644
|
+
return sanitize(value, { stage, field });
|
|
645
|
+
}
|
|
646
|
+
function resolveMessage(event) {
|
|
647
|
+
if (event.stage === "request") {
|
|
648
|
+
return `API Request ${event.method} ${event.path}`;
|
|
649
|
+
}
|
|
650
|
+
if (event.stage === "response") {
|
|
651
|
+
return `API Response ${event.method} ${event.path} ${event.statusCode ?? "-"}`;
|
|
652
|
+
}
|
|
653
|
+
return `API Error ${event.method} ${event.path}`;
|
|
654
|
+
}
|
|
655
|
+
function resolveLevel(error) {
|
|
656
|
+
if (!error) return "info";
|
|
657
|
+
if (error.code === "VALIDATION" || error.code === "BUSINESS") return "warn";
|
|
658
|
+
return "error";
|
|
659
|
+
}
|
|
660
|
+
function createApiLoggerTransport(config = {}) {
|
|
661
|
+
return (event) => {
|
|
662
|
+
const logger = config.logger ?? getGlobalLogger();
|
|
663
|
+
if (!logger) return;
|
|
664
|
+
const data = {
|
|
665
|
+
endpointName: event.endpointName,
|
|
666
|
+
method: event.method,
|
|
667
|
+
path: event.path,
|
|
668
|
+
url: event.url,
|
|
669
|
+
statusCode: event.statusCode,
|
|
670
|
+
durationMs: event.durationMs,
|
|
671
|
+
input: config.includeInput || event.stage !== "request" ? defaultSanitize(event.input, config.sanitize, event.stage, "input") : void 0,
|
|
672
|
+
responseData: config.includeResponseData ? defaultSanitize(event.responseData, config.sanitize, event.stage, "responseData") : void 0,
|
|
673
|
+
error: event.error ? defaultSanitize(
|
|
674
|
+
{
|
|
675
|
+
code: event.error.code,
|
|
676
|
+
message: event.error.message,
|
|
677
|
+
statusCode: event.error.statusCode,
|
|
678
|
+
retryable: event.error.retryable
|
|
679
|
+
},
|
|
680
|
+
config.sanitize,
|
|
681
|
+
event.stage,
|
|
682
|
+
"error"
|
|
683
|
+
) : void 0
|
|
684
|
+
};
|
|
685
|
+
const namespace = config.namespace ?? "api";
|
|
686
|
+
const message = resolveMessage(event);
|
|
687
|
+
if (event.stage === "request") {
|
|
688
|
+
logger.debug(message, data, namespace);
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
if (event.stage === "response") {
|
|
692
|
+
logger.info(message, data, namespace);
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
logger[resolveLevel(event.error)](message, data, namespace);
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
function resolveApiObservability(config) {
|
|
699
|
+
const enabled = config?.enabled ?? isDevelopment();
|
|
700
|
+
if (!enabled) {
|
|
701
|
+
return { enabled, transports: [] };
|
|
702
|
+
}
|
|
703
|
+
return {
|
|
704
|
+
enabled,
|
|
705
|
+
transports: [createApiLoggerTransport(config), ...config?.transports ?? []]
|
|
706
|
+
};
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// src/core/api/create-api.ts
|
|
505
710
|
function parseZodError(error) {
|
|
506
711
|
const first = error.errors[0];
|
|
507
712
|
return {
|
|
@@ -554,6 +759,7 @@ async function notifyError(error, context, endpoint, config) {
|
|
|
554
759
|
function createAPI(config) {
|
|
555
760
|
const endpoints = {};
|
|
556
761
|
const fetcher = config.fetcher ?? fetch;
|
|
762
|
+
const observability = resolveApiObservability(config.observability);
|
|
557
763
|
for (const [name, ep] of Object.entries(config.endpoints)) {
|
|
558
764
|
endpoints[name] = async (input) => {
|
|
559
765
|
const context = {
|
|
@@ -569,11 +775,43 @@ function createAPI(config) {
|
|
|
569
775
|
}
|
|
570
776
|
}
|
|
571
777
|
const url = config.baseURL + ep.path;
|
|
778
|
+
const startAt = Date.now();
|
|
779
|
+
if (observability.enabled) {
|
|
780
|
+
await Promise.all(
|
|
781
|
+
observability.transports.map(
|
|
782
|
+
(transport) => transport({
|
|
783
|
+
stage: "request",
|
|
784
|
+
endpointName: name,
|
|
785
|
+
path: ep.path,
|
|
786
|
+
method: ep.method,
|
|
787
|
+
url,
|
|
788
|
+
input
|
|
789
|
+
})
|
|
790
|
+
)
|
|
791
|
+
);
|
|
792
|
+
}
|
|
572
793
|
let response;
|
|
573
794
|
try {
|
|
574
795
|
response = await fetcher(url, { method: ep.method });
|
|
575
796
|
} catch (error) {
|
|
576
|
-
|
|
797
|
+
const enhanced = await notifyError(parseNetworkError(error), context, ep, config);
|
|
798
|
+
if (observability.enabled) {
|
|
799
|
+
await Promise.all(
|
|
800
|
+
observability.transports.map(
|
|
801
|
+
(transport) => transport({
|
|
802
|
+
stage: "error",
|
|
803
|
+
endpointName: name,
|
|
804
|
+
path: ep.path,
|
|
805
|
+
method: ep.method,
|
|
806
|
+
url,
|
|
807
|
+
input,
|
|
808
|
+
durationMs: Date.now() - startAt,
|
|
809
|
+
error: enhanced
|
|
810
|
+
})
|
|
811
|
+
)
|
|
812
|
+
);
|
|
813
|
+
}
|
|
814
|
+
throw enhanced;
|
|
577
815
|
}
|
|
578
816
|
context.response = response;
|
|
579
817
|
let data = void 0;
|
|
@@ -588,18 +826,115 @@ function createAPI(config) {
|
|
|
588
826
|
}
|
|
589
827
|
context.responseData = data;
|
|
590
828
|
if (!response.ok) {
|
|
591
|
-
|
|
829
|
+
const enhanced = await notifyError(parseHttpError(response, data), context, ep, config);
|
|
830
|
+
if (observability.enabled) {
|
|
831
|
+
await Promise.all(
|
|
832
|
+
observability.transports.map(
|
|
833
|
+
(transport) => transport({
|
|
834
|
+
stage: "error",
|
|
835
|
+
endpointName: name,
|
|
836
|
+
path: ep.path,
|
|
837
|
+
method: ep.method,
|
|
838
|
+
url,
|
|
839
|
+
input,
|
|
840
|
+
response,
|
|
841
|
+
responseData: data,
|
|
842
|
+
statusCode: response.status,
|
|
843
|
+
durationMs: Date.now() - startAt,
|
|
844
|
+
error: enhanced
|
|
845
|
+
})
|
|
846
|
+
)
|
|
847
|
+
);
|
|
848
|
+
}
|
|
849
|
+
throw enhanced;
|
|
592
850
|
}
|
|
593
851
|
const businessError = ep.parseBusinessError?.(data, response) ?? config.parseBusinessError?.(data, response);
|
|
594
852
|
if (businessError) {
|
|
595
|
-
|
|
853
|
+
const enhanced = await notifyError(businessError, context, ep, config);
|
|
854
|
+
if (observability.enabled) {
|
|
855
|
+
await Promise.all(
|
|
856
|
+
observability.transports.map(
|
|
857
|
+
(transport) => transport({
|
|
858
|
+
stage: "error",
|
|
859
|
+
endpointName: name,
|
|
860
|
+
path: ep.path,
|
|
861
|
+
method: ep.method,
|
|
862
|
+
url,
|
|
863
|
+
input,
|
|
864
|
+
response,
|
|
865
|
+
responseData: data,
|
|
866
|
+
statusCode: response.status,
|
|
867
|
+
durationMs: Date.now() - startAt,
|
|
868
|
+
error: enhanced
|
|
869
|
+
})
|
|
870
|
+
)
|
|
871
|
+
);
|
|
872
|
+
}
|
|
873
|
+
throw enhanced;
|
|
596
874
|
}
|
|
597
875
|
try {
|
|
598
876
|
if (ep.output) {
|
|
599
|
-
|
|
877
|
+
const parsed = ep.output.parse(data);
|
|
878
|
+
if (observability.enabled) {
|
|
879
|
+
await Promise.all(
|
|
880
|
+
observability.transports.map(
|
|
881
|
+
(transport) => transport({
|
|
882
|
+
stage: "response",
|
|
883
|
+
endpointName: name,
|
|
884
|
+
path: ep.path,
|
|
885
|
+
method: ep.method,
|
|
886
|
+
url,
|
|
887
|
+
input,
|
|
888
|
+
response,
|
|
889
|
+
responseData: parsed,
|
|
890
|
+
statusCode: response.status,
|
|
891
|
+
durationMs: Date.now() - startAt
|
|
892
|
+
})
|
|
893
|
+
)
|
|
894
|
+
);
|
|
895
|
+
}
|
|
896
|
+
return parsed;
|
|
600
897
|
}
|
|
601
898
|
} catch (error) {
|
|
602
|
-
|
|
899
|
+
const enhanced = await notifyError(parseUnknownError(error), context, ep, config);
|
|
900
|
+
if (observability.enabled) {
|
|
901
|
+
await Promise.all(
|
|
902
|
+
observability.transports.map(
|
|
903
|
+
(transport) => transport({
|
|
904
|
+
stage: "error",
|
|
905
|
+
endpointName: name,
|
|
906
|
+
path: ep.path,
|
|
907
|
+
method: ep.method,
|
|
908
|
+
url,
|
|
909
|
+
input,
|
|
910
|
+
response,
|
|
911
|
+
responseData: data,
|
|
912
|
+
statusCode: response.status,
|
|
913
|
+
durationMs: Date.now() - startAt,
|
|
914
|
+
error: enhanced
|
|
915
|
+
})
|
|
916
|
+
)
|
|
917
|
+
);
|
|
918
|
+
}
|
|
919
|
+
throw enhanced;
|
|
920
|
+
}
|
|
921
|
+
if (observability.enabled) {
|
|
922
|
+
await Promise.all(
|
|
923
|
+
observability.transports.map(
|
|
924
|
+
(transport) => transport({
|
|
925
|
+
stage: "response",
|
|
926
|
+
endpointName: name,
|
|
927
|
+
path: ep.path,
|
|
928
|
+
method: ep.method,
|
|
929
|
+
url,
|
|
930
|
+
input,
|
|
931
|
+
response,
|
|
932
|
+
responseData: data,
|
|
933
|
+
statusCode: response.status,
|
|
934
|
+
durationMs: Date.now() - startAt
|
|
935
|
+
})
|
|
936
|
+
)
|
|
937
|
+
);
|
|
603
938
|
}
|
|
604
939
|
return data;
|
|
605
940
|
};
|
|
@@ -1205,6 +1540,7 @@ function AppScrollView({
|
|
|
1205
1540
|
surface,
|
|
1206
1541
|
rounded,
|
|
1207
1542
|
className,
|
|
1543
|
+
dismissKeyboardOnPressOutside = false,
|
|
1208
1544
|
children,
|
|
1209
1545
|
style,
|
|
1210
1546
|
...props
|
|
@@ -1212,7 +1548,7 @@ function AppScrollView({
|
|
|
1212
1548
|
const { theme, isDark } = useOptionalTheme();
|
|
1213
1549
|
const resolvedBgColor = resolveSurfaceColor(surface, theme, isDark) ?? resolveNamedColor(bg, theme, isDark);
|
|
1214
1550
|
const shouldUseClassBg = !!bg && !resolvedBgColor;
|
|
1215
|
-
|
|
1551
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
1216
1552
|
import_react_native2.ScrollView,
|
|
1217
1553
|
{
|
|
1218
1554
|
className: cn(
|
|
@@ -1225,11 +1561,16 @@ function AppScrollView({
|
|
|
1225
1561
|
rounded && `rounded-${rounded}`,
|
|
1226
1562
|
className
|
|
1227
1563
|
),
|
|
1228
|
-
style: [resolvedBgColor ? { backgroundColor: resolvedBgColor } : void 0, style],
|
|
1229
1564
|
...props,
|
|
1565
|
+
style: [resolvedBgColor ? { backgroundColor: resolvedBgColor } : void 0, style],
|
|
1566
|
+
keyboardShouldPersistTaps: dismissKeyboardOnPressOutside ? props.keyboardShouldPersistTaps ?? "handled" : props.keyboardShouldPersistTaps,
|
|
1230
1567
|
children
|
|
1231
1568
|
}
|
|
1232
1569
|
);
|
|
1570
|
+
if (!dismissKeyboardOnPressOutside) {
|
|
1571
|
+
return content;
|
|
1572
|
+
}
|
|
1573
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react_native2.TouchableWithoutFeedback, { onPress: import_react_native2.Keyboard.dismiss, accessible: false, children: content });
|
|
1233
1574
|
}
|
|
1234
1575
|
|
|
1235
1576
|
// src/ui/primitives/AppText.tsx
|
|
@@ -1312,8 +1653,19 @@ function AppPressable({
|
|
|
1312
1653
|
);
|
|
1313
1654
|
}
|
|
1314
1655
|
|
|
1315
|
-
// src/ui/
|
|
1656
|
+
// src/ui/primitives/KeyboardDismissView.tsx
|
|
1657
|
+
var import_react_native5 = require("react-native");
|
|
1316
1658
|
var import_jsx_runtime6 = require("nativewind/jsx-runtime");
|
|
1659
|
+
function KeyboardDismissView({ enabled = true, children, ...props }) {
|
|
1660
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(AppView, { ...props, children });
|
|
1661
|
+
if (!enabled) {
|
|
1662
|
+
return content;
|
|
1663
|
+
}
|
|
1664
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_react_native5.TouchableWithoutFeedback, { onPress: import_react_native5.Keyboard.dismiss, accessible: false, children: content });
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
// src/ui/layout/Row.tsx
|
|
1668
|
+
var import_jsx_runtime7 = require("nativewind/jsx-runtime");
|
|
1317
1669
|
var justifyMap = {
|
|
1318
1670
|
start: "justify-start",
|
|
1319
1671
|
center: "justify-center",
|
|
@@ -1328,11 +1680,11 @@ var itemsMap = {
|
|
|
1328
1680
|
stretch: "items-stretch"
|
|
1329
1681
|
};
|
|
1330
1682
|
function Row({ justify = "start", items = "center", className, ...props }) {
|
|
1331
|
-
return /* @__PURE__ */ (0,
|
|
1683
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(AppView, { row: true, className: cn(justifyMap[justify], itemsMap[items], className), ...props });
|
|
1332
1684
|
}
|
|
1333
1685
|
|
|
1334
1686
|
// src/ui/layout/Col.tsx
|
|
1335
|
-
var
|
|
1687
|
+
var import_jsx_runtime8 = require("nativewind/jsx-runtime");
|
|
1336
1688
|
var justifyMap2 = {
|
|
1337
1689
|
start: "justify-start",
|
|
1338
1690
|
center: "justify-center",
|
|
@@ -1347,19 +1699,19 @@ var itemsMap2 = {
|
|
|
1347
1699
|
stretch: "items-stretch"
|
|
1348
1700
|
};
|
|
1349
1701
|
function Col({ justify = "start", items = "stretch", className, ...props }) {
|
|
1350
|
-
return /* @__PURE__ */ (0,
|
|
1702
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(AppView, { className: cn(justifyMap2[justify], itemsMap2[items], className), ...props });
|
|
1351
1703
|
}
|
|
1352
1704
|
|
|
1353
1705
|
// src/ui/layout/Center.tsx
|
|
1354
|
-
var
|
|
1706
|
+
var import_jsx_runtime9 = require("nativewind/jsx-runtime");
|
|
1355
1707
|
function Center({ flex = true, ...props }) {
|
|
1356
|
-
return /* @__PURE__ */ (0,
|
|
1708
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(AppView, { center: true, flex, ...props });
|
|
1357
1709
|
}
|
|
1358
1710
|
|
|
1359
1711
|
// src/ui/layout/SafeScreen.tsx
|
|
1360
|
-
var
|
|
1712
|
+
var import_react_native6 = require("react-native");
|
|
1361
1713
|
var import_react_native_safe_area_context = require("react-native-safe-area-context");
|
|
1362
|
-
var
|
|
1714
|
+
var import_jsx_runtime10 = require("nativewind/jsx-runtime");
|
|
1363
1715
|
function SafeScreen({
|
|
1364
1716
|
top = true,
|
|
1365
1717
|
bottom = true,
|
|
@@ -1368,6 +1720,7 @@ function SafeScreen({
|
|
|
1368
1720
|
bg,
|
|
1369
1721
|
surface,
|
|
1370
1722
|
flex = true,
|
|
1723
|
+
dismissKeyboardOnPressOutside = false,
|
|
1371
1724
|
className,
|
|
1372
1725
|
children,
|
|
1373
1726
|
style,
|
|
@@ -1377,8 +1730,8 @@ function SafeScreen({
|
|
|
1377
1730
|
const { theme, isDark } = useOptionalTheme();
|
|
1378
1731
|
const resolvedBgColor = resolveSurfaceColor(surface, theme, isDark) ?? resolveNamedColor(bg, theme, isDark);
|
|
1379
1732
|
const shouldUseClassBg = !!bg && !resolvedBgColor;
|
|
1380
|
-
|
|
1381
|
-
|
|
1733
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
|
|
1734
|
+
import_react_native6.View,
|
|
1382
1735
|
{
|
|
1383
1736
|
className: cn(flex && "flex-1", shouldUseClassBg && `bg-${bg}`, className),
|
|
1384
1737
|
style: [
|
|
@@ -1396,8 +1749,12 @@ function SafeScreen({
|
|
|
1396
1749
|
children
|
|
1397
1750
|
}
|
|
1398
1751
|
);
|
|
1752
|
+
if (!dismissKeyboardOnPressOutside) {
|
|
1753
|
+
return content;
|
|
1754
|
+
}
|
|
1755
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_react_native6.TouchableWithoutFeedback, { onPress: import_react_native6.Keyboard.dismiss, accessible: false, children: content });
|
|
1399
1756
|
}
|
|
1400
|
-
var styles =
|
|
1757
|
+
var styles = import_react_native6.StyleSheet.create({
|
|
1401
1758
|
flex: {
|
|
1402
1759
|
flex: 1
|
|
1403
1760
|
}
|
|
@@ -1407,19 +1764,20 @@ function AppScreen({
|
|
|
1407
1764
|
className,
|
|
1408
1765
|
...props
|
|
1409
1766
|
}) {
|
|
1410
|
-
return /* @__PURE__ */ (0,
|
|
1767
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SafeScreen, { flex: true, surface: "background", ...props, className, children });
|
|
1411
1768
|
}
|
|
1412
1769
|
function SafeBottom({
|
|
1413
1770
|
children,
|
|
1414
1771
|
className,
|
|
1415
1772
|
...props
|
|
1416
1773
|
}) {
|
|
1417
|
-
return /* @__PURE__ */ (0,
|
|
1774
|
+
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(SafeScreen, { bottom: true, left: true, right: true, flex: false, ...props, className, children });
|
|
1418
1775
|
}
|
|
1419
1776
|
|
|
1420
1777
|
// src/ui/actions/AppButton.tsx
|
|
1421
|
-
var
|
|
1422
|
-
var
|
|
1778
|
+
var import_react13 = require("react");
|
|
1779
|
+
var import_react_native7 = require("react-native");
|
|
1780
|
+
var import_jsx_runtime11 = require("nativewind/jsx-runtime");
|
|
1423
1781
|
function AppButton({
|
|
1424
1782
|
variant = "solid",
|
|
1425
1783
|
size = "md",
|
|
@@ -1427,6 +1785,7 @@ function AppButton({
|
|
|
1427
1785
|
loading,
|
|
1428
1786
|
disabled,
|
|
1429
1787
|
onPress,
|
|
1788
|
+
dismissKeyboardOnPress = true,
|
|
1430
1789
|
children,
|
|
1431
1790
|
className
|
|
1432
1791
|
}) {
|
|
@@ -1447,11 +1806,17 @@ function AppButton({
|
|
|
1447
1806
|
const ghostBackgroundColor = isDark ? "rgba(255,255,255,0.04)" : "transparent";
|
|
1448
1807
|
const loadingColor = variant === "solid" ? "white" : buttonColors[color];
|
|
1449
1808
|
const textColor = variant === "solid" ? "#ffffff" : variant === "ghost" ? ghostTextColor : buttonColors[color];
|
|
1809
|
+
const handlePress = (0, import_react13.useCallback)(() => {
|
|
1810
|
+
if (dismissKeyboardOnPress) {
|
|
1811
|
+
import_react_native7.Keyboard.dismiss();
|
|
1812
|
+
}
|
|
1813
|
+
onPress?.();
|
|
1814
|
+
}, [dismissKeyboardOnPress, onPress]);
|
|
1450
1815
|
const buttonStyle = variant === "solid" ? { backgroundColor: buttonColors[color] } : variant === "outline" ? { borderWidth: 0.5, borderColor: buttonColors[color], backgroundColor: "transparent" } : { backgroundColor: ghostBackgroundColor };
|
|
1451
|
-
return /* @__PURE__ */ (0,
|
|
1816
|
+
return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
|
|
1452
1817
|
AppPressable,
|
|
1453
1818
|
{
|
|
1454
|
-
onPress,
|
|
1819
|
+
onPress: onPress ? handlePress : void 0,
|
|
1455
1820
|
disabled: isDisabled,
|
|
1456
1821
|
className: cn(
|
|
1457
1822
|
"flex-row items-center justify-center rounded-lg",
|
|
@@ -1460,30 +1825,61 @@ function AppButton({
|
|
|
1460
1825
|
className
|
|
1461
1826
|
),
|
|
1462
1827
|
style: buttonStyle,
|
|
1463
|
-
children: loading ? /* @__PURE__ */ (0,
|
|
1828
|
+
children: loading ? /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react_native7.ActivityIndicator, { size: "small", color: loadingColor }) : /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(AppText, { weight: "semibold", style: { color: textColor }, children })
|
|
1464
1829
|
}
|
|
1465
1830
|
);
|
|
1466
1831
|
}
|
|
1467
1832
|
|
|
1468
1833
|
// src/ui/feedback/Toast.tsx
|
|
1469
|
-
var
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
error: "bg-red-500",
|
|
1473
|
-
warning: "bg-yellow-500",
|
|
1474
|
-
info: "bg-blue-500"
|
|
1475
|
-
};
|
|
1476
|
-
function Toast({ message, type = "info", visible = true }) {
|
|
1834
|
+
var import_jsx_runtime12 = require("nativewind/jsx-runtime");
|
|
1835
|
+
function Toast({ message, type = "info", visible = true, testID }) {
|
|
1836
|
+
const { theme } = useOptionalTheme();
|
|
1477
1837
|
if (!visible) return null;
|
|
1478
|
-
|
|
1838
|
+
const palette = {
|
|
1839
|
+
success: {
|
|
1840
|
+
backgroundColor: theme.colors.success?.[500] || "#22c55e",
|
|
1841
|
+
textColor: "#ffffff"
|
|
1842
|
+
},
|
|
1843
|
+
error: {
|
|
1844
|
+
backgroundColor: theme.colors.error?.[500] || "#ef4444",
|
|
1845
|
+
textColor: "#ffffff"
|
|
1846
|
+
},
|
|
1847
|
+
warning: {
|
|
1848
|
+
backgroundColor: theme.colors.warning?.[500] || "#f59e0b",
|
|
1849
|
+
textColor: "#111827"
|
|
1850
|
+
},
|
|
1851
|
+
info: {
|
|
1852
|
+
backgroundColor: theme.colors.info?.[500] || theme.colors.primary?.[500] || "#3b82f6",
|
|
1853
|
+
textColor: "#ffffff"
|
|
1854
|
+
}
|
|
1855
|
+
};
|
|
1856
|
+
const currentPalette = palette[type];
|
|
1857
|
+
return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
|
|
1858
|
+
AppView,
|
|
1859
|
+
{
|
|
1860
|
+
testID,
|
|
1861
|
+
className: "px-4 py-3 rounded-lg",
|
|
1862
|
+
style: { backgroundColor: currentPalette.backgroundColor },
|
|
1863
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(AppText, { style: { color: currentPalette.textColor }, children: message })
|
|
1864
|
+
}
|
|
1865
|
+
);
|
|
1479
1866
|
}
|
|
1480
1867
|
|
|
1481
1868
|
// src/ui/feedback/Alert.tsx
|
|
1482
|
-
var
|
|
1483
|
-
var
|
|
1484
|
-
var
|
|
1869
|
+
var import_react14 = require("react");
|
|
1870
|
+
var import_react_native8 = require("react-native");
|
|
1871
|
+
var import_jsx_runtime13 = require("nativewind/jsx-runtime");
|
|
1872
|
+
function createAnimatedValue(value) {
|
|
1873
|
+
const AnimatedValue = import_react_native8.Animated.Value;
|
|
1874
|
+
try {
|
|
1875
|
+
return new AnimatedValue(value);
|
|
1876
|
+
} catch {
|
|
1877
|
+
return AnimatedValue(value);
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1485
1880
|
function Alert({ visible, title, message, buttons, onClose }) {
|
|
1486
1881
|
const { theme, isDark } = useTheme();
|
|
1882
|
+
const progress = (0, import_react14.useRef)(createAnimatedValue(0)).current;
|
|
1487
1883
|
const modalBgColor = isDark ? "#1f2937" : "#ffffff";
|
|
1488
1884
|
const textColor = isDark ? "#ffffff" : "#1f2937";
|
|
1489
1885
|
const messageColor = isDark ? "#9ca3af" : "#6b7280";
|
|
@@ -1491,7 +1887,19 @@ function Alert({ visible, title, message, buttons, onClose }) {
|
|
|
1491
1887
|
const cancelButtonBg = isDark ? "#374151" : "#f3f4f6";
|
|
1492
1888
|
const cancelButtonText = isDark ? "#ffffff" : "#374151";
|
|
1493
1889
|
const destructiveColor = theme.colors.error?.[500] || "#ef4444";
|
|
1494
|
-
|
|
1890
|
+
(0, import_react14.useEffect)(() => {
|
|
1891
|
+
if (!visible) {
|
|
1892
|
+
progress.setValue(0);
|
|
1893
|
+
return;
|
|
1894
|
+
}
|
|
1895
|
+
progress.setValue(0);
|
|
1896
|
+
import_react_native8.Animated.timing(progress, {
|
|
1897
|
+
toValue: 1,
|
|
1898
|
+
duration: 220,
|
|
1899
|
+
useNativeDriver: true
|
|
1900
|
+
}).start();
|
|
1901
|
+
}, [progress, visible]);
|
|
1902
|
+
const handleButtonPress = (0, import_react14.useCallback)(
|
|
1495
1903
|
(button) => (e) => {
|
|
1496
1904
|
e.stopPropagation();
|
|
1497
1905
|
button.onPress?.();
|
|
@@ -1528,108 +1936,141 @@ function Alert({ visible, title, message, buttons, onClose }) {
|
|
|
1528
1936
|
}
|
|
1529
1937
|
return "#ffffff";
|
|
1530
1938
|
};
|
|
1531
|
-
return /* @__PURE__ */ (0,
|
|
1532
|
-
|
|
1939
|
+
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1940
|
+
import_react_native8.Modal,
|
|
1533
1941
|
{
|
|
1534
1942
|
visible,
|
|
1535
1943
|
transparent: true,
|
|
1536
|
-
animationType: "
|
|
1944
|
+
animationType: "none",
|
|
1537
1945
|
onRequestClose: onClose,
|
|
1538
1946
|
statusBarTranslucent: true,
|
|
1539
|
-
children: /* @__PURE__ */ (0,
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
{
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1947
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(AppView, { className: "flex-1", center: true, children: [
|
|
1948
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1949
|
+
import_react_native8.Animated.View,
|
|
1950
|
+
{
|
|
1951
|
+
style: [
|
|
1952
|
+
import_react_native8.StyleSheet.absoluteFillObject,
|
|
1953
|
+
{
|
|
1954
|
+
backgroundColor: "rgba(0,0,0,0.5)",
|
|
1955
|
+
opacity: progress
|
|
1956
|
+
}
|
|
1957
|
+
]
|
|
1958
|
+
}
|
|
1959
|
+
),
|
|
1960
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(
|
|
1961
|
+
import_react_native8.Animated.View,
|
|
1962
|
+
{
|
|
1963
|
+
className: "rounded-xl mx-8 min-w-[280px]",
|
|
1964
|
+
style: [
|
|
1965
|
+
{
|
|
1966
|
+
backgroundColor: modalBgColor,
|
|
1967
|
+
opacity: progress,
|
|
1968
|
+
transform: [
|
|
1969
|
+
{
|
|
1970
|
+
translateY: progress.interpolate({
|
|
1971
|
+
inputRange: [0, 1],
|
|
1972
|
+
outputRange: [16, 0]
|
|
1973
|
+
})
|
|
1974
|
+
},
|
|
1975
|
+
{
|
|
1976
|
+
scale: progress.interpolate({
|
|
1977
|
+
inputRange: [0, 1],
|
|
1978
|
+
outputRange: [0.96, 1]
|
|
1979
|
+
})
|
|
1980
|
+
}
|
|
1981
|
+
]
|
|
1982
|
+
}
|
|
1983
|
+
],
|
|
1984
|
+
children: [
|
|
1985
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(AppView, { className: "px-6 py-5", children: [
|
|
1986
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
1987
|
+
AppText,
|
|
1988
|
+
{
|
|
1989
|
+
size: "lg",
|
|
1990
|
+
weight: "semibold",
|
|
1991
|
+
className: "text-center mb-2",
|
|
1992
|
+
style: { color: textColor },
|
|
1993
|
+
children: title
|
|
1994
|
+
}
|
|
1995
|
+
),
|
|
1996
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AppText, { size: "sm", style: { color: messageColor }, className: "text-center leading-5", children: message })
|
|
1997
|
+
] }),
|
|
1998
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AppView, { className: "border-t", style: { borderTopColor: borderColor }, children: buttons.length === 1 ? (
|
|
1999
|
+
// 单个按钮
|
|
2000
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2001
|
+
import_react_native8.TouchableOpacity,
|
|
2002
|
+
{
|
|
2003
|
+
onPress: handleButtonPress(buttons[0]),
|
|
2004
|
+
className: "py-3 rounded-b-xl",
|
|
2005
|
+
style: [styles2.singleButton, getButtonStyle(buttons[0])],
|
|
2006
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2007
|
+
AppText,
|
|
2008
|
+
{
|
|
2009
|
+
weight: "medium",
|
|
2010
|
+
className: "text-center",
|
|
2011
|
+
style: { color: getButtonTextColor(buttons[0]) },
|
|
2012
|
+
children: buttons[0].text
|
|
2013
|
+
}
|
|
2014
|
+
)
|
|
2015
|
+
}
|
|
2016
|
+
)
|
|
2017
|
+
) : buttons.length === 2 ? (
|
|
2018
|
+
// 两个按钮横向排列
|
|
2019
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AppView, { row: true, style: styles2.twoButtonContainer, children: buttons.map((button, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2020
|
+
import_react_native8.TouchableOpacity,
|
|
2021
|
+
{
|
|
2022
|
+
onPress: handleButtonPress(button),
|
|
2023
|
+
className: cn(
|
|
2024
|
+
"py-3 flex-1",
|
|
2025
|
+
index === 0 && "rounded-bl-xl",
|
|
2026
|
+
index === 1 && "rounded-br-xl"
|
|
2027
|
+
),
|
|
2028
|
+
style: [
|
|
2029
|
+
styles2.twoButton,
|
|
2030
|
+
index > 0 && { borderLeftColor: borderColor },
|
|
2031
|
+
getButtonStyle(button)
|
|
2032
|
+
],
|
|
2033
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2034
|
+
AppText,
|
|
2035
|
+
{
|
|
2036
|
+
weight: "medium",
|
|
2037
|
+
className: "text-center",
|
|
2038
|
+
style: { color: getButtonTextColor(button) },
|
|
2039
|
+
children: button.text
|
|
2040
|
+
}
|
|
2041
|
+
)
|
|
2042
|
+
},
|
|
2043
|
+
index
|
|
2044
|
+
)) })
|
|
2045
|
+
) : (
|
|
2046
|
+
// 多个按钮纵向排列
|
|
2047
|
+
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AppView, { className: "gap-2 pb-4 px-4", children: buttons.map((button, index) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2048
|
+
import_react_native8.TouchableOpacity,
|
|
2049
|
+
{
|
|
2050
|
+
onPress: handleButtonPress(button),
|
|
2051
|
+
className: "py-3 rounded-lg",
|
|
2052
|
+
style: getButtonStyle(button),
|
|
2053
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(
|
|
2054
|
+
AppText,
|
|
2055
|
+
{
|
|
2056
|
+
weight: "medium",
|
|
2057
|
+
className: "text-center",
|
|
2058
|
+
style: { color: getButtonTextColor(button) },
|
|
2059
|
+
children: button.text
|
|
2060
|
+
}
|
|
2061
|
+
)
|
|
2062
|
+
},
|
|
2063
|
+
index
|
|
2064
|
+
)) })
|
|
2065
|
+
) })
|
|
2066
|
+
]
|
|
2067
|
+
}
|
|
2068
|
+
)
|
|
2069
|
+
] })
|
|
1629
2070
|
}
|
|
1630
2071
|
);
|
|
1631
2072
|
}
|
|
1632
|
-
var styles2 =
|
|
2073
|
+
var styles2 = import_react_native8.StyleSheet.create({
|
|
1633
2074
|
singleButton: {
|
|
1634
2075
|
borderBottomLeftRadius: 12,
|
|
1635
2076
|
borderBottomRightRadius: 12
|
|
@@ -1644,19 +2085,8 @@ var styles2 = import_react_native7.StyleSheet.create({
|
|
|
1644
2085
|
});
|
|
1645
2086
|
|
|
1646
2087
|
// src/ui/feedback/Loading.tsx
|
|
1647
|
-
var
|
|
1648
|
-
var
|
|
1649
|
-
function Loading({ text, color, overlay = false, visible = true, testID }) {
|
|
1650
|
-
if (!visible) return null;
|
|
1651
|
-
const content = /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(AppView, { center: true, gap: 3, testID, children: [
|
|
1652
|
-
/* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_react_native8.ActivityIndicator, { size: "large", color }),
|
|
1653
|
-
text && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AppText, { style: color ? { color } : void 0, children: text })
|
|
1654
|
-
] });
|
|
1655
|
-
if (overlay) {
|
|
1656
|
-
return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(AppView, { center: true, flex: true, className: "absolute inset-0 bg-black/30", testID, children: content });
|
|
1657
|
-
}
|
|
1658
|
-
return content;
|
|
1659
|
-
}
|
|
2088
|
+
var import_react_native14 = require("react-native");
|
|
2089
|
+
var import_react18 = require("react");
|
|
1660
2090
|
|
|
1661
2091
|
// src/ui/display/Progress.tsx
|
|
1662
2092
|
var import_jsx_runtime14 = require("nativewind/jsx-runtime");
|
|
@@ -1850,7 +2280,7 @@ var FileIcons = {
|
|
|
1850
2280
|
};
|
|
1851
2281
|
|
|
1852
2282
|
// src/ui/display/AppImage.tsx
|
|
1853
|
-
var
|
|
2283
|
+
var import_react15 = require("react");
|
|
1854
2284
|
var import_react_native11 = require("react-native");
|
|
1855
2285
|
var import_jsx_runtime17 = require("nativewind/jsx-runtime");
|
|
1856
2286
|
var radiusMap = {
|
|
@@ -1886,15 +2316,15 @@ function AppImage({
|
|
|
1886
2316
|
className,
|
|
1887
2317
|
style
|
|
1888
2318
|
}) {
|
|
1889
|
-
const [isLoading, setIsLoading] = (0,
|
|
1890
|
-
const [hasError, setHasError] = (0,
|
|
2319
|
+
const [isLoading, setIsLoading] = (0, import_react15.useState)(true);
|
|
2320
|
+
const [hasError, setHasError] = (0, import_react15.useState)(false);
|
|
1891
2321
|
const { theme } = useTheme();
|
|
1892
2322
|
const resolvedRadius = resolveRadius(borderRadius);
|
|
1893
|
-
const handleLoad = (0,
|
|
2323
|
+
const handleLoad = (0, import_react15.useCallback)(() => {
|
|
1894
2324
|
setIsLoading(false);
|
|
1895
2325
|
onLoad?.();
|
|
1896
2326
|
}, [onLoad]);
|
|
1897
|
-
const handleError = (0,
|
|
2327
|
+
const handleError = (0, import_react15.useCallback)(
|
|
1898
2328
|
(error) => {
|
|
1899
2329
|
setIsLoading(false);
|
|
1900
2330
|
setHasError(true);
|
|
@@ -2008,9 +2438,18 @@ function AppImage({
|
|
|
2008
2438
|
}
|
|
2009
2439
|
|
|
2010
2440
|
// src/ui/display/AppList.tsx
|
|
2011
|
-
var
|
|
2441
|
+
var import_react16 = __toESM(require("react"));
|
|
2012
2442
|
var import_react_native12 = require("react-native");
|
|
2013
2443
|
var import_jsx_runtime18 = require("nativewind/jsx-runtime");
|
|
2444
|
+
function renderListSlot(slot) {
|
|
2445
|
+
if (!slot) return null;
|
|
2446
|
+
if (import_react16.default.isValidElement(slot)) return slot;
|
|
2447
|
+
if (typeof slot === "function") {
|
|
2448
|
+
const SlotComponent = slot;
|
|
2449
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SlotComponent, {});
|
|
2450
|
+
}
|
|
2451
|
+
return null;
|
|
2452
|
+
}
|
|
2014
2453
|
function SkeletonItem2({ render }) {
|
|
2015
2454
|
const colors = useThemeColors();
|
|
2016
2455
|
if (render) {
|
|
@@ -2110,8 +2549,8 @@ function AppList({
|
|
|
2110
2549
|
showsHorizontalScrollIndicator
|
|
2111
2550
|
}) {
|
|
2112
2551
|
const { theme } = useTheme();
|
|
2113
|
-
const [isLoadingMore, setIsLoadingMore] = (0,
|
|
2114
|
-
const handleEndReached = (0,
|
|
2552
|
+
const [isLoadingMore, setIsLoadingMore] = (0, import_react16.useState)(false);
|
|
2553
|
+
const handleEndReached = (0, import_react16.useCallback)(async () => {
|
|
2115
2554
|
if (isLoadingMore || !hasMore || !onEndReached) return;
|
|
2116
2555
|
setIsLoadingMore(true);
|
|
2117
2556
|
try {
|
|
@@ -2120,14 +2559,14 @@ function AppList({
|
|
|
2120
2559
|
setIsLoadingMore(false);
|
|
2121
2560
|
}
|
|
2122
2561
|
}, [isLoadingMore, hasMore, onEndReached]);
|
|
2123
|
-
const defaultKeyExtractor = (0,
|
|
2562
|
+
const defaultKeyExtractor = (0, import_react16.useCallback)(
|
|
2124
2563
|
(item, index) => {
|
|
2125
2564
|
if (keyExtractor) return keyExtractor(item, index);
|
|
2126
2565
|
return `item-${index}`;
|
|
2127
2566
|
},
|
|
2128
2567
|
[keyExtractor]
|
|
2129
2568
|
);
|
|
2130
|
-
const wrappedRenderItem = (0,
|
|
2569
|
+
const wrappedRenderItem = (0, import_react16.useCallback)(
|
|
2131
2570
|
(info) => {
|
|
2132
2571
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
2133
2572
|
divider && info.index > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Divider, { style: dividerStyle }),
|
|
@@ -2136,14 +2575,18 @@ function AppList({
|
|
|
2136
2575
|
},
|
|
2137
2576
|
[renderItem, divider, dividerStyle]
|
|
2138
2577
|
);
|
|
2139
|
-
const skeletonData = (0,
|
|
2578
|
+
const skeletonData = (0, import_react16.useMemo)(
|
|
2140
2579
|
() => new Array(skeletonCount).fill(null).map((_, i) => ({ _skeletonId: i })),
|
|
2141
2580
|
[skeletonCount]
|
|
2142
2581
|
);
|
|
2143
|
-
const skeletonRenderItem = (0,
|
|
2582
|
+
const skeletonRenderItem = (0, import_react16.useCallback)(
|
|
2144
2583
|
() => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SkeletonItem2, { render: skeletonRender }),
|
|
2145
2584
|
[skeletonRender]
|
|
2146
2585
|
);
|
|
2586
|
+
const flatListKey = (0, import_react16.useMemo)(() => {
|
|
2587
|
+
if (horizontal) return "app-list-horizontal";
|
|
2588
|
+
return `app-list-columns-${numColumns ?? 1}`;
|
|
2589
|
+
}, [horizontal, numColumns]);
|
|
2147
2590
|
if (loading && data.length === 0) {
|
|
2148
2591
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2149
2592
|
import_react_native12.FlatList,
|
|
@@ -2155,7 +2598,8 @@ function AppList({
|
|
|
2155
2598
|
style,
|
|
2156
2599
|
showsVerticalScrollIndicator,
|
|
2157
2600
|
showsHorizontalScrollIndicator
|
|
2158
|
-
}
|
|
2601
|
+
},
|
|
2602
|
+
`${flatListKey}-skeleton`
|
|
2159
2603
|
);
|
|
2160
2604
|
}
|
|
2161
2605
|
if (error && data.length === 0) {
|
|
@@ -2170,16 +2614,20 @@ function AppList({
|
|
|
2170
2614
|
}
|
|
2171
2615
|
) });
|
|
2172
2616
|
}
|
|
2173
|
-
const ListEmptyComponent = (0,
|
|
2174
|
-
if (EmptyComponent) return
|
|
2617
|
+
const ListEmptyComponent = (0, import_react16.useMemo)(() => {
|
|
2618
|
+
if (EmptyComponent) return renderListSlot(EmptyComponent);
|
|
2175
2619
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(EmptyState, { title: emptyTitle, description: emptyDescription, icon: emptyIcon });
|
|
2176
2620
|
}, [EmptyComponent, emptyTitle, emptyDescription, emptyIcon]);
|
|
2177
|
-
const FooterComponent = (0,
|
|
2621
|
+
const FooterComponent = (0, import_react16.useMemo)(() => {
|
|
2178
2622
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
|
|
2179
2623
|
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)(LoadMoreFooter, { loading: isLoadingMore }),
|
|
2180
|
-
ListFooterComponent
|
|
2624
|
+
renderListSlot(ListFooterComponent)
|
|
2181
2625
|
] });
|
|
2182
2626
|
}, [isLoadingMore, ListFooterComponent]);
|
|
2627
|
+
const HeaderComponent = (0, import_react16.useMemo)(
|
|
2628
|
+
() => renderListSlot(ListHeaderComponent),
|
|
2629
|
+
[ListHeaderComponent]
|
|
2630
|
+
);
|
|
2183
2631
|
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
|
|
2184
2632
|
import_react_native12.FlatList,
|
|
2185
2633
|
{
|
|
@@ -2198,7 +2646,7 @@ function AppList({
|
|
|
2198
2646
|
onEndReached: onEndReached ? handleEndReached : void 0,
|
|
2199
2647
|
onEndReachedThreshold,
|
|
2200
2648
|
ListEmptyComponent,
|
|
2201
|
-
ListHeaderComponent,
|
|
2649
|
+
ListHeaderComponent: HeaderComponent,
|
|
2202
2650
|
ListFooterComponent: FooterComponent,
|
|
2203
2651
|
contentContainerStyle,
|
|
2204
2652
|
style,
|
|
@@ -2211,7 +2659,8 @@ function AppList({
|
|
|
2211
2659
|
maxToRenderPerBatch: 10,
|
|
2212
2660
|
windowSize: 10,
|
|
2213
2661
|
initialNumToRender: 10
|
|
2214
|
-
}
|
|
2662
|
+
},
|
|
2663
|
+
flatListKey
|
|
2215
2664
|
);
|
|
2216
2665
|
}
|
|
2217
2666
|
var styles3 = import_react_native12.StyleSheet.create({
|
|
@@ -2221,7 +2670,7 @@ var styles3 = import_react_native12.StyleSheet.create({
|
|
|
2221
2670
|
});
|
|
2222
2671
|
|
|
2223
2672
|
// src/ui/display/PageDrawer.tsx
|
|
2224
|
-
var
|
|
2673
|
+
var import_react17 = __toESM(require("react"));
|
|
2225
2674
|
var import_react_native13 = require("react-native");
|
|
2226
2675
|
var import_jsx_runtime19 = require("nativewind/jsx-runtime");
|
|
2227
2676
|
function PageDrawer({
|
|
@@ -2242,13 +2691,12 @@ function PageDrawer({
|
|
|
2242
2691
|
backdropTestID = "page-drawer-backdrop"
|
|
2243
2692
|
}) {
|
|
2244
2693
|
const colors = useThemeColors();
|
|
2245
|
-
const [translateX, setTranslateX] =
|
|
2246
|
-
|
|
2247
|
-
const handleClose = import_react16.default.useCallback(() => {
|
|
2694
|
+
const [translateX, setTranslateX] = import_react17.default.useState(0);
|
|
2695
|
+
const handleClose = import_react17.default.useCallback(() => {
|
|
2248
2696
|
setTranslateX(0);
|
|
2249
2697
|
onClose?.();
|
|
2250
2698
|
}, [onClose]);
|
|
2251
|
-
|
|
2699
|
+
import_react17.default.useEffect(() => {
|
|
2252
2700
|
if (!visible) return;
|
|
2253
2701
|
const subscription = import_react_native13.BackHandler.addEventListener("hardwareBackPress", () => {
|
|
2254
2702
|
handleClose();
|
|
@@ -2256,7 +2704,7 @@ function PageDrawer({
|
|
|
2256
2704
|
});
|
|
2257
2705
|
return () => subscription.remove();
|
|
2258
2706
|
}, [handleClose, visible]);
|
|
2259
|
-
const panResponder =
|
|
2707
|
+
const panResponder = import_react17.default.useMemo(
|
|
2260
2708
|
() => import_react_native13.PanResponder.create({
|
|
2261
2709
|
onMoveShouldSetPanResponder: (_event, gestureState) => {
|
|
2262
2710
|
if (!swipeEnabled) return false;
|
|
@@ -2287,6 +2735,7 @@ function PageDrawer({
|
|
|
2287
2735
|
}),
|
|
2288
2736
|
[handleClose, placement, swipeEnabled, swipeThreshold, width]
|
|
2289
2737
|
);
|
|
2738
|
+
if (!visible) return null;
|
|
2290
2739
|
const drawerContent = /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
2291
2740
|
AppView,
|
|
2292
2741
|
{
|
|
@@ -2383,23 +2832,66 @@ function GradientView({
|
|
|
2383
2832
|
return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_expo_linear_gradient.LinearGradient, { colors: [...colors], start, end, style, ...props, children });
|
|
2384
2833
|
}
|
|
2385
2834
|
|
|
2386
|
-
// src/ui/
|
|
2387
|
-
var import_react17 = require("react");
|
|
2388
|
-
var import_react_native14 = require("react-native");
|
|
2835
|
+
// src/ui/feedback/Loading.tsx
|
|
2389
2836
|
var import_jsx_runtime21 = require("nativewind/jsx-runtime");
|
|
2390
|
-
var
|
|
2837
|
+
var LOADING_CLOSE_DELAY = 3e4;
|
|
2838
|
+
function Loading({
|
|
2839
|
+
text,
|
|
2840
|
+
color,
|
|
2841
|
+
overlay = false,
|
|
2842
|
+
visible = true,
|
|
2843
|
+
testID,
|
|
2844
|
+
onClose
|
|
2845
|
+
}) {
|
|
2846
|
+
const [showCloseButton, setShowCloseButton] = (0, import_react18.useState)(false);
|
|
2847
|
+
(0, import_react18.useEffect)(() => {
|
|
2848
|
+
if (!visible) {
|
|
2849
|
+
setShowCloseButton(false);
|
|
2850
|
+
return;
|
|
2851
|
+
}
|
|
2852
|
+
setShowCloseButton(false);
|
|
2853
|
+
const timer = setTimeout(() => {
|
|
2854
|
+
setShowCloseButton(true);
|
|
2855
|
+
}, LOADING_CLOSE_DELAY);
|
|
2856
|
+
return () => clearTimeout(timer);
|
|
2857
|
+
}, [visible]);
|
|
2858
|
+
if (!visible) return null;
|
|
2859
|
+
const content = /* @__PURE__ */ (0, import_jsx_runtime21.jsxs)(AppView, { center: true, gap: 3, testID, children: [
|
|
2860
|
+
/* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_react_native14.ActivityIndicator, { size: "large", color }),
|
|
2861
|
+
text && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(AppText, { style: color ? { color } : void 0, children: text }),
|
|
2862
|
+
showCloseButton && onClose && /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(
|
|
2863
|
+
AppPressable,
|
|
2864
|
+
{
|
|
2865
|
+
testID: testID ? `${testID}-close` : "loading-close",
|
|
2866
|
+
className: "mt-1 p-1",
|
|
2867
|
+
onPress: onClose,
|
|
2868
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(Icon, { name: "close", size: "md", color: color || "white" })
|
|
2869
|
+
}
|
|
2870
|
+
)
|
|
2871
|
+
] });
|
|
2872
|
+
if (overlay) {
|
|
2873
|
+
return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(AppView, { center: true, flex: true, className: "absolute inset-0 bg-black/30", testID, children: content });
|
|
2874
|
+
}
|
|
2875
|
+
return content;
|
|
2876
|
+
}
|
|
2877
|
+
|
|
2878
|
+
// src/ui/form/AppInput.tsx
|
|
2879
|
+
var import_react19 = require("react");
|
|
2880
|
+
var import_react_native15 = require("react-native");
|
|
2881
|
+
var import_jsx_runtime22 = require("nativewind/jsx-runtime");
|
|
2882
|
+
var AppInput = (0, import_react19.forwardRef)(
|
|
2391
2883
|
({ label, error, disabled = false, leftIcon, rightIcon, className, style, ...props }, ref) => {
|
|
2392
2884
|
const colors = useThemeColors();
|
|
2393
|
-
const [isFocused, setIsFocused] = (0,
|
|
2885
|
+
const [isFocused, setIsFocused] = (0, import_react19.useState)(false);
|
|
2394
2886
|
const errorColor = "#ef4444";
|
|
2395
2887
|
const getBorderColor = () => {
|
|
2396
2888
|
if (error) return errorColor;
|
|
2397
2889
|
if (isFocused) return colors.primary;
|
|
2398
2890
|
return colors.border;
|
|
2399
2891
|
};
|
|
2400
|
-
return /* @__PURE__ */ (0,
|
|
2401
|
-
label && /* @__PURE__ */ (0,
|
|
2402
|
-
/* @__PURE__ */ (0,
|
|
2892
|
+
return /* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(AppView, { className: cn("flex-col gap-1", className), children: [
|
|
2893
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(AppText, { size: "sm", weight: "medium", style: { color: colors.textSecondary }, children: label }),
|
|
2894
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsxs)(
|
|
2403
2895
|
AppView,
|
|
2404
2896
|
{
|
|
2405
2897
|
row: true,
|
|
@@ -2414,9 +2906,9 @@ var AppInput = (0, import_react17.forwardRef)(
|
|
|
2414
2906
|
}
|
|
2415
2907
|
],
|
|
2416
2908
|
children: [
|
|
2417
|
-
leftIcon && /* @__PURE__ */ (0,
|
|
2418
|
-
/* @__PURE__ */ (0,
|
|
2419
|
-
|
|
2909
|
+
leftIcon && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native15.View, { style: styles5.icon, children: leftIcon }),
|
|
2910
|
+
/* @__PURE__ */ (0, import_jsx_runtime22.jsx)(
|
|
2911
|
+
import_react_native15.TextInput,
|
|
2420
2912
|
{
|
|
2421
2913
|
ref,
|
|
2422
2914
|
className: "flex-1 py-3 text-base",
|
|
@@ -2434,18 +2926,18 @@ var AppInput = (0, import_react17.forwardRef)(
|
|
|
2434
2926
|
...props
|
|
2435
2927
|
}
|
|
2436
2928
|
),
|
|
2437
|
-
rightIcon && /* @__PURE__ */ (0,
|
|
2929
|
+
rightIcon && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(import_react_native15.View, { style: styles5.icon, children: rightIcon })
|
|
2438
2930
|
]
|
|
2439
2931
|
}
|
|
2440
2932
|
),
|
|
2441
|
-
error && /* @__PURE__ */ (0,
|
|
2933
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(AppText, { size: "xs", style: { color: errorColor }, children: error })
|
|
2442
2934
|
] });
|
|
2443
2935
|
}
|
|
2444
2936
|
);
|
|
2445
2937
|
AppInput.displayName = "AppInput";
|
|
2446
2938
|
var AppTextInput = AppInput;
|
|
2447
2939
|
AppTextInput.displayName = "AppTextInput";
|
|
2448
|
-
var styles5 =
|
|
2940
|
+
var styles5 = import_react_native15.StyleSheet.create({
|
|
2449
2941
|
inputContainer: {
|
|
2450
2942
|
borderWidth: 0.5,
|
|
2451
2943
|
minHeight: 48
|
|
@@ -2460,9 +2952,9 @@ var styles5 = import_react_native14.StyleSheet.create({
|
|
|
2460
2952
|
});
|
|
2461
2953
|
|
|
2462
2954
|
// src/ui/form/Checkbox.tsx
|
|
2463
|
-
var
|
|
2464
|
-
var
|
|
2465
|
-
var
|
|
2955
|
+
var import_react20 = require("react");
|
|
2956
|
+
var import_react_native16 = require("react-native");
|
|
2957
|
+
var import_jsx_runtime23 = require("nativewind/jsx-runtime");
|
|
2466
2958
|
function Checkbox({
|
|
2467
2959
|
checked,
|
|
2468
2960
|
defaultChecked,
|
|
@@ -2473,7 +2965,7 @@ function Checkbox({
|
|
|
2473
2965
|
testID
|
|
2474
2966
|
}) {
|
|
2475
2967
|
const colors = useThemeColors();
|
|
2476
|
-
const [internalChecked, setInternalChecked] = (0,
|
|
2968
|
+
const [internalChecked, setInternalChecked] = (0, import_react20.useState)(defaultChecked || false);
|
|
2477
2969
|
const isChecked = checked !== void 0 ? checked : internalChecked;
|
|
2478
2970
|
const toggle = () => {
|
|
2479
2971
|
if (disabled) return;
|
|
@@ -2484,8 +2976,8 @@ function Checkbox({
|
|
|
2484
2976
|
onChange?.(newChecked);
|
|
2485
2977
|
};
|
|
2486
2978
|
const disabledOpacity = 0.4;
|
|
2487
|
-
return /* @__PURE__ */ (0,
|
|
2488
|
-
|
|
2979
|
+
return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(
|
|
2980
|
+
import_react_native16.TouchableOpacity,
|
|
2489
2981
|
{
|
|
2490
2982
|
onPress: toggle,
|
|
2491
2983
|
disabled,
|
|
@@ -2494,7 +2986,7 @@ function Checkbox({
|
|
|
2494
2986
|
testID,
|
|
2495
2987
|
activeOpacity: 0.7,
|
|
2496
2988
|
children: [
|
|
2497
|
-
/* @__PURE__ */ (0,
|
|
2989
|
+
/* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
|
|
2498
2990
|
AppView,
|
|
2499
2991
|
{
|
|
2500
2992
|
className: cn(
|
|
@@ -2508,17 +3000,27 @@ function Checkbox({
|
|
|
2508
3000
|
borderColor: isChecked ? colors.primary : colors.border
|
|
2509
3001
|
}
|
|
2510
3002
|
],
|
|
2511
|
-
children: isChecked && /* @__PURE__ */ (0,
|
|
3003
|
+
children: isChecked && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(AppView, { pointerEvents: "none", style: styles6.iconContainer, testID: `${testID}-icon`, children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(Icon, { name: "check", size: 14, color: "white", style: styles6.icon }) })
|
|
2512
3004
|
}
|
|
2513
3005
|
),
|
|
2514
|
-
children && /* @__PURE__ */ (0,
|
|
3006
|
+
children && /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(AppText, { size: "sm", style: { color: colors.text }, children })
|
|
2515
3007
|
]
|
|
2516
3008
|
}
|
|
2517
3009
|
);
|
|
2518
3010
|
}
|
|
2519
|
-
var styles6 =
|
|
3011
|
+
var styles6 = import_react_native16.StyleSheet.create({
|
|
2520
3012
|
checkbox: {
|
|
2521
3013
|
borderWidth: 0.5
|
|
3014
|
+
},
|
|
3015
|
+
iconContainer: {
|
|
3016
|
+
...import_react_native16.StyleSheet.absoluteFillObject,
|
|
3017
|
+
alignItems: "center",
|
|
3018
|
+
justifyContent: "center"
|
|
3019
|
+
},
|
|
3020
|
+
icon: {
|
|
3021
|
+
lineHeight: 14,
|
|
3022
|
+
includeFontPadding: false,
|
|
3023
|
+
textAlignVertical: "center"
|
|
2522
3024
|
}
|
|
2523
3025
|
});
|
|
2524
3026
|
|
|
@@ -2534,7 +3036,7 @@ var isGroupOptionDisabled = (groupDisabled, optionDisabled) => {
|
|
|
2534
3036
|
};
|
|
2535
3037
|
|
|
2536
3038
|
// src/ui/form/CheckboxGroup.tsx
|
|
2537
|
-
var
|
|
3039
|
+
var import_jsx_runtime24 = require("nativewind/jsx-runtime");
|
|
2538
3040
|
function CheckboxGroup({
|
|
2539
3041
|
value = [],
|
|
2540
3042
|
onChange,
|
|
@@ -2547,7 +3049,7 @@ function CheckboxGroup({
|
|
|
2547
3049
|
onChange(toggleGroupValue(value, optionValue, checked));
|
|
2548
3050
|
};
|
|
2549
3051
|
const isRow = direction === "row";
|
|
2550
|
-
return /* @__PURE__ */ (0,
|
|
3052
|
+
return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(AppView, { row: isRow, flex: isRow, gap: 4, children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
|
|
2551
3053
|
Checkbox,
|
|
2552
3054
|
{
|
|
2553
3055
|
checked: value.includes(option.value),
|
|
@@ -2560,9 +3062,9 @@ function CheckboxGroup({
|
|
|
2560
3062
|
}
|
|
2561
3063
|
|
|
2562
3064
|
// src/ui/form/Radio.tsx
|
|
2563
|
-
var
|
|
2564
|
-
var
|
|
2565
|
-
var
|
|
3065
|
+
var import_react21 = require("react");
|
|
3066
|
+
var import_react_native17 = require("react-native");
|
|
3067
|
+
var import_jsx_runtime25 = require("nativewind/jsx-runtime");
|
|
2566
3068
|
function Radio({
|
|
2567
3069
|
checked,
|
|
2568
3070
|
defaultChecked,
|
|
@@ -2573,7 +3075,7 @@ function Radio({
|
|
|
2573
3075
|
testID
|
|
2574
3076
|
}) {
|
|
2575
3077
|
const colors = useThemeColors();
|
|
2576
|
-
const [internalChecked, setInternalChecked] = (0,
|
|
3078
|
+
const [internalChecked, setInternalChecked] = (0, import_react21.useState)(defaultChecked || false);
|
|
2577
3079
|
const isChecked = checked !== void 0 ? checked : internalChecked;
|
|
2578
3080
|
const toggle = () => {
|
|
2579
3081
|
if (disabled) return;
|
|
@@ -2584,8 +3086,8 @@ function Radio({
|
|
|
2584
3086
|
onChange?.(newChecked);
|
|
2585
3087
|
};
|
|
2586
3088
|
const disabledOpacity = 0.4;
|
|
2587
|
-
return /* @__PURE__ */ (0,
|
|
2588
|
-
|
|
3089
|
+
return /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)(
|
|
3090
|
+
import_react_native17.TouchableOpacity,
|
|
2589
3091
|
{
|
|
2590
3092
|
onPress: toggle,
|
|
2591
3093
|
disabled,
|
|
@@ -2594,7 +3096,7 @@ function Radio({
|
|
|
2594
3096
|
testID,
|
|
2595
3097
|
activeOpacity: 0.7,
|
|
2596
3098
|
children: [
|
|
2597
|
-
/* @__PURE__ */ (0,
|
|
3099
|
+
/* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
2598
3100
|
AppView,
|
|
2599
3101
|
{
|
|
2600
3102
|
className: cn("w-5 h-5 rounded-full items-center justify-center", isChecked && "border-2"),
|
|
@@ -2606,7 +3108,7 @@ function Radio({
|
|
|
2606
3108
|
borderWidth: isChecked ? 0.5 : 0.5
|
|
2607
3109
|
}
|
|
2608
3110
|
],
|
|
2609
|
-
children: isChecked && /* @__PURE__ */ (0,
|
|
3111
|
+
children: isChecked && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
|
|
2610
3112
|
AppView,
|
|
2611
3113
|
{
|
|
2612
3114
|
className: "rounded-full",
|
|
@@ -2615,12 +3117,12 @@ function Radio({
|
|
|
2615
3117
|
)
|
|
2616
3118
|
}
|
|
2617
3119
|
),
|
|
2618
|
-
children && /* @__PURE__ */ (0,
|
|
3120
|
+
children && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(AppText, { size: "sm", style: { color: colors.text }, children })
|
|
2619
3121
|
]
|
|
2620
3122
|
}
|
|
2621
3123
|
);
|
|
2622
3124
|
}
|
|
2623
|
-
var styles7 =
|
|
3125
|
+
var styles7 = import_react_native17.StyleSheet.create({
|
|
2624
3126
|
radio: {
|
|
2625
3127
|
borderWidth: 0.5
|
|
2626
3128
|
},
|
|
@@ -2631,7 +3133,7 @@ var styles7 = import_react_native16.StyleSheet.create({
|
|
|
2631
3133
|
});
|
|
2632
3134
|
|
|
2633
3135
|
// src/ui/form/RadioGroup.tsx
|
|
2634
|
-
var
|
|
3136
|
+
var import_jsx_runtime26 = require("nativewind/jsx-runtime");
|
|
2635
3137
|
function RadioGroup({
|
|
2636
3138
|
value,
|
|
2637
3139
|
onChange,
|
|
@@ -2640,7 +3142,7 @@ function RadioGroup({
|
|
|
2640
3142
|
disabled = false
|
|
2641
3143
|
}) {
|
|
2642
3144
|
const isRow = direction === "row";
|
|
2643
|
-
return /* @__PURE__ */ (0,
|
|
3145
|
+
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(AppView, { row: isRow, flex: isRow, gap: 4, children: options.map((option) => /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2644
3146
|
Radio,
|
|
2645
3147
|
{
|
|
2646
3148
|
checked: value === option.value,
|
|
@@ -2653,9 +3155,17 @@ function RadioGroup({
|
|
|
2653
3155
|
}
|
|
2654
3156
|
|
|
2655
3157
|
// src/ui/form/Switch.tsx
|
|
2656
|
-
var
|
|
2657
|
-
var
|
|
2658
|
-
var
|
|
3158
|
+
var import_react22 = require("react");
|
|
3159
|
+
var import_react_native18 = require("react-native");
|
|
3160
|
+
var import_jsx_runtime27 = require("nativewind/jsx-runtime");
|
|
3161
|
+
function createAnimatedValue2(value) {
|
|
3162
|
+
const AnimatedValue = import_react_native18.Animated.Value;
|
|
3163
|
+
try {
|
|
3164
|
+
return new AnimatedValue(value);
|
|
3165
|
+
} catch {
|
|
3166
|
+
return AnimatedValue(value);
|
|
3167
|
+
}
|
|
3168
|
+
}
|
|
2659
3169
|
function Switch({
|
|
2660
3170
|
checked,
|
|
2661
3171
|
defaultChecked,
|
|
@@ -2667,35 +3177,79 @@ function Switch({
|
|
|
2667
3177
|
style
|
|
2668
3178
|
}) {
|
|
2669
3179
|
const colors = useThemeColors();
|
|
2670
|
-
const [internalChecked, setInternalChecked] = (0,
|
|
3180
|
+
const [internalChecked, setInternalChecked] = (0, import_react22.useState)(defaultChecked || false);
|
|
3181
|
+
const [isInteractionLocked, setIsInteractionLocked] = (0, import_react22.useState)(false);
|
|
3182
|
+
const isFirstRender = (0, import_react22.useRef)(true);
|
|
3183
|
+
const unlockTimerRef = (0, import_react22.useRef)(null);
|
|
2671
3184
|
const isChecked = checked !== void 0 ? checked : internalChecked;
|
|
3185
|
+
const sizes = {
|
|
3186
|
+
sm: { width: 36, height: 20, thumb: 16, padding: 2 },
|
|
3187
|
+
md: { width: 48, height: 26, thumb: 22, padding: 2 },
|
|
3188
|
+
lg: { width: 60, height: 32, thumb: 28, padding: 2 }
|
|
3189
|
+
};
|
|
3190
|
+
const config = sizes[size];
|
|
3191
|
+
const maxTranslateX = config.width - config.thumb - config.padding * 2;
|
|
3192
|
+
const thumbTranslateX = (0, import_react22.useRef)(createAnimatedValue2(isChecked ? maxTranslateX : 0)).current;
|
|
3193
|
+
const clearUnlockTimer = () => {
|
|
3194
|
+
if (!unlockTimerRef.current) return;
|
|
3195
|
+
clearTimeout(unlockTimerRef.current);
|
|
3196
|
+
unlockTimerRef.current = null;
|
|
3197
|
+
};
|
|
3198
|
+
const animateThumb = (nextChecked, shouldUnlock = true) => {
|
|
3199
|
+
import_react_native18.Animated.timing(thumbTranslateX, {
|
|
3200
|
+
toValue: nextChecked ? maxTranslateX : 0,
|
|
3201
|
+
duration: 180,
|
|
3202
|
+
useNativeDriver: true
|
|
3203
|
+
}).start((result) => {
|
|
3204
|
+
if (result?.finished ?? true) {
|
|
3205
|
+
thumbTranslateX.setValue(nextChecked ? maxTranslateX : 0);
|
|
3206
|
+
}
|
|
3207
|
+
if (shouldUnlock) {
|
|
3208
|
+
clearUnlockTimer();
|
|
3209
|
+
setIsInteractionLocked(false);
|
|
3210
|
+
}
|
|
3211
|
+
});
|
|
3212
|
+
};
|
|
3213
|
+
(0, import_react22.useEffect)(() => {
|
|
3214
|
+
if (isFirstRender.current) {
|
|
3215
|
+
thumbTranslateX.setValue(isChecked ? maxTranslateX : 0);
|
|
3216
|
+
isFirstRender.current = false;
|
|
3217
|
+
return;
|
|
3218
|
+
}
|
|
3219
|
+
animateThumb(isChecked);
|
|
3220
|
+
}, [isChecked, maxTranslateX, thumbTranslateX]);
|
|
3221
|
+
(0, import_react22.useEffect)(() => {
|
|
3222
|
+
return () => {
|
|
3223
|
+
clearUnlockTimer();
|
|
3224
|
+
};
|
|
3225
|
+
}, []);
|
|
2672
3226
|
const toggle = () => {
|
|
2673
|
-
if (disabled) return;
|
|
3227
|
+
if (disabled || isInteractionLocked) return;
|
|
2674
3228
|
const newChecked = !isChecked;
|
|
3229
|
+
setIsInteractionLocked(true);
|
|
2675
3230
|
if (checked === void 0) {
|
|
2676
3231
|
setInternalChecked(newChecked);
|
|
3232
|
+
} else {
|
|
3233
|
+
animateThumb(newChecked, false);
|
|
3234
|
+
unlockTimerRef.current = setTimeout(() => {
|
|
3235
|
+
unlockTimerRef.current = null;
|
|
3236
|
+
setIsInteractionLocked(false);
|
|
3237
|
+
}, 220);
|
|
2677
3238
|
}
|
|
2678
3239
|
onChange?.(newChecked);
|
|
2679
3240
|
};
|
|
2680
|
-
const
|
|
2681
|
-
const
|
|
2682
|
-
const
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
md: { width: 48, height: 26, thumb: 22, padding: 2 },
|
|
2686
|
-
lg: { width: 60, height: 32, thumb: 28, padding: 2 }
|
|
2687
|
-
};
|
|
2688
|
-
const config = sizes[size];
|
|
2689
|
-
const thumbPosition = isChecked ? config.width - config.thumb - config.padding : config.padding;
|
|
2690
|
-
return /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
|
|
2691
|
-
import_react_native17.TouchableOpacity,
|
|
3241
|
+
const trackBackgroundColor = disabled ? isChecked ? colors.primarySurface : colors.divider : isChecked ? colors.primary : colors.divider;
|
|
3242
|
+
const trackBorderColor = disabled ? isChecked ? colors.primarySurface : colors.border : isChecked ? colors.primary : colors.border;
|
|
3243
|
+
const thumbBackgroundColor = disabled ? colors.card : colors.textInverse;
|
|
3244
|
+
return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3245
|
+
import_react_native18.TouchableOpacity,
|
|
2692
3246
|
{
|
|
2693
3247
|
onPress: toggle,
|
|
2694
|
-
disabled,
|
|
3248
|
+
disabled: disabled || isInteractionLocked,
|
|
2695
3249
|
className: cn(className),
|
|
2696
3250
|
testID,
|
|
2697
|
-
activeOpacity: disabled ? 1 : 0.8,
|
|
2698
|
-
children: /* @__PURE__ */ (0,
|
|
3251
|
+
activeOpacity: disabled || isInteractionLocked ? 1 : 0.8,
|
|
3252
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
2699
3253
|
AppView,
|
|
2700
3254
|
{
|
|
2701
3255
|
className: "rounded-full",
|
|
@@ -2704,22 +3258,22 @@ function Switch({
|
|
|
2704
3258
|
{
|
|
2705
3259
|
width: config.width,
|
|
2706
3260
|
height: config.height,
|
|
2707
|
-
backgroundColor:
|
|
2708
|
-
|
|
3261
|
+
backgroundColor: trackBackgroundColor,
|
|
3262
|
+
borderColor: trackBorderColor
|
|
2709
3263
|
},
|
|
2710
3264
|
style
|
|
2711
3265
|
],
|
|
2712
|
-
children: /* @__PURE__ */ (0,
|
|
2713
|
-
|
|
3266
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
|
|
3267
|
+
import_react_native18.Animated.View,
|
|
2714
3268
|
{
|
|
2715
|
-
className: "rounded-full",
|
|
2716
3269
|
style: [
|
|
2717
3270
|
styles8.thumb,
|
|
2718
3271
|
{
|
|
2719
3272
|
width: config.thumb,
|
|
2720
3273
|
height: config.thumb,
|
|
2721
|
-
|
|
2722
|
-
|
|
3274
|
+
borderRadius: config.thumb / 2,
|
|
3275
|
+
backgroundColor: thumbBackgroundColor,
|
|
3276
|
+
transform: [{ translateX: thumbTranslateX }],
|
|
2723
3277
|
shadowColor: "#000000",
|
|
2724
3278
|
shadowOffset: { width: 0, height: 1 },
|
|
2725
3279
|
shadowOpacity: 0.25,
|
|
@@ -2733,10 +3287,11 @@ function Switch({
|
|
|
2733
3287
|
}
|
|
2734
3288
|
);
|
|
2735
3289
|
}
|
|
2736
|
-
var styles8 =
|
|
3290
|
+
var styles8 = import_react_native18.StyleSheet.create({
|
|
2737
3291
|
track: {
|
|
2738
3292
|
justifyContent: "center",
|
|
2739
|
-
padding: 2
|
|
3293
|
+
padding: 2,
|
|
3294
|
+
borderWidth: 0.5
|
|
2740
3295
|
},
|
|
2741
3296
|
thumb: {
|
|
2742
3297
|
elevation: 2,
|
|
@@ -2748,15 +3303,15 @@ var styles8 = import_react_native17.StyleSheet.create({
|
|
|
2748
3303
|
});
|
|
2749
3304
|
|
|
2750
3305
|
// src/ui/form/Slider.tsx
|
|
2751
|
-
var
|
|
2752
|
-
var
|
|
3306
|
+
var import_react24 = require("react");
|
|
3307
|
+
var import_react_native19 = require("react-native");
|
|
2753
3308
|
|
|
2754
3309
|
// src/ui/form/useFormTheme.ts
|
|
2755
|
-
var
|
|
3310
|
+
var import_react23 = require("react");
|
|
2756
3311
|
function useFormThemeColors() {
|
|
2757
3312
|
const { isDark } = useOptionalTheme();
|
|
2758
3313
|
const colors = useThemeColors();
|
|
2759
|
-
return (0,
|
|
3314
|
+
return (0, import_react23.useMemo)(
|
|
2760
3315
|
() => ({
|
|
2761
3316
|
primary: colors.primary,
|
|
2762
3317
|
primarySurface: colors.primarySurface,
|
|
@@ -2777,7 +3332,7 @@ function useFormThemeColors() {
|
|
|
2777
3332
|
}
|
|
2778
3333
|
|
|
2779
3334
|
// src/ui/form/Slider.tsx
|
|
2780
|
-
var
|
|
3335
|
+
var import_jsx_runtime28 = require("nativewind/jsx-runtime");
|
|
2781
3336
|
function Slider({
|
|
2782
3337
|
value,
|
|
2783
3338
|
defaultValue = 0,
|
|
@@ -2791,53 +3346,82 @@ function Slider({
|
|
|
2791
3346
|
className
|
|
2792
3347
|
}) {
|
|
2793
3348
|
const colors = useFormThemeColors();
|
|
2794
|
-
const [internalValue, setInternalValue] = (0,
|
|
2795
|
-
const [
|
|
2796
|
-
const
|
|
3349
|
+
const [internalValue, setInternalValue] = (0, import_react24.useState)(defaultValue);
|
|
3350
|
+
const [isDragging, setIsDragging] = (0, import_react24.useState)(false);
|
|
3351
|
+
const trackWidthRef = (0, import_react24.useRef)(0);
|
|
3352
|
+
const currentValueRef = (0, import_react24.useRef)(value ?? defaultValue);
|
|
3353
|
+
const dragStartValueRef = (0, import_react24.useRef)(value ?? defaultValue);
|
|
2797
3354
|
const currentValue = value !== void 0 ? value : internalValue;
|
|
3355
|
+
const range = max - min;
|
|
2798
3356
|
const disabledOpacity = 0.4;
|
|
2799
|
-
const progress = (currentValue - min) /
|
|
2800
|
-
|
|
3357
|
+
const progress = range <= 0 ? 0 : (currentValue - min) / range * 100;
|
|
3358
|
+
(0, import_react24.useEffect)(() => {
|
|
3359
|
+
currentValueRef.current = currentValue;
|
|
3360
|
+
}, [currentValue]);
|
|
3361
|
+
const clampValue = (0, import_react24.useCallback)(
|
|
3362
|
+
(nextValue) => {
|
|
3363
|
+
if (!Number.isFinite(nextValue)) return currentValueRef.current;
|
|
3364
|
+
return Math.min(max, Math.max(min, nextValue));
|
|
3365
|
+
},
|
|
3366
|
+
[max, min]
|
|
3367
|
+
);
|
|
3368
|
+
const valueToPosition = (0, import_react24.useCallback)(
|
|
3369
|
+
(nextValue) => {
|
|
3370
|
+
if (trackWidthRef.current <= 0 || range <= 0) return 0;
|
|
3371
|
+
return (clampValue(nextValue) - min) / range * trackWidthRef.current;
|
|
3372
|
+
},
|
|
3373
|
+
[clampValue, min, range]
|
|
3374
|
+
);
|
|
3375
|
+
const getValueFromPosition = (0, import_react24.useCallback)(
|
|
2801
3376
|
(position) => {
|
|
2802
|
-
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
3377
|
+
if (trackWidthRef.current <= 0 || range <= 0 || !Number.isFinite(position)) {
|
|
3378
|
+
return clampValue(currentValueRef.current);
|
|
3379
|
+
}
|
|
3380
|
+
const percentage = Math.max(0, Math.min(1, position / trackWidthRef.current));
|
|
3381
|
+
const rawValue = min + percentage * range;
|
|
3382
|
+
const steppedValue = step > 0 ? Math.round((rawValue - min) / step) * step + min : rawValue;
|
|
3383
|
+
return clampValue(steppedValue);
|
|
2806
3384
|
},
|
|
2807
|
-
[
|
|
3385
|
+
[clampValue, min, range, step]
|
|
2808
3386
|
);
|
|
2809
|
-
const setValue = (0,
|
|
3387
|
+
const setValue = (0, import_react24.useCallback)(
|
|
2810
3388
|
(newValue) => {
|
|
2811
|
-
const clampedValue =
|
|
3389
|
+
const clampedValue = clampValue(newValue);
|
|
2812
3390
|
if (value === void 0) {
|
|
2813
3391
|
setInternalValue(clampedValue);
|
|
2814
3392
|
}
|
|
3393
|
+
currentValueRef.current = clampedValue;
|
|
2815
3394
|
onChange?.(clampedValue);
|
|
2816
3395
|
},
|
|
2817
|
-
[
|
|
3396
|
+
[clampValue, onChange, value]
|
|
2818
3397
|
);
|
|
2819
|
-
const panResponder = (0,
|
|
2820
|
-
|
|
3398
|
+
const panResponder = (0, import_react24.useMemo)(
|
|
3399
|
+
() => import_react_native19.PanResponder.create({
|
|
2821
3400
|
onStartShouldSetPanResponder: () => !disabled,
|
|
2822
3401
|
onMoveShouldSetPanResponder: () => !disabled,
|
|
2823
3402
|
onPanResponderGrant: () => {
|
|
3403
|
+
dragStartValueRef.current = currentValueRef.current;
|
|
2824
3404
|
setIsDragging(true);
|
|
2825
3405
|
},
|
|
2826
3406
|
onPanResponderMove: (_, gestureState) => {
|
|
2827
|
-
const position =
|
|
3407
|
+
const position = valueToPosition(dragStartValueRef.current) + gestureState.dx;
|
|
2828
3408
|
const newValue = getValueFromPosition(position);
|
|
2829
3409
|
setValue(newValue);
|
|
2830
3410
|
},
|
|
2831
3411
|
onPanResponderRelease: (_, gestureState) => {
|
|
2832
|
-
const position =
|
|
3412
|
+
const position = valueToPosition(dragStartValueRef.current) + gestureState.dx;
|
|
2833
3413
|
const newValue = getValueFromPosition(position);
|
|
2834
3414
|
setValue(newValue);
|
|
2835
3415
|
setIsDragging(false);
|
|
2836
3416
|
onChangeEnd?.(newValue);
|
|
3417
|
+
},
|
|
3418
|
+
onPanResponderTerminate: () => {
|
|
3419
|
+
setIsDragging(false);
|
|
2837
3420
|
}
|
|
2838
|
-
})
|
|
2839
|
-
|
|
2840
|
-
|
|
3421
|
+
}),
|
|
3422
|
+
[disabled, getValueFromPosition, onChangeEnd, setValue, valueToPosition]
|
|
3423
|
+
);
|
|
3424
|
+
const handleTrackPress = (0, import_react24.useCallback)(
|
|
2841
3425
|
(event) => {
|
|
2842
3426
|
if (disabled) return;
|
|
2843
3427
|
const { locationX } = event.nativeEvent;
|
|
@@ -2847,11 +3431,12 @@ function Slider({
|
|
|
2847
3431
|
},
|
|
2848
3432
|
[disabled, getValueFromPosition, setValue, onChangeEnd]
|
|
2849
3433
|
);
|
|
2850
|
-
const onLayout = (0,
|
|
2851
|
-
|
|
3434
|
+
const onLayout = (0, import_react24.useCallback)((event) => {
|
|
3435
|
+
const width = event.nativeEvent.layout.width;
|
|
3436
|
+
trackWidthRef.current = width;
|
|
2852
3437
|
}, []);
|
|
2853
|
-
return /* @__PURE__ */ (0,
|
|
2854
|
-
showTooltip && isDragging && /* @__PURE__ */ (0,
|
|
3438
|
+
return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(AppView, { className: cn("py-2", className), children: [
|
|
3439
|
+
showTooltip && isDragging && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
2855
3440
|
AppView,
|
|
2856
3441
|
{
|
|
2857
3442
|
className: "absolute rounded px-2 py-1 -top-8",
|
|
@@ -2864,8 +3449,8 @@ function Slider({
|
|
|
2864
3449
|
}
|
|
2865
3450
|
],
|
|
2866
3451
|
children: [
|
|
2867
|
-
/* @__PURE__ */ (0,
|
|
2868
|
-
/* @__PURE__ */ (0,
|
|
3452
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(AppText, { size: "xs", style: { color: colors.text }, children: Math.round(currentValue) }),
|
|
3453
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2869
3454
|
AppView,
|
|
2870
3455
|
{
|
|
2871
3456
|
style: [
|
|
@@ -2879,8 +3464,8 @@ function Slider({
|
|
|
2879
3464
|
]
|
|
2880
3465
|
}
|
|
2881
3466
|
),
|
|
2882
|
-
/* @__PURE__ */ (0,
|
|
2883
|
-
|
|
3467
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
3468
|
+
import_react_native19.View,
|
|
2884
3469
|
{
|
|
2885
3470
|
onLayout,
|
|
2886
3471
|
className: "rounded-full",
|
|
@@ -2890,7 +3475,7 @@ function Slider({
|
|
|
2890
3475
|
],
|
|
2891
3476
|
onTouchEnd: handleTrackPress,
|
|
2892
3477
|
children: [
|
|
2893
|
-
/* @__PURE__ */ (0,
|
|
3478
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2894
3479
|
AppView,
|
|
2895
3480
|
{
|
|
2896
3481
|
className: "rounded-full",
|
|
@@ -2903,7 +3488,7 @@ function Slider({
|
|
|
2903
3488
|
]
|
|
2904
3489
|
}
|
|
2905
3490
|
),
|
|
2906
|
-
/* @__PURE__ */ (0,
|
|
3491
|
+
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2907
3492
|
AppView,
|
|
2908
3493
|
{
|
|
2909
3494
|
className: "absolute rounded-full items-center justify-center",
|
|
@@ -2920,7 +3505,7 @@ function Slider({
|
|
|
2920
3505
|
}
|
|
2921
3506
|
],
|
|
2922
3507
|
...panResponder.panHandlers,
|
|
2923
|
-
children: /* @__PURE__ */ (0,
|
|
3508
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
2924
3509
|
AppView,
|
|
2925
3510
|
{
|
|
2926
3511
|
className: "rounded-full",
|
|
@@ -2939,7 +3524,7 @@ function Slider({
|
|
|
2939
3524
|
)
|
|
2940
3525
|
] });
|
|
2941
3526
|
}
|
|
2942
|
-
var styles9 =
|
|
3527
|
+
var styles9 = import_react_native19.StyleSheet.create({
|
|
2943
3528
|
track: {
|
|
2944
3529
|
height: 6,
|
|
2945
3530
|
width: "100%"
|
|
@@ -2980,9 +3565,204 @@ var styles9 = import_react_native18.StyleSheet.create({
|
|
|
2980
3565
|
});
|
|
2981
3566
|
|
|
2982
3567
|
// src/ui/form/Select.tsx
|
|
2983
|
-
var
|
|
2984
|
-
var
|
|
2985
|
-
|
|
3568
|
+
var import_react26 = require("react");
|
|
3569
|
+
var import_react_native21 = require("react-native");
|
|
3570
|
+
|
|
3571
|
+
// src/ui/form/BottomSheetModal.tsx
|
|
3572
|
+
var import_react25 = require("react");
|
|
3573
|
+
var import_react_native20 = require("react-native");
|
|
3574
|
+
var import_jsx_runtime29 = require("nativewind/jsx-runtime");
|
|
3575
|
+
var SHEET_OPEN_DURATION = 220;
|
|
3576
|
+
var SHEET_CLOSE_DURATION = 180;
|
|
3577
|
+
var OVERLAY_OPEN_DURATION = 180;
|
|
3578
|
+
var OVERLAY_CLOSE_DURATION = 160;
|
|
3579
|
+
var SHEET_INITIAL_OFFSET = 24;
|
|
3580
|
+
var SHEET_CLOSED_OFFSET = 240;
|
|
3581
|
+
var SHEET_DRAG_CLOSE_THRESHOLD = 72;
|
|
3582
|
+
var SHEET_DRAG_VELOCITY_THRESHOLD = 1;
|
|
3583
|
+
function createAnimatedValue3(value) {
|
|
3584
|
+
const AnimatedValue = import_react_native20.Animated.Value;
|
|
3585
|
+
try {
|
|
3586
|
+
return new AnimatedValue(value);
|
|
3587
|
+
} catch {
|
|
3588
|
+
return AnimatedValue(value);
|
|
3589
|
+
}
|
|
3590
|
+
}
|
|
3591
|
+
function startAnimations(animations, onComplete) {
|
|
3592
|
+
if (animations.length === 0) {
|
|
3593
|
+
onComplete?.();
|
|
3594
|
+
return;
|
|
3595
|
+
}
|
|
3596
|
+
let completed = 0;
|
|
3597
|
+
animations.forEach((animation) => {
|
|
3598
|
+
animation.start(() => {
|
|
3599
|
+
completed += 1;
|
|
3600
|
+
if (completed >= animations.length) {
|
|
3601
|
+
onComplete?.();
|
|
3602
|
+
}
|
|
3603
|
+
});
|
|
3604
|
+
});
|
|
3605
|
+
}
|
|
3606
|
+
function BottomSheetModal({
|
|
3607
|
+
visible,
|
|
3608
|
+
onRequestClose,
|
|
3609
|
+
overlayColor,
|
|
3610
|
+
surfaceColor,
|
|
3611
|
+
children,
|
|
3612
|
+
closeOnBackdropPress = false,
|
|
3613
|
+
maxHeight = "70%",
|
|
3614
|
+
showHandle = true,
|
|
3615
|
+
contentClassName,
|
|
3616
|
+
contentStyle,
|
|
3617
|
+
swipeToClose = true,
|
|
3618
|
+
backdropTestID = "bottom-sheet-backdrop",
|
|
3619
|
+
handleTestID = "bottom-sheet-handle"
|
|
3620
|
+
}) {
|
|
3621
|
+
const [renderVisible, setRenderVisible] = (0, import_react25.useState)(visible);
|
|
3622
|
+
const overlayOpacity = (0, import_react25.useRef)(createAnimatedValue3(0)).current;
|
|
3623
|
+
const sheetTranslateY = (0, import_react25.useRef)(createAnimatedValue3(SHEET_INITIAL_OFFSET)).current;
|
|
3624
|
+
const isDraggingRef = (0, import_react25.useRef)(false);
|
|
3625
|
+
const handlePanResponder = (0, import_react25.useMemo)(
|
|
3626
|
+
() => import_react_native20.PanResponder.create({
|
|
3627
|
+
onMoveShouldSetPanResponder: (_event, gestureState) => {
|
|
3628
|
+
if (!visible || !swipeToClose) return false;
|
|
3629
|
+
const isVertical = Math.abs(gestureState.dy) > Math.abs(gestureState.dx);
|
|
3630
|
+
return isVertical && gestureState.dy > 6;
|
|
3631
|
+
},
|
|
3632
|
+
onPanResponderGrant: () => {
|
|
3633
|
+
isDraggingRef.current = true;
|
|
3634
|
+
},
|
|
3635
|
+
onPanResponderMove: (_event, gestureState) => {
|
|
3636
|
+
if (!visible || !swipeToClose) return;
|
|
3637
|
+
sheetTranslateY.setValue(Math.max(0, Math.min(SHEET_CLOSED_OFFSET, gestureState.dy)));
|
|
3638
|
+
},
|
|
3639
|
+
onPanResponderRelease: (_event, gestureState) => {
|
|
3640
|
+
isDraggingRef.current = false;
|
|
3641
|
+
if (!visible || !swipeToClose) {
|
|
3642
|
+
sheetTranslateY.setValue(0);
|
|
3643
|
+
return;
|
|
3644
|
+
}
|
|
3645
|
+
const shouldClose = gestureState.dy >= SHEET_DRAG_CLOSE_THRESHOLD || gestureState.vy >= SHEET_DRAG_VELOCITY_THRESHOLD;
|
|
3646
|
+
if (shouldClose) {
|
|
3647
|
+
onRequestClose();
|
|
3648
|
+
return;
|
|
3649
|
+
}
|
|
3650
|
+
import_react_native20.Animated.timing(sheetTranslateY, {
|
|
3651
|
+
toValue: 0,
|
|
3652
|
+
duration: SHEET_OPEN_DURATION,
|
|
3653
|
+
useNativeDriver: true
|
|
3654
|
+
}).start();
|
|
3655
|
+
},
|
|
3656
|
+
onPanResponderTerminate: () => {
|
|
3657
|
+
isDraggingRef.current = false;
|
|
3658
|
+
import_react_native20.Animated.timing(sheetTranslateY, {
|
|
3659
|
+
toValue: 0,
|
|
3660
|
+
duration: SHEET_OPEN_DURATION,
|
|
3661
|
+
useNativeDriver: true
|
|
3662
|
+
}).start();
|
|
3663
|
+
}
|
|
3664
|
+
}),
|
|
3665
|
+
[onRequestClose, sheetTranslateY, swipeToClose, visible]
|
|
3666
|
+
);
|
|
3667
|
+
(0, import_react25.useEffect)(() => {
|
|
3668
|
+
if (visible) {
|
|
3669
|
+
setRenderVisible(true);
|
|
3670
|
+
overlayOpacity.setValue(0);
|
|
3671
|
+
sheetTranslateY.setValue(SHEET_INITIAL_OFFSET);
|
|
3672
|
+
startAnimations([
|
|
3673
|
+
import_react_native20.Animated.timing(overlayOpacity, {
|
|
3674
|
+
toValue: 1,
|
|
3675
|
+
duration: OVERLAY_OPEN_DURATION,
|
|
3676
|
+
useNativeDriver: true
|
|
3677
|
+
}),
|
|
3678
|
+
import_react_native20.Animated.timing(sheetTranslateY, {
|
|
3679
|
+
toValue: 0,
|
|
3680
|
+
duration: SHEET_OPEN_DURATION,
|
|
3681
|
+
useNativeDriver: true
|
|
3682
|
+
})
|
|
3683
|
+
]);
|
|
3684
|
+
return;
|
|
3685
|
+
}
|
|
3686
|
+
if (!renderVisible) return;
|
|
3687
|
+
isDraggingRef.current = false;
|
|
3688
|
+
startAnimations(
|
|
3689
|
+
[
|
|
3690
|
+
import_react_native20.Animated.timing(overlayOpacity, {
|
|
3691
|
+
toValue: 0,
|
|
3692
|
+
duration: OVERLAY_CLOSE_DURATION,
|
|
3693
|
+
useNativeDriver: true
|
|
3694
|
+
}),
|
|
3695
|
+
import_react_native20.Animated.timing(sheetTranslateY, {
|
|
3696
|
+
toValue: SHEET_CLOSED_OFFSET,
|
|
3697
|
+
duration: SHEET_CLOSE_DURATION,
|
|
3698
|
+
useNativeDriver: true
|
|
3699
|
+
})
|
|
3700
|
+
],
|
|
3701
|
+
() => {
|
|
3702
|
+
setRenderVisible(false);
|
|
3703
|
+
}
|
|
3704
|
+
);
|
|
3705
|
+
}, [overlayOpacity, renderVisible, sheetTranslateY, visible]);
|
|
3706
|
+
return /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(import_react_native20.Modal, { visible: renderVisible, transparent: true, animationType: "none", onRequestClose, children: /* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(AppView, { flex: true, justify: "end", children: [
|
|
3707
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3708
|
+
import_react_native20.Animated.View,
|
|
3709
|
+
{
|
|
3710
|
+
pointerEvents: "none",
|
|
3711
|
+
style: [import_react_native20.StyleSheet.absoluteFillObject, { backgroundColor: overlayColor, opacity: overlayOpacity }]
|
|
3712
|
+
}
|
|
3713
|
+
),
|
|
3714
|
+
closeOnBackdropPress && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(AppPressable, { testID: backdropTestID, className: "flex-1", onPress: onRequestClose }),
|
|
3715
|
+
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
3716
|
+
import_react_native20.Animated.View,
|
|
3717
|
+
{
|
|
3718
|
+
className: contentClassName,
|
|
3719
|
+
style: [
|
|
3720
|
+
styles10.sheet,
|
|
3721
|
+
{
|
|
3722
|
+
backgroundColor: surfaceColor,
|
|
3723
|
+
maxHeight,
|
|
3724
|
+
transform: [{ translateY: sheetTranslateY }]
|
|
3725
|
+
},
|
|
3726
|
+
contentStyle
|
|
3727
|
+
],
|
|
3728
|
+
children: [
|
|
3729
|
+
showHandle && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3730
|
+
AppView,
|
|
3731
|
+
{
|
|
3732
|
+
testID: handleTestID,
|
|
3733
|
+
center: true,
|
|
3734
|
+
className: "pt-2 pb-1",
|
|
3735
|
+
...swipeToClose ? handlePanResponder.panHandlers : void 0,
|
|
3736
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(AppView, { style: styles10.handle })
|
|
3737
|
+
}
|
|
3738
|
+
),
|
|
3739
|
+
children
|
|
3740
|
+
]
|
|
3741
|
+
}
|
|
3742
|
+
)
|
|
3743
|
+
] }) });
|
|
3744
|
+
}
|
|
3745
|
+
var styles10 = import_react_native20.StyleSheet.create({
|
|
3746
|
+
handle: {
|
|
3747
|
+
width: 36,
|
|
3748
|
+
height: 4,
|
|
3749
|
+
borderRadius: 999,
|
|
3750
|
+
backgroundColor: "rgba(156,163,175,0.7)"
|
|
3751
|
+
},
|
|
3752
|
+
sheet: {
|
|
3753
|
+
borderTopLeftRadius: 24,
|
|
3754
|
+
borderTopRightRadius: 24,
|
|
3755
|
+
overflow: "hidden",
|
|
3756
|
+
shadowColor: "#000000",
|
|
3757
|
+
shadowOffset: { width: 0, height: -4 },
|
|
3758
|
+
shadowOpacity: 0.12,
|
|
3759
|
+
shadowRadius: 16,
|
|
3760
|
+
elevation: 12
|
|
3761
|
+
}
|
|
3762
|
+
});
|
|
3763
|
+
|
|
3764
|
+
// src/ui/form/Select.tsx
|
|
3765
|
+
var import_jsx_runtime30 = require("nativewind/jsx-runtime");
|
|
2986
3766
|
function formatSelectedCountText(template, count) {
|
|
2987
3767
|
return template.replace("{{count}}", String(count));
|
|
2988
3768
|
}
|
|
@@ -3005,24 +3785,24 @@ function Select({
|
|
|
3005
3785
|
className
|
|
3006
3786
|
}) {
|
|
3007
3787
|
const colors = useFormThemeColors();
|
|
3008
|
-
const [visible, setVisible] = (0,
|
|
3009
|
-
const [searchKeyword, setSearchKeyword] = (0,
|
|
3010
|
-
const selectedValues = (0,
|
|
3788
|
+
const [visible, setVisible] = (0, import_react26.useState)(false);
|
|
3789
|
+
const [searchKeyword, setSearchKeyword] = (0, import_react26.useState)("");
|
|
3790
|
+
const selectedValues = (0, import_react26.useMemo)(() => {
|
|
3011
3791
|
if (multiple) {
|
|
3012
3792
|
return Array.isArray(value) ? value : [];
|
|
3013
3793
|
}
|
|
3014
3794
|
return value ? [value] : [];
|
|
3015
3795
|
}, [value, multiple]);
|
|
3016
|
-
const displayText = (0,
|
|
3796
|
+
const displayText = (0, import_react26.useMemo)(() => {
|
|
3017
3797
|
if (selectedValues.length === 0) return placeholder;
|
|
3018
3798
|
const selectedLabels = options.filter((opt) => selectedValues.includes(opt.value)).map((opt) => opt.label);
|
|
3019
3799
|
return selectedLabels.join(", ") || placeholder;
|
|
3020
3800
|
}, [selectedValues, options, placeholder]);
|
|
3021
|
-
const filteredOptions = (0,
|
|
3801
|
+
const filteredOptions = (0, import_react26.useMemo)(() => {
|
|
3022
3802
|
if (!searchable || !searchKeyword) return options;
|
|
3023
3803
|
return options.filter((opt) => opt.label.toLowerCase().includes(searchKeyword.toLowerCase()));
|
|
3024
3804
|
}, [options, searchable, searchKeyword]);
|
|
3025
|
-
const handleSelect = (0,
|
|
3805
|
+
const handleSelect = (0, import_react26.useCallback)(
|
|
3026
3806
|
(optionValue) => {
|
|
3027
3807
|
if (multiple) {
|
|
3028
3808
|
const currentValues = Array.isArray(value) ? value : [];
|
|
@@ -3033,26 +3813,26 @@ function Select({
|
|
|
3033
3813
|
setVisible(false);
|
|
3034
3814
|
}
|
|
3035
3815
|
},
|
|
3036
|
-
[multiple,
|
|
3816
|
+
[multiple, onChange, value]
|
|
3037
3817
|
);
|
|
3038
|
-
const handleClear = (0,
|
|
3818
|
+
const handleClear = (0, import_react26.useCallback)(
|
|
3039
3819
|
(e) => {
|
|
3040
3820
|
e.stopPropagation();
|
|
3041
3821
|
onChange?.(multiple ? [] : "");
|
|
3042
3822
|
},
|
|
3043
3823
|
[multiple, onChange]
|
|
3044
3824
|
);
|
|
3045
|
-
const handleSearch = (0,
|
|
3825
|
+
const handleSearch = (0, import_react26.useCallback)(
|
|
3046
3826
|
(text) => {
|
|
3047
3827
|
setSearchKeyword(text);
|
|
3048
3828
|
onSearch?.(text);
|
|
3049
3829
|
},
|
|
3050
3830
|
[onSearch]
|
|
3051
3831
|
);
|
|
3052
|
-
const renderOption = (0,
|
|
3832
|
+
const renderOption = (0, import_react26.useCallback)(
|
|
3053
3833
|
({ item }) => {
|
|
3054
3834
|
const isSelected = selectedValues.includes(item.value);
|
|
3055
|
-
return /* @__PURE__ */ (0,
|
|
3835
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
3056
3836
|
AppPressable,
|
|
3057
3837
|
{
|
|
3058
3838
|
className: cn(
|
|
@@ -3060,22 +3840,22 @@ function Select({
|
|
|
3060
3840
|
isSelected && "bg-primary-50"
|
|
3061
3841
|
),
|
|
3062
3842
|
style: [
|
|
3063
|
-
|
|
3843
|
+
styles11.optionItem,
|
|
3064
3844
|
{ borderBottomColor: colors.divider },
|
|
3065
3845
|
isSelected && { backgroundColor: colors.primarySurface }
|
|
3066
3846
|
],
|
|
3067
3847
|
onPress: () => handleSelect(item.value),
|
|
3068
3848
|
children: [
|
|
3069
|
-
/* @__PURE__ */ (0,
|
|
3070
|
-
isSelected && /* @__PURE__ */ (0,
|
|
3849
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(AppText, { style: { color: isSelected ? colors.primary : colors.text }, children: item.label }),
|
|
3850
|
+
isSelected && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Icon, { name: "check", size: "sm", color: "primary-500" })
|
|
3071
3851
|
]
|
|
3072
3852
|
}
|
|
3073
3853
|
);
|
|
3074
3854
|
},
|
|
3075
3855
|
[selectedValues, handleSelect, colors]
|
|
3076
3856
|
);
|
|
3077
|
-
return /* @__PURE__ */ (0,
|
|
3078
|
-
/* @__PURE__ */ (0,
|
|
3857
|
+
return /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
|
|
3858
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
3079
3859
|
AppPressable,
|
|
3080
3860
|
{
|
|
3081
3861
|
className: cn(
|
|
@@ -3083,11 +3863,11 @@ function Select({
|
|
|
3083
3863
|
disabled ? "opacity-60" : "",
|
|
3084
3864
|
className
|
|
3085
3865
|
),
|
|
3086
|
-
style: [
|
|
3866
|
+
style: [styles11.trigger, { backgroundColor: colors.surface, borderColor: colors.border }],
|
|
3087
3867
|
disabled,
|
|
3088
3868
|
onPress: () => setVisible(true),
|
|
3089
3869
|
children: [
|
|
3090
|
-
/* @__PURE__ */ (0,
|
|
3870
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
3091
3871
|
AppText,
|
|
3092
3872
|
{
|
|
3093
3873
|
className: "flex-1",
|
|
@@ -3096,111 +3876,106 @@ function Select({
|
|
|
3096
3876
|
children: displayText
|
|
3097
3877
|
}
|
|
3098
3878
|
),
|
|
3099
|
-
/* @__PURE__ */ (0,
|
|
3100
|
-
clearable && selectedValues.length > 0 && !disabled && /* @__PURE__ */ (0,
|
|
3101
|
-
/* @__PURE__ */ (0,
|
|
3879
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_react_native21.View, { className: "flex-row items-center", children: [
|
|
3880
|
+
clearable && selectedValues.length > 0 && !disabled && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_native21.TouchableOpacity, { onPress: handleClear, className: "mr-2 p-1", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Icon, { name: "close", size: "sm", color: colors.icon }) }),
|
|
3881
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Icon, { name: "keyboard-arrow-down", size: "md", color: colors.icon })
|
|
3102
3882
|
] })
|
|
3103
3883
|
]
|
|
3104
3884
|
}
|
|
3105
3885
|
),
|
|
3106
|
-
/* @__PURE__ */ (0,
|
|
3107
|
-
|
|
3886
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
3887
|
+
BottomSheetModal,
|
|
3108
3888
|
{
|
|
3109
3889
|
visible,
|
|
3110
|
-
transparent: true,
|
|
3111
|
-
animationType: "slide",
|
|
3112
3890
|
onRequestClose: () => setVisible(false),
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
3139
|
-
AppView,
|
|
3140
|
-
{
|
|
3141
|
-
row: true,
|
|
3142
|
-
items: "center",
|
|
3143
|
-
className: "px-3 py-2 rounded-lg",
|
|
3144
|
-
style: { backgroundColor: colors.surfaceMuted },
|
|
3145
|
-
children: [
|
|
3146
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_native19.View, { style: { marginRight: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Icon, { name: "search", size: "sm", color: colors.icon }) }),
|
|
3147
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3148
|
-
import_react_native19.TextInput,
|
|
3149
|
-
{
|
|
3150
|
-
className: "flex-1 text-base",
|
|
3151
|
-
style: { color: colors.text },
|
|
3152
|
-
placeholder: searchPlaceholder,
|
|
3153
|
-
placeholderTextColor: colors.textMuted,
|
|
3154
|
-
value: searchKeyword,
|
|
3155
|
-
onChangeText: handleSearch,
|
|
3156
|
-
autoFocus: true
|
|
3157
|
-
}
|
|
3158
|
-
),
|
|
3159
|
-
searchKeyword.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(import_react_native19.TouchableOpacity, { onPress: () => setSearchKeyword(""), children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(Icon, { name: "close", size: "sm", color: colors.icon }) })
|
|
3160
|
-
]
|
|
3161
|
-
}
|
|
3162
|
-
)
|
|
3163
|
-
}
|
|
3164
|
-
),
|
|
3165
|
-
/* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
|
|
3166
|
-
import_react_native19.FlatList,
|
|
3167
|
-
{
|
|
3168
|
-
data: filteredOptions,
|
|
3169
|
-
keyExtractor: (item) => item.value,
|
|
3170
|
-
renderItem: renderOption,
|
|
3171
|
-
ListEmptyComponent: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(AppView, { center: true, className: "py-8", children: /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(AppText, { style: { color: colors.textMuted }, children: emptyText }) })
|
|
3172
|
-
}
|
|
3173
|
-
),
|
|
3174
|
-
multiple && /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
|
|
3891
|
+
overlayColor: colors.overlay,
|
|
3892
|
+
surfaceColor: colors.surface,
|
|
3893
|
+
closeOnBackdropPress: true,
|
|
3894
|
+
contentClassName: "max-h-[70%]",
|
|
3895
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(import_jsx_runtime30.Fragment, { children: [
|
|
3896
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
3897
|
+
AppView,
|
|
3898
|
+
{
|
|
3899
|
+
row: true,
|
|
3900
|
+
between: true,
|
|
3901
|
+
items: "center",
|
|
3902
|
+
className: "px-4 py-3",
|
|
3903
|
+
style: [styles11.header, { borderBottomColor: colors.divider }],
|
|
3904
|
+
children: [
|
|
3905
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(AppText, { className: "text-lg font-semibold", style: { color: colors.text }, children: multiple ? multipleSelectTitle : singleSelectTitle }),
|
|
3906
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_native21.TouchableOpacity, { onPress: () => setVisible(false), children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Icon, { name: "close", size: "md", color: colors.icon }) })
|
|
3907
|
+
]
|
|
3908
|
+
}
|
|
3909
|
+
),
|
|
3910
|
+
searchable && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
3911
|
+
AppView,
|
|
3912
|
+
{
|
|
3913
|
+
className: "px-4 py-3",
|
|
3914
|
+
style: [styles11.searchBox, { borderBottomColor: colors.divider }],
|
|
3915
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
3175
3916
|
AppView,
|
|
3176
3917
|
{
|
|
3177
3918
|
row: true,
|
|
3178
|
-
between: true,
|
|
3179
3919
|
items: "center",
|
|
3180
|
-
className: "px-
|
|
3181
|
-
style:
|
|
3920
|
+
className: "px-3 py-2 rounded-lg",
|
|
3921
|
+
style: { backgroundColor: colors.surfaceMuted },
|
|
3182
3922
|
children: [
|
|
3183
|
-
/* @__PURE__ */ (0,
|
|
3184
|
-
/* @__PURE__ */ (0,
|
|
3185
|
-
|
|
3923
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_native21.View, { style: { marginRight: 8 }, children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Icon, { name: "search", size: "sm", color: colors.icon }) }),
|
|
3924
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
3925
|
+
import_react_native21.TextInput,
|
|
3186
3926
|
{
|
|
3187
|
-
className: "
|
|
3188
|
-
style: {
|
|
3189
|
-
|
|
3190
|
-
|
|
3927
|
+
className: "flex-1 text-base",
|
|
3928
|
+
style: { color: colors.text },
|
|
3929
|
+
placeholder: searchPlaceholder,
|
|
3930
|
+
placeholderTextColor: colors.textMuted,
|
|
3931
|
+
value: searchKeyword,
|
|
3932
|
+
onChangeText: handleSearch,
|
|
3933
|
+
autoFocus: true
|
|
3191
3934
|
}
|
|
3192
|
-
)
|
|
3935
|
+
),
|
|
3936
|
+
searchKeyword.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(import_react_native21.TouchableOpacity, { onPress: () => setSearchKeyword(""), children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(Icon, { name: "close", size: "sm", color: colors.icon }) })
|
|
3193
3937
|
]
|
|
3194
3938
|
}
|
|
3195
3939
|
)
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3940
|
+
}
|
|
3941
|
+
),
|
|
3942
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
3943
|
+
import_react_native21.FlatList,
|
|
3944
|
+
{
|
|
3945
|
+
data: filteredOptions,
|
|
3946
|
+
keyExtractor: (item, index) => `${item.value}-${index}`,
|
|
3947
|
+
renderItem: renderOption,
|
|
3948
|
+
ListEmptyComponent: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(AppView, { center: true, className: "py-8", children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(AppText, { style: { color: colors.textMuted }, children: emptyText }) })
|
|
3949
|
+
}
|
|
3950
|
+
),
|
|
3951
|
+
multiple && /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
|
|
3952
|
+
AppView,
|
|
3953
|
+
{
|
|
3954
|
+
row: true,
|
|
3955
|
+
between: true,
|
|
3956
|
+
items: "center",
|
|
3957
|
+
className: "px-4 py-3",
|
|
3958
|
+
style: [styles11.footer, { borderTopColor: colors.divider }],
|
|
3959
|
+
children: [
|
|
3960
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(AppText, { style: { color: colors.textMuted }, children: formatSelectedCountText(selectedCountText, selectedValues.length) }),
|
|
3961
|
+
/* @__PURE__ */ (0, import_jsx_runtime30.jsx)(
|
|
3962
|
+
import_react_native21.TouchableOpacity,
|
|
3963
|
+
{
|
|
3964
|
+
className: "px-4 py-2 rounded-lg",
|
|
3965
|
+
style: { backgroundColor: colors.primary },
|
|
3966
|
+
onPress: () => setVisible(false),
|
|
3967
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(AppText, { className: "font-medium", style: { color: colors.textInverse }, children: confirmText })
|
|
3968
|
+
}
|
|
3969
|
+
)
|
|
3970
|
+
]
|
|
3971
|
+
}
|
|
3972
|
+
)
|
|
3973
|
+
] })
|
|
3199
3974
|
}
|
|
3200
3975
|
)
|
|
3201
3976
|
] });
|
|
3202
3977
|
}
|
|
3203
|
-
var
|
|
3978
|
+
var styles11 = import_react_native21.StyleSheet.create({
|
|
3204
3979
|
trigger: {
|
|
3205
3980
|
borderWidth: 0.5
|
|
3206
3981
|
},
|
|
@@ -3218,126 +3993,302 @@ var styles10 = import_react_native19.StyleSheet.create({
|
|
|
3218
3993
|
}
|
|
3219
3994
|
});
|
|
3220
3995
|
|
|
3221
|
-
// src/ui/form/
|
|
3222
|
-
var
|
|
3223
|
-
var
|
|
3224
|
-
var
|
|
3225
|
-
function
|
|
3226
|
-
|
|
3227
|
-
|
|
3996
|
+
// src/ui/form/Picker.tsx
|
|
3997
|
+
var import_react27 = require("react");
|
|
3998
|
+
var import_react_native22 = require("react-native");
|
|
3999
|
+
var import_jsx_runtime31 = require("nativewind/jsx-runtime");
|
|
4000
|
+
function findFirstEnabledValue(column) {
|
|
4001
|
+
return column.options.find((option) => !option.disabled)?.value;
|
|
4002
|
+
}
|
|
4003
|
+
function normalizeValues(columns, values) {
|
|
4004
|
+
return columns.map((column, index) => {
|
|
4005
|
+
const candidate = values?.[index];
|
|
4006
|
+
const matched = column.options.find((option) => option.value === candidate && !option.disabled);
|
|
4007
|
+
return matched?.value ?? findFirstEnabledValue(column) ?? column.options[0]?.value ?? "";
|
|
4008
|
+
});
|
|
4009
|
+
}
|
|
4010
|
+
function WheelPickerColumn({
|
|
4011
|
+
colors,
|
|
4012
|
+
column,
|
|
4013
|
+
onChange,
|
|
4014
|
+
rowHeight,
|
|
3228
4015
|
selectedValue,
|
|
3229
|
-
onSelect,
|
|
3230
|
-
isDisabled,
|
|
3231
|
-
formatLabel = (value) => String(value),
|
|
3232
4016
|
showDivider = false,
|
|
3233
|
-
|
|
4017
|
+
visibleRows
|
|
3234
4018
|
}) {
|
|
3235
|
-
|
|
4019
|
+
const scrollRef = (0, import_react27.useRef)(null);
|
|
4020
|
+
const paddingRows = Math.floor(visibleRows / 2);
|
|
4021
|
+
const selectedIndex = Math.max(
|
|
4022
|
+
0,
|
|
4023
|
+
column.options.findIndex((option) => option.value === selectedValue)
|
|
4024
|
+
);
|
|
4025
|
+
const scrollToIndex = (0, import_react27.useCallback)(
|
|
4026
|
+
(index, animated) => {
|
|
4027
|
+
scrollRef.current?.scrollTo?.({ y: index * rowHeight, animated });
|
|
4028
|
+
},
|
|
4029
|
+
[rowHeight]
|
|
4030
|
+
);
|
|
4031
|
+
const selectNearestEnabled = (0, import_react27.useCallback)(
|
|
4032
|
+
(targetIndex) => {
|
|
4033
|
+
if (column.options.length === 0) return;
|
|
4034
|
+
const maxIndex = column.options.length - 1;
|
|
4035
|
+
const clampedIndex = Math.max(0, Math.min(maxIndex, targetIndex));
|
|
4036
|
+
const exactOption = column.options[clampedIndex];
|
|
4037
|
+
if (exactOption && !exactOption.disabled) {
|
|
4038
|
+
onChange(exactOption.value);
|
|
4039
|
+
scrollToIndex(clampedIndex, true);
|
|
4040
|
+
return;
|
|
4041
|
+
}
|
|
4042
|
+
for (let distance = 1; distance <= maxIndex; distance += 1) {
|
|
4043
|
+
const prevIndex = clampedIndex - distance;
|
|
4044
|
+
if (prevIndex >= 0) {
|
|
4045
|
+
const prevOption = column.options[prevIndex];
|
|
4046
|
+
if (prevOption && !prevOption.disabled) {
|
|
4047
|
+
onChange(prevOption.value);
|
|
4048
|
+
scrollToIndex(prevIndex, true);
|
|
4049
|
+
return;
|
|
4050
|
+
}
|
|
4051
|
+
}
|
|
4052
|
+
const nextIndex = clampedIndex + distance;
|
|
4053
|
+
if (nextIndex <= maxIndex) {
|
|
4054
|
+
const nextOption = column.options[nextIndex];
|
|
4055
|
+
if (nextOption && !nextOption.disabled) {
|
|
4056
|
+
onChange(nextOption.value);
|
|
4057
|
+
scrollToIndex(nextIndex, true);
|
|
4058
|
+
return;
|
|
4059
|
+
}
|
|
4060
|
+
}
|
|
4061
|
+
}
|
|
4062
|
+
},
|
|
4063
|
+
[column.options, onChange, scrollToIndex]
|
|
4064
|
+
);
|
|
4065
|
+
const handleScrollEnd = (0, import_react27.useCallback)(
|
|
4066
|
+
(event) => {
|
|
4067
|
+
const offsetY = event.nativeEvent.contentOffset?.y ?? 0;
|
|
4068
|
+
selectNearestEnabled(Math.round(offsetY / rowHeight));
|
|
4069
|
+
},
|
|
4070
|
+
[rowHeight, selectNearestEnabled]
|
|
4071
|
+
);
|
|
4072
|
+
(0, import_react27.useEffect)(() => {
|
|
4073
|
+
scrollToIndex(selectedIndex, false);
|
|
4074
|
+
}, [scrollToIndex, selectedIndex]);
|
|
4075
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
3236
4076
|
AppView,
|
|
3237
4077
|
{
|
|
3238
4078
|
flex: true,
|
|
3239
4079
|
style: [
|
|
3240
|
-
showDivider
|
|
4080
|
+
showDivider ? styles12.columnDivider : void 0,
|
|
3241
4081
|
showDivider ? { borderRightColor: colors.divider } : void 0
|
|
3242
4082
|
],
|
|
3243
4083
|
children: [
|
|
3244
|
-
/* @__PURE__ */ (0,
|
|
3245
|
-
/* @__PURE__ */ (0,
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
|
|
3252
|
-
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
|
|
4084
|
+
column.title && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AppView, { center: true, className: "py-2", style: { backgroundColor: colors.headerSurface }, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AppText, { className: "text-sm font-medium", style: { color: colors.textMuted }, children: column.title }) }),
|
|
4085
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
4086
|
+
AppView,
|
|
4087
|
+
{
|
|
4088
|
+
style: [
|
|
4089
|
+
styles12.wheelViewport,
|
|
4090
|
+
{
|
|
4091
|
+
height: rowHeight * visibleRows,
|
|
4092
|
+
backgroundColor: colors.surface
|
|
4093
|
+
}
|
|
4094
|
+
],
|
|
4095
|
+
children: [
|
|
4096
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
4097
|
+
import_react_native22.ScrollView,
|
|
3257
4098
|
{
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
4099
|
+
ref: scrollRef,
|
|
4100
|
+
showsVerticalScrollIndicator: false,
|
|
4101
|
+
snapToInterval: rowHeight,
|
|
4102
|
+
decelerationRate: "fast",
|
|
4103
|
+
onMomentumScrollEnd: handleScrollEnd,
|
|
4104
|
+
onScrollEndDrag: handleScrollEnd,
|
|
4105
|
+
contentContainerStyle: { paddingVertical: rowHeight * paddingRows },
|
|
4106
|
+
children: column.options.map((option, index) => {
|
|
4107
|
+
const selected = option.value === selectedValue;
|
|
4108
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
4109
|
+
import_react_native22.TouchableOpacity,
|
|
4110
|
+
{
|
|
4111
|
+
disabled: option.disabled,
|
|
4112
|
+
onPress: () => {
|
|
4113
|
+
if (option.disabled) return;
|
|
4114
|
+
onChange(option.value);
|
|
4115
|
+
scrollToIndex(index, true);
|
|
4116
|
+
},
|
|
4117
|
+
style: [
|
|
4118
|
+
styles12.optionButton,
|
|
4119
|
+
{
|
|
4120
|
+
height: rowHeight,
|
|
4121
|
+
opacity: option.disabled ? 0.35 : selected ? 1 : 0.72
|
|
4122
|
+
}
|
|
4123
|
+
],
|
|
4124
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
4125
|
+
AppText,
|
|
4126
|
+
{
|
|
4127
|
+
className: cn(selected ? "font-semibold" : void 0),
|
|
4128
|
+
style: { color: selected ? colors.primary : colors.text },
|
|
4129
|
+
children: option.label
|
|
4130
|
+
}
|
|
4131
|
+
)
|
|
4132
|
+
},
|
|
4133
|
+
`${column.key}-${String(option.value)}-${index}`
|
|
4134
|
+
);
|
|
4135
|
+
})
|
|
4136
|
+
}
|
|
4137
|
+
),
|
|
4138
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
4139
|
+
AppView,
|
|
4140
|
+
{
|
|
4141
|
+
pointerEvents: "none",
|
|
4142
|
+
style: [
|
|
4143
|
+
styles12.fadeMask,
|
|
4144
|
+
{
|
|
4145
|
+
top: 0,
|
|
4146
|
+
height: rowHeight * paddingRows
|
|
4147
|
+
}
|
|
4148
|
+
],
|
|
4149
|
+
children: [0.92, 0.72, 0.48, 0.24].map((opacity) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
4150
|
+
AppView,
|
|
4151
|
+
{
|
|
4152
|
+
flex: true,
|
|
4153
|
+
style: { backgroundColor: colors.surface, opacity }
|
|
4154
|
+
},
|
|
4155
|
+
`top-${opacity}`
|
|
4156
|
+
))
|
|
4157
|
+
}
|
|
4158
|
+
),
|
|
4159
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
4160
|
+
AppView,
|
|
4161
|
+
{
|
|
4162
|
+
pointerEvents: "none",
|
|
4163
|
+
style: [
|
|
4164
|
+
styles12.fadeMask,
|
|
4165
|
+
{
|
|
4166
|
+
bottom: 0,
|
|
4167
|
+
height: rowHeight * paddingRows
|
|
4168
|
+
}
|
|
4169
|
+
],
|
|
4170
|
+
children: [0.24, 0.48, 0.72, 0.92].map((opacity) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
4171
|
+
AppView,
|
|
4172
|
+
{
|
|
4173
|
+
flex: true,
|
|
4174
|
+
style: { backgroundColor: colors.surface, opacity }
|
|
4175
|
+
},
|
|
4176
|
+
`bottom-${opacity}`
|
|
4177
|
+
))
|
|
4178
|
+
}
|
|
4179
|
+
),
|
|
4180
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
4181
|
+
AppView,
|
|
4182
|
+
{
|
|
4183
|
+
pointerEvents: "none",
|
|
4184
|
+
style: [
|
|
4185
|
+
styles12.selectionOverlay,
|
|
4186
|
+
{
|
|
4187
|
+
top: rowHeight * paddingRows,
|
|
4188
|
+
height: rowHeight,
|
|
4189
|
+
borderColor: colors.divider,
|
|
4190
|
+
backgroundColor: colors.primarySurface
|
|
4191
|
+
}
|
|
4192
|
+
]
|
|
3263
4193
|
}
|
|
3264
4194
|
)
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
}) })
|
|
4195
|
+
]
|
|
4196
|
+
}
|
|
4197
|
+
)
|
|
3269
4198
|
]
|
|
3270
4199
|
}
|
|
3271
4200
|
);
|
|
3272
4201
|
}
|
|
3273
|
-
function
|
|
4202
|
+
function Picker({
|
|
3274
4203
|
value,
|
|
3275
4204
|
onChange,
|
|
3276
|
-
|
|
4205
|
+
columns,
|
|
4206
|
+
placeholder = "\u8BF7\u9009\u62E9",
|
|
3277
4207
|
disabled = false,
|
|
3278
|
-
format = "yyyy-MM-dd",
|
|
3279
|
-
minDate,
|
|
3280
|
-
maxDate,
|
|
3281
4208
|
className,
|
|
4209
|
+
pickerTitle = "\u8BF7\u9009\u62E9",
|
|
3282
4210
|
cancelText = "\u53D6\u6D88",
|
|
3283
4211
|
confirmText = "\u786E\u5B9A",
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
|
|
3288
|
-
|
|
3289
|
-
|
|
3290
|
-
|
|
3291
|
-
|
|
4212
|
+
triggerIconName = "keyboard-arrow-down",
|
|
4213
|
+
renderDisplayText,
|
|
4214
|
+
renderFooter,
|
|
4215
|
+
tempValue,
|
|
4216
|
+
defaultTempValue,
|
|
4217
|
+
onTempChange,
|
|
4218
|
+
onOpen,
|
|
4219
|
+
rowHeight = 40,
|
|
4220
|
+
visibleRows = 5
|
|
3292
4221
|
}) {
|
|
3293
4222
|
const colors = useFormThemeColors();
|
|
3294
|
-
const [visible, setVisible] = (0,
|
|
3295
|
-
const [
|
|
3296
|
-
|
|
3297
|
-
|
|
3298
|
-
|
|
3299
|
-
const
|
|
3300
|
-
|
|
3301
|
-
|
|
3302
|
-
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
for (let i = currentYear - 50; i <= currentYear + 50; i++) {
|
|
3307
|
-
arr.push(i);
|
|
4223
|
+
const [visible, setVisible] = (0, import_react27.useState)(false);
|
|
4224
|
+
const [internalTempValues, setInternalTempValues] = (0, import_react27.useState)(
|
|
4225
|
+
normalizeValues(columns, defaultTempValue ?? value)
|
|
4226
|
+
);
|
|
4227
|
+
const isControlledTemp = tempValue !== void 0;
|
|
4228
|
+
const tempValues = (0, import_react27.useMemo)(
|
|
4229
|
+
() => isControlledTemp ? normalizeValues(columns, tempValue) : internalTempValues,
|
|
4230
|
+
[columns, internalTempValues, isControlledTemp, tempValue]
|
|
4231
|
+
);
|
|
4232
|
+
(0, import_react27.useEffect)(() => {
|
|
4233
|
+
if (!isControlledTemp) {
|
|
4234
|
+
setInternalTempValues((previous) => normalizeValues(columns, previous));
|
|
3308
4235
|
}
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
|
|
3316
|
-
|
|
3317
|
-
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
3322
|
-
|
|
3323
|
-
|
|
3324
|
-
|
|
3325
|
-
|
|
4236
|
+
}, [columns, isControlledTemp]);
|
|
4237
|
+
const selectedOptions = (0, import_react27.useMemo)(
|
|
4238
|
+
() => columns.map(
|
|
4239
|
+
(column, index) => column.options.find((option) => option.value === value?.[index] && !option.disabled)
|
|
4240
|
+
),
|
|
4241
|
+
[columns, value]
|
|
4242
|
+
);
|
|
4243
|
+
const displayText = (0, import_react27.useMemo)(() => {
|
|
4244
|
+
if (!value || value.length === 0) return placeholder;
|
|
4245
|
+
if (renderDisplayText) return renderDisplayText(selectedOptions);
|
|
4246
|
+
const labels = selectedOptions.map((option) => option?.label).filter(Boolean);
|
|
4247
|
+
return labels.length > 0 ? labels.join(" / ") : placeholder;
|
|
4248
|
+
}, [placeholder, renderDisplayText, selectedOptions, value]);
|
|
4249
|
+
const setTempValues = (0, import_react27.useCallback)(
|
|
4250
|
+
(nextValues) => {
|
|
4251
|
+
const normalized = normalizeValues(columns, nextValues);
|
|
4252
|
+
if (isControlledTemp) {
|
|
4253
|
+
onTempChange?.(normalized);
|
|
4254
|
+
return;
|
|
4255
|
+
}
|
|
4256
|
+
setInternalTempValues(normalized);
|
|
4257
|
+
onTempChange?.(normalized);
|
|
3326
4258
|
},
|
|
3327
|
-
[
|
|
4259
|
+
[columns, isControlledTemp, onTempChange]
|
|
3328
4260
|
);
|
|
3329
|
-
const
|
|
3330
|
-
(
|
|
3331
|
-
const
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
if (day !== void 0) newDate.setDate(day);
|
|
3335
|
-
setTempDate(newDate);
|
|
4261
|
+
const updateColumnValue = (0, import_react27.useCallback)(
|
|
4262
|
+
(columnIndex, nextValue) => {
|
|
4263
|
+
const nextValues = [...tempValues];
|
|
4264
|
+
nextValues[columnIndex] = nextValue;
|
|
4265
|
+
setTempValues(nextValues);
|
|
3336
4266
|
},
|
|
3337
|
-
[
|
|
4267
|
+
[setTempValues, tempValues]
|
|
3338
4268
|
);
|
|
3339
|
-
|
|
3340
|
-
|
|
4269
|
+
const openModal = (0, import_react27.useCallback)(() => {
|
|
4270
|
+
const normalized = normalizeValues(columns, tempValue ?? value ?? defaultTempValue);
|
|
4271
|
+
if (!isControlledTemp) {
|
|
4272
|
+
setInternalTempValues(normalized);
|
|
4273
|
+
}
|
|
4274
|
+
onTempChange?.(normalized);
|
|
4275
|
+
onOpen?.();
|
|
4276
|
+
setVisible(true);
|
|
4277
|
+
}, [
|
|
4278
|
+
columns,
|
|
4279
|
+
defaultTempValue,
|
|
4280
|
+
isControlledTemp,
|
|
4281
|
+
onOpen,
|
|
4282
|
+
onTempChange,
|
|
4283
|
+
tempValue,
|
|
4284
|
+
value
|
|
4285
|
+
]);
|
|
4286
|
+
const handleConfirm = (0, import_react27.useCallback)(() => {
|
|
4287
|
+
onChange?.(tempValues);
|
|
4288
|
+
setVisible(false);
|
|
4289
|
+
}, [onChange, tempValues]);
|
|
4290
|
+
return /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
4291
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
3341
4292
|
AppPressable,
|
|
3342
4293
|
{
|
|
3343
4294
|
className: cn(
|
|
@@ -3345,147 +4296,252 @@ function DatePicker({
|
|
|
3345
4296
|
disabled ? "opacity-60" : "",
|
|
3346
4297
|
className
|
|
3347
4298
|
),
|
|
3348
|
-
style: [
|
|
4299
|
+
style: [styles12.trigger, { backgroundColor: colors.surface, borderColor: colors.border }],
|
|
3349
4300
|
disabled,
|
|
3350
|
-
onPress:
|
|
3351
|
-
setTempDate(value || /* @__PURE__ */ new Date());
|
|
3352
|
-
setVisible(true);
|
|
3353
|
-
},
|
|
4301
|
+
onPress: openModal,
|
|
3354
4302
|
children: [
|
|
3355
|
-
/* @__PURE__ */ (0,
|
|
4303
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
3356
4304
|
AppText,
|
|
3357
4305
|
{
|
|
3358
4306
|
className: "flex-1",
|
|
3359
|
-
style: { color: value ? colors.text : colors.textMuted },
|
|
4307
|
+
style: { color: value && value.length > 0 ? colors.text : colors.textMuted },
|
|
3360
4308
|
numberOfLines: 1,
|
|
3361
4309
|
children: displayText
|
|
3362
4310
|
}
|
|
3363
4311
|
),
|
|
3364
|
-
/* @__PURE__ */ (0,
|
|
4312
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(Icon, { name: triggerIconName, size: "md", color: colors.icon })
|
|
3365
4313
|
]
|
|
3366
4314
|
}
|
|
3367
4315
|
),
|
|
3368
|
-
/* @__PURE__ */ (0,
|
|
3369
|
-
|
|
4316
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
4317
|
+
BottomSheetModal,
|
|
3370
4318
|
{
|
|
3371
4319
|
visible,
|
|
3372
|
-
transparent: true,
|
|
3373
|
-
animationType: "slide",
|
|
3374
4320
|
onRequestClose: () => setVisible(false),
|
|
3375
|
-
|
|
3376
|
-
|
|
4321
|
+
overlayColor: colors.overlay,
|
|
4322
|
+
surfaceColor: colors.surface,
|
|
4323
|
+
closeOnBackdropPress: true,
|
|
4324
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(import_jsx_runtime31.Fragment, { children: [
|
|
4325
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsxs)(
|
|
3377
4326
|
AppView,
|
|
3378
4327
|
{
|
|
3379
4328
|
row: true,
|
|
3380
4329
|
between: true,
|
|
3381
4330
|
items: "center",
|
|
3382
4331
|
className: "px-4 py-3",
|
|
3383
|
-
style: [
|
|
4332
|
+
style: [styles12.header, { borderBottomColor: colors.divider }],
|
|
3384
4333
|
children: [
|
|
3385
|
-
/* @__PURE__ */ (0,
|
|
3386
|
-
/* @__PURE__ */ (0,
|
|
3387
|
-
/* @__PURE__ */ (0,
|
|
4334
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_react_native22.TouchableOpacity, { onPress: () => setVisible(false), children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AppText, { style: { color: colors.textMuted }, children: cancelText }) }),
|
|
4335
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AppText, { className: "text-lg font-semibold", style: { color: colors.text }, children: pickerTitle }),
|
|
4336
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(import_react_native22.TouchableOpacity, { onPress: handleConfirm, children: /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AppText, { className: "font-medium", style: { color: colors.primary }, children: confirmText }) })
|
|
3388
4337
|
]
|
|
3389
4338
|
}
|
|
3390
4339
|
),
|
|
3391
|
-
/* @__PURE__ */ (0,
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3402
|
-
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3406
|
-
PickerColumn,
|
|
3407
|
-
{
|
|
3408
|
-
title: monthLabel,
|
|
3409
|
-
values: months,
|
|
3410
|
-
selectedValue: tempDate.getMonth() + 1,
|
|
3411
|
-
onSelect: (month) => updateTempDate(void 0, month),
|
|
3412
|
-
isDisabled: (month) => isDateDisabled(tempDate.getFullYear(), month, tempDate.getDate()),
|
|
3413
|
-
formatLabel: (month) => `${month}\u6708`,
|
|
3414
|
-
colors,
|
|
3415
|
-
showDivider: true
|
|
3416
|
-
}
|
|
3417
|
-
),
|
|
3418
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3419
|
-
PickerColumn,
|
|
3420
|
-
{
|
|
3421
|
-
title: dayLabel,
|
|
3422
|
-
values: days,
|
|
3423
|
-
selectedValue: tempDate.getDate(),
|
|
3424
|
-
onSelect: (day) => updateTempDate(void 0, void 0, day),
|
|
3425
|
-
isDisabled: (day) => isDateDisabled(tempDate.getFullYear(), tempDate.getMonth() + 1, day),
|
|
3426
|
-
colors
|
|
3427
|
-
}
|
|
3428
|
-
)
|
|
3429
|
-
] }),
|
|
3430
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsxs)(
|
|
4340
|
+
/* @__PURE__ */ (0, import_jsx_runtime31.jsx)(AppView, { row: true, children: columns.map((column, index) => /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
4341
|
+
WheelPickerColumn,
|
|
4342
|
+
{
|
|
4343
|
+
colors,
|
|
4344
|
+
column,
|
|
4345
|
+
onChange: (nextValue) => updateColumnValue(index, nextValue),
|
|
4346
|
+
rowHeight,
|
|
4347
|
+
selectedValue: tempValues[index],
|
|
4348
|
+
showDivider: index < columns.length - 1,
|
|
4349
|
+
visibleRows
|
|
4350
|
+
},
|
|
4351
|
+
column.key
|
|
4352
|
+
)) }),
|
|
4353
|
+
renderFooter && /* @__PURE__ */ (0, import_jsx_runtime31.jsx)(
|
|
3431
4354
|
AppView,
|
|
3432
4355
|
{
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
children: [
|
|
3437
|
-
/* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3438
|
-
import_react_native20.TouchableOpacity,
|
|
3439
|
-
{
|
|
3440
|
-
className: "flex-1 py-2 items-center rounded-lg",
|
|
3441
|
-
style: { backgroundColor: colors.surfaceMuted },
|
|
3442
|
-
onPress: () => setTempDate(/* @__PURE__ */ new Date()),
|
|
3443
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(AppText, { style: { color: colors.text }, children: todayText })
|
|
3444
|
-
}
|
|
3445
|
-
),
|
|
3446
|
-
minDate && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3447
|
-
import_react_native20.TouchableOpacity,
|
|
3448
|
-
{
|
|
3449
|
-
className: "flex-1 py-2 items-center rounded-lg",
|
|
3450
|
-
style: { backgroundColor: colors.surfaceMuted },
|
|
3451
|
-
onPress: () => setTempDate(minDate),
|
|
3452
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(AppText, { style: { color: colors.text }, children: minDateText })
|
|
3453
|
-
}
|
|
3454
|
-
),
|
|
3455
|
-
maxDate && /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(
|
|
3456
|
-
import_react_native20.TouchableOpacity,
|
|
3457
|
-
{
|
|
3458
|
-
className: "flex-1 py-2 items-center rounded-lg",
|
|
3459
|
-
style: { backgroundColor: colors.surfaceMuted },
|
|
3460
|
-
onPress: () => setTempDate(maxDate),
|
|
3461
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime29.jsx)(AppText, { style: { color: colors.text }, children: maxDateText })
|
|
3462
|
-
}
|
|
3463
|
-
)
|
|
3464
|
-
]
|
|
4356
|
+
className: "px-4 py-3",
|
|
4357
|
+
style: [styles12.footer, { borderTopColor: colors.divider }],
|
|
4358
|
+
children: renderFooter({ close: () => setVisible(false), setTempValues, tempValues })
|
|
3465
4359
|
}
|
|
3466
4360
|
)
|
|
3467
|
-
] })
|
|
4361
|
+
] })
|
|
3468
4362
|
}
|
|
3469
4363
|
)
|
|
3470
4364
|
] });
|
|
3471
4365
|
}
|
|
3472
|
-
var
|
|
3473
|
-
trigger: {
|
|
3474
|
-
borderWidth: 0.5
|
|
3475
|
-
},
|
|
3476
|
-
header: {
|
|
3477
|
-
borderBottomWidth: 0.5
|
|
3478
|
-
},
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
},
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
}
|
|
3485
|
-
|
|
4366
|
+
var styles12 = import_react_native22.StyleSheet.create({
|
|
4367
|
+
trigger: {
|
|
4368
|
+
borderWidth: 0.5
|
|
4369
|
+
},
|
|
4370
|
+
header: {
|
|
4371
|
+
borderBottomWidth: 0.5
|
|
4372
|
+
},
|
|
4373
|
+
footer: {
|
|
4374
|
+
borderTopWidth: 0.5
|
|
4375
|
+
},
|
|
4376
|
+
columnDivider: {
|
|
4377
|
+
borderRightWidth: 0.5
|
|
4378
|
+
},
|
|
4379
|
+
wheelViewport: {
|
|
4380
|
+
position: "relative",
|
|
4381
|
+
overflow: "hidden"
|
|
4382
|
+
},
|
|
4383
|
+
fadeMask: {
|
|
4384
|
+
position: "absolute",
|
|
4385
|
+
left: 0,
|
|
4386
|
+
right: 0
|
|
4387
|
+
},
|
|
4388
|
+
selectionOverlay: {
|
|
4389
|
+
position: "absolute",
|
|
4390
|
+
left: 8,
|
|
4391
|
+
right: 8,
|
|
4392
|
+
borderRadius: 12,
|
|
4393
|
+
borderWidth: 0.5
|
|
4394
|
+
},
|
|
4395
|
+
optionButton: {
|
|
4396
|
+
alignItems: "center",
|
|
4397
|
+
justifyContent: "center"
|
|
4398
|
+
}
|
|
4399
|
+
});
|
|
4400
|
+
|
|
4401
|
+
// src/ui/form/DatePicker.tsx
|
|
4402
|
+
var import_react28 = require("react");
|
|
4403
|
+
var import_react_native23 = require("react-native");
|
|
4404
|
+
var import_jsx_runtime32 = require("nativewind/jsx-runtime");
|
|
4405
|
+
function createSafeDate(year, month, day) {
|
|
4406
|
+
const daysInMonth = new Date(year, month, 0).getDate();
|
|
4407
|
+
return new Date(year, month - 1, Math.min(day, daysInMonth));
|
|
4408
|
+
}
|
|
4409
|
+
function getDateValues(date) {
|
|
4410
|
+
return [date.getFullYear(), date.getMonth() + 1, date.getDate()];
|
|
4411
|
+
}
|
|
4412
|
+
function DatePicker({
|
|
4413
|
+
value,
|
|
4414
|
+
onChange,
|
|
4415
|
+
placeholder = "\u8BF7\u9009\u62E9\u65E5\u671F",
|
|
4416
|
+
disabled = false,
|
|
4417
|
+
format = "yyyy-MM-dd",
|
|
4418
|
+
minDate,
|
|
4419
|
+
maxDate,
|
|
4420
|
+
className,
|
|
4421
|
+
cancelText = "\u53D6\u6D88",
|
|
4422
|
+
confirmText = "\u786E\u5B9A",
|
|
4423
|
+
pickerTitle = "\u9009\u62E9\u65E5\u671F",
|
|
4424
|
+
pickerDateFormat: _pickerDateFormat = "yyyy\u5E74MM\u6708dd\u65E5",
|
|
4425
|
+
yearLabel = "\u5E74",
|
|
4426
|
+
monthLabel = "\u6708",
|
|
4427
|
+
dayLabel = "\u65E5",
|
|
4428
|
+
todayText = "\u4ECA\u5929",
|
|
4429
|
+
minDateText = "\u6700\u65E9",
|
|
4430
|
+
maxDateText = "\u6700\u665A"
|
|
4431
|
+
}) {
|
|
4432
|
+
const colors = useFormThemeColors();
|
|
4433
|
+
const [tempDate, setTempDate] = (0, import_react28.useState)(value || /* @__PURE__ */ new Date());
|
|
4434
|
+
(0, import_react28.useEffect)(() => {
|
|
4435
|
+
if (value) setTempDate(value);
|
|
4436
|
+
}, [value]);
|
|
4437
|
+
const years = (0, import_react28.useMemo)(() => {
|
|
4438
|
+
const baseYear = value?.getFullYear() ?? (/* @__PURE__ */ new Date()).getFullYear();
|
|
4439
|
+
const startYear = minDate?.getFullYear() ?? baseYear - 50;
|
|
4440
|
+
const endYear = maxDate?.getFullYear() ?? baseYear + 50;
|
|
4441
|
+
return Array.from({ length: endYear - startYear + 1 }, (_, index) => startYear + index);
|
|
4442
|
+
}, [maxDate, minDate, value]);
|
|
4443
|
+
const months = (0, import_react28.useMemo)(() => Array.from({ length: 12 }, (_, index) => index + 1), []);
|
|
4444
|
+
const days = (0, import_react28.useMemo)(() => {
|
|
4445
|
+
const daysInMonth = new Date(tempDate.getFullYear(), tempDate.getMonth() + 1, 0).getDate();
|
|
4446
|
+
return Array.from({ length: daysInMonth }, (_, index) => index + 1);
|
|
4447
|
+
}, [tempDate]);
|
|
4448
|
+
const isDateDisabled = (0, import_react28.useCallback)(
|
|
4449
|
+
(year, month, day) => {
|
|
4450
|
+
const date = createSafeDate(year, month, day);
|
|
4451
|
+
if (minDate && date < minDate) return true;
|
|
4452
|
+
if (maxDate && date > maxDate) return true;
|
|
4453
|
+
return false;
|
|
4454
|
+
},
|
|
4455
|
+
[maxDate, minDate]
|
|
4456
|
+
);
|
|
4457
|
+
const columns = (0, import_react28.useMemo)(
|
|
4458
|
+
() => [
|
|
4459
|
+
{
|
|
4460
|
+
key: "year",
|
|
4461
|
+
title: yearLabel,
|
|
4462
|
+
options: years.map((year) => ({
|
|
4463
|
+
label: String(year),
|
|
4464
|
+
value: year,
|
|
4465
|
+
disabled: isDateDisabled(year, tempDate.getMonth() + 1, tempDate.getDate())
|
|
4466
|
+
}))
|
|
4467
|
+
},
|
|
4468
|
+
{
|
|
4469
|
+
key: "month",
|
|
4470
|
+
title: monthLabel,
|
|
4471
|
+
options: months.map((month) => ({
|
|
4472
|
+
label: `${month}\u6708`,
|
|
4473
|
+
value: month,
|
|
4474
|
+
disabled: isDateDisabled(tempDate.getFullYear(), month, tempDate.getDate())
|
|
4475
|
+
}))
|
|
4476
|
+
},
|
|
4477
|
+
{
|
|
4478
|
+
key: "day",
|
|
4479
|
+
title: dayLabel,
|
|
4480
|
+
options: days.map((day) => ({
|
|
4481
|
+
label: `${day}\u65E5`,
|
|
4482
|
+
value: day,
|
|
4483
|
+
disabled: isDateDisabled(tempDate.getFullYear(), tempDate.getMonth() + 1, day)
|
|
4484
|
+
}))
|
|
4485
|
+
}
|
|
4486
|
+
],
|
|
4487
|
+
[dayLabel, days, isDateDisabled, monthLabel, months, tempDate, yearLabel, years]
|
|
4488
|
+
);
|
|
4489
|
+
const handleTempChange = (0, import_react28.useCallback)((nextValues) => {
|
|
4490
|
+
const [nextYear, nextMonth, nextDay] = nextValues;
|
|
4491
|
+
if (typeof nextYear !== "number" || typeof nextMonth !== "number" || typeof nextDay !== "number") {
|
|
4492
|
+
return;
|
|
4493
|
+
}
|
|
4494
|
+
setTempDate(createSafeDate(nextYear, nextMonth, nextDay));
|
|
4495
|
+
}, []);
|
|
4496
|
+
const handleChange = (0, import_react28.useCallback)(
|
|
4497
|
+
(nextValues) => {
|
|
4498
|
+
const [nextYear, nextMonth, nextDay] = nextValues;
|
|
4499
|
+
if (typeof nextYear !== "number" || typeof nextMonth !== "number" || typeof nextDay !== "number") {
|
|
4500
|
+
return;
|
|
4501
|
+
}
|
|
4502
|
+
onChange?.(createSafeDate(nextYear, nextMonth, nextDay));
|
|
4503
|
+
},
|
|
4504
|
+
[onChange]
|
|
4505
|
+
);
|
|
4506
|
+
const quickActions = (0, import_react28.useMemo)(() => {
|
|
4507
|
+
const actions = [{ label: todayText, date: /* @__PURE__ */ new Date() }];
|
|
4508
|
+
if (minDate) actions.push({ label: minDateText, date: minDate });
|
|
4509
|
+
if (maxDate) actions.push({ label: maxDateText, date: maxDate });
|
|
4510
|
+
return actions;
|
|
4511
|
+
}, [maxDate, maxDateText, minDate, minDateText, todayText]);
|
|
4512
|
+
return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
4513
|
+
Picker,
|
|
4514
|
+
{
|
|
4515
|
+
value: value ? getDateValues(value) : void 0,
|
|
4516
|
+
tempValue: getDateValues(tempDate),
|
|
4517
|
+
onTempChange: handleTempChange,
|
|
4518
|
+
onChange: handleChange,
|
|
4519
|
+
onOpen: () => setTempDate(value || /* @__PURE__ */ new Date()),
|
|
4520
|
+
columns,
|
|
4521
|
+
placeholder,
|
|
4522
|
+
disabled,
|
|
4523
|
+
className,
|
|
4524
|
+
pickerTitle,
|
|
4525
|
+
cancelText,
|
|
4526
|
+
confirmText,
|
|
4527
|
+
triggerIconName: "calendar-today",
|
|
4528
|
+
renderDisplayText: () => value ? formatDate(value, format) : placeholder,
|
|
4529
|
+
renderFooter: () => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(AppView, { row: true, className: "gap-2", children: quickActions.map((action) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
|
|
4530
|
+
import_react_native23.TouchableOpacity,
|
|
4531
|
+
{
|
|
4532
|
+
className: "flex-1 py-2 items-center rounded-lg",
|
|
4533
|
+
style: { backgroundColor: colors.surfaceMuted },
|
|
4534
|
+
onPress: () => setTempDate(action.date),
|
|
4535
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(AppText, { style: { color: colors.text }, children: action.label })
|
|
4536
|
+
},
|
|
4537
|
+
action.label
|
|
4538
|
+
)) })
|
|
4539
|
+
}
|
|
4540
|
+
);
|
|
4541
|
+
}
|
|
3486
4542
|
|
|
3487
4543
|
// src/ui/form/FormItem.tsx
|
|
3488
|
-
var
|
|
4544
|
+
var import_jsx_runtime33 = require("nativewind/jsx-runtime");
|
|
3489
4545
|
function FormItem({
|
|
3490
4546
|
name: _name,
|
|
3491
4547
|
label,
|
|
@@ -3497,19 +4553,19 @@ function FormItem({
|
|
|
3497
4553
|
labelClassName
|
|
3498
4554
|
}) {
|
|
3499
4555
|
const colors = useThemeColors();
|
|
3500
|
-
return /* @__PURE__ */ (0,
|
|
3501
|
-
label && /* @__PURE__ */ (0,
|
|
3502
|
-
/* @__PURE__ */ (0,
|
|
3503
|
-
required && /* @__PURE__ */ (0,
|
|
4556
|
+
return /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(AppView, { className: cn("mb-4", className), children: [
|
|
4557
|
+
label && /* @__PURE__ */ (0, import_jsx_runtime33.jsxs)(AppView, { row: true, items: "center", gap: 1, className: cn("mb-2", labelClassName), children: [
|
|
4558
|
+
/* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AppText, { size: "sm", weight: "medium", style: { color: colors.textSecondary }, children: label }),
|
|
4559
|
+
required && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AppText, { color: "error-500", children: "*" })
|
|
3504
4560
|
] }),
|
|
3505
4561
|
children,
|
|
3506
|
-
error && /* @__PURE__ */ (0,
|
|
3507
|
-
help && !error && /* @__PURE__ */ (0,
|
|
4562
|
+
error && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AppText, { size: "sm", color: "error-500", className: "mt-1", children: error }),
|
|
4563
|
+
help && !error && /* @__PURE__ */ (0, import_jsx_runtime33.jsx)(AppText, { size: "sm", className: "mt-1", style: { color: colors.textMuted }, children: help })
|
|
3508
4564
|
] });
|
|
3509
4565
|
}
|
|
3510
4566
|
|
|
3511
4567
|
// src/ui/form/useForm.ts
|
|
3512
|
-
var
|
|
4568
|
+
var import_react29 = require("react");
|
|
3513
4569
|
var getIssuePath = (issue) => issue.path.map(String).join(".");
|
|
3514
4570
|
var getFieldError = (issues, name) => {
|
|
3515
4571
|
const exactIssue = issues.find((issue) => getIssuePath(issue) === name);
|
|
@@ -3525,16 +4581,16 @@ var buildFormErrors = (issues) => {
|
|
|
3525
4581
|
}, {});
|
|
3526
4582
|
};
|
|
3527
4583
|
function useForm({ schema, defaultValues }) {
|
|
3528
|
-
const [values, setValues] = (0,
|
|
3529
|
-
const [errors, setErrors] = (0,
|
|
3530
|
-
const [isSubmitting, setIsSubmitting] = (0,
|
|
3531
|
-
const isDirty = (0,
|
|
4584
|
+
const [values, setValues] = (0, import_react29.useState)(defaultValues);
|
|
4585
|
+
const [errors, setErrors] = (0, import_react29.useState)({});
|
|
4586
|
+
const [isSubmitting, setIsSubmitting] = (0, import_react29.useState)(false);
|
|
4587
|
+
const isDirty = (0, import_react29.useMemo)(() => {
|
|
3532
4588
|
return JSON.stringify(values) !== JSON.stringify(defaultValues);
|
|
3533
4589
|
}, [values, defaultValues]);
|
|
3534
|
-
const isValid = (0,
|
|
4590
|
+
const isValid = (0, import_react29.useMemo)(() => {
|
|
3535
4591
|
return Object.keys(errors).length === 0;
|
|
3536
4592
|
}, [errors]);
|
|
3537
|
-
const clearFieldError = (0,
|
|
4593
|
+
const clearFieldError = (0, import_react29.useCallback)((name) => {
|
|
3538
4594
|
setErrors((prev) => {
|
|
3539
4595
|
if (!(name in prev)) return prev;
|
|
3540
4596
|
const next = { ...prev };
|
|
@@ -3542,20 +4598,20 @@ function useForm({ schema, defaultValues }) {
|
|
|
3542
4598
|
return next;
|
|
3543
4599
|
});
|
|
3544
4600
|
}, []);
|
|
3545
|
-
const setValue = (0,
|
|
4601
|
+
const setValue = (0, import_react29.useCallback)(
|
|
3546
4602
|
(name, value) => {
|
|
3547
4603
|
setValues((prev) => ({ ...prev, [name]: value }));
|
|
3548
4604
|
clearFieldError(name);
|
|
3549
4605
|
},
|
|
3550
4606
|
[clearFieldError]
|
|
3551
4607
|
);
|
|
3552
|
-
const getValue = (0,
|
|
4608
|
+
const getValue = (0, import_react29.useCallback)(
|
|
3553
4609
|
(name) => {
|
|
3554
4610
|
return values[name];
|
|
3555
4611
|
},
|
|
3556
4612
|
[values]
|
|
3557
4613
|
);
|
|
3558
|
-
const validateField = (0,
|
|
4614
|
+
const validateField = (0, import_react29.useCallback)(
|
|
3559
4615
|
async (name) => {
|
|
3560
4616
|
const fieldName = name;
|
|
3561
4617
|
const result = await schema.safeParseAsync(values);
|
|
@@ -3576,7 +4632,7 @@ function useForm({ schema, defaultValues }) {
|
|
|
3576
4632
|
},
|
|
3577
4633
|
[schema, values, clearFieldError]
|
|
3578
4634
|
);
|
|
3579
|
-
const validate = (0,
|
|
4635
|
+
const validate = (0, import_react29.useCallback)(async () => {
|
|
3580
4636
|
const result = await schema.safeParseAsync(values);
|
|
3581
4637
|
if (result.success) {
|
|
3582
4638
|
setErrors({});
|
|
@@ -3585,12 +4641,12 @@ function useForm({ schema, defaultValues }) {
|
|
|
3585
4641
|
setErrors(buildFormErrors(result.error.issues));
|
|
3586
4642
|
return false;
|
|
3587
4643
|
}, [schema, values]);
|
|
3588
|
-
const reset = (0,
|
|
4644
|
+
const reset = (0, import_react29.useCallback)(() => {
|
|
3589
4645
|
setValues(defaultValues);
|
|
3590
4646
|
setErrors({});
|
|
3591
4647
|
setIsSubmitting(false);
|
|
3592
4648
|
}, [defaultValues]);
|
|
3593
|
-
const handleSubmit = (0,
|
|
4649
|
+
const handleSubmit = (0, import_react29.useCallback)(
|
|
3594
4650
|
async (onSubmit) => {
|
|
3595
4651
|
const valid = await validate();
|
|
3596
4652
|
if (!valid) return;
|
|
@@ -3619,38 +4675,38 @@ function useForm({ schema, defaultValues }) {
|
|
|
3619
4675
|
}
|
|
3620
4676
|
|
|
3621
4677
|
// src/ui/hooks/useToggle.ts
|
|
3622
|
-
var
|
|
4678
|
+
var import_react30 = require("react");
|
|
3623
4679
|
function useToggle(defaultValue = false) {
|
|
3624
|
-
const [value, setValue] = (0,
|
|
3625
|
-
const toggle = (0,
|
|
4680
|
+
const [value, setValue] = (0, import_react30.useState)(defaultValue);
|
|
4681
|
+
const toggle = (0, import_react30.useCallback)(() => {
|
|
3626
4682
|
setValue((v) => !v);
|
|
3627
4683
|
}, []);
|
|
3628
|
-
const set = (0,
|
|
4684
|
+
const set = (0, import_react30.useCallback)((newValue) => {
|
|
3629
4685
|
setValue(newValue);
|
|
3630
4686
|
}, []);
|
|
3631
|
-
const setTrue = (0,
|
|
4687
|
+
const setTrue = (0, import_react30.useCallback)(() => {
|
|
3632
4688
|
setValue(true);
|
|
3633
4689
|
}, []);
|
|
3634
|
-
const setFalse = (0,
|
|
4690
|
+
const setFalse = (0, import_react30.useCallback)(() => {
|
|
3635
4691
|
setValue(false);
|
|
3636
4692
|
}, []);
|
|
3637
4693
|
return [value, { toggle, set, setTrue, setFalse }];
|
|
3638
4694
|
}
|
|
3639
4695
|
|
|
3640
4696
|
// src/ui/hooks/usePageDrawer.ts
|
|
3641
|
-
var
|
|
4697
|
+
var import_react31 = require("react");
|
|
3642
4698
|
function usePageDrawer(defaultVisible = false) {
|
|
3643
|
-
const [visible, setVisibleState] = (0,
|
|
3644
|
-
const open = (0,
|
|
4699
|
+
const [visible, setVisibleState] = (0, import_react31.useState)(defaultVisible);
|
|
4700
|
+
const open = (0, import_react31.useCallback)(() => {
|
|
3645
4701
|
setVisibleState(true);
|
|
3646
4702
|
}, []);
|
|
3647
|
-
const close = (0,
|
|
4703
|
+
const close = (0, import_react31.useCallback)(() => {
|
|
3648
4704
|
setVisibleState(false);
|
|
3649
4705
|
}, []);
|
|
3650
|
-
const toggle = (0,
|
|
4706
|
+
const toggle = (0, import_react31.useCallback)(() => {
|
|
3651
4707
|
setVisibleState((current) => !current);
|
|
3652
4708
|
}, []);
|
|
3653
|
-
const setVisible = (0,
|
|
4709
|
+
const setVisible = (0, import_react31.useCallback)((nextVisible) => {
|
|
3654
4710
|
setVisibleState(nextVisible);
|
|
3655
4711
|
}, []);
|
|
3656
4712
|
return {
|
|
@@ -3663,10 +4719,10 @@ function usePageDrawer(defaultVisible = false) {
|
|
|
3663
4719
|
}
|
|
3664
4720
|
|
|
3665
4721
|
// src/ui/hooks/useDebounce.ts
|
|
3666
|
-
var
|
|
4722
|
+
var import_react32 = require("react");
|
|
3667
4723
|
function useDebounce(value, delay = 500) {
|
|
3668
|
-
const [debouncedValue, setDebouncedValue] = (0,
|
|
3669
|
-
(0,
|
|
4724
|
+
const [debouncedValue, setDebouncedValue] = (0, import_react32.useState)(value);
|
|
4725
|
+
(0, import_react32.useEffect)(() => {
|
|
3670
4726
|
const timer = setTimeout(() => {
|
|
3671
4727
|
setDebouncedValue(value);
|
|
3672
4728
|
}, delay);
|
|
@@ -3678,11 +4734,11 @@ function useDebounce(value, delay = 500) {
|
|
|
3678
4734
|
}
|
|
3679
4735
|
|
|
3680
4736
|
// src/ui/hooks/useThrottle.ts
|
|
3681
|
-
var
|
|
4737
|
+
var import_react33 = require("react");
|
|
3682
4738
|
function useThrottle(value, delay = 200) {
|
|
3683
|
-
const [throttledValue, setThrottledValue] = (0,
|
|
3684
|
-
const lastUpdatedRef = (0,
|
|
3685
|
-
(0,
|
|
4739
|
+
const [throttledValue, setThrottledValue] = (0, import_react33.useState)(value);
|
|
4740
|
+
const lastUpdatedRef = (0, import_react33.useRef)(Date.now());
|
|
4741
|
+
(0, import_react33.useEffect)(() => {
|
|
3686
4742
|
const now = Date.now();
|
|
3687
4743
|
const timeElapsed = now - lastUpdatedRef.current;
|
|
3688
4744
|
if (timeElapsed >= delay) {
|
|
@@ -3703,12 +4759,12 @@ function useThrottle(value, delay = 200) {
|
|
|
3703
4759
|
}
|
|
3704
4760
|
|
|
3705
4761
|
// src/ui/hooks/useKeyboard.ts
|
|
3706
|
-
var
|
|
3707
|
-
var
|
|
4762
|
+
var import_react34 = require("react");
|
|
4763
|
+
var import_react_native24 = require("react-native");
|
|
3708
4764
|
function useKeyboard() {
|
|
3709
|
-
const [visible, setVisible] = (0,
|
|
3710
|
-
const [height, setHeight] = (0,
|
|
3711
|
-
(0,
|
|
4765
|
+
const [visible, setVisible] = (0, import_react34.useState)(false);
|
|
4766
|
+
const [height, setHeight] = (0, import_react34.useState)(0);
|
|
4767
|
+
(0, import_react34.useEffect)(() => {
|
|
3712
4768
|
const handleKeyboardWillShow = (event) => {
|
|
3713
4769
|
setVisible(true);
|
|
3714
4770
|
setHeight(event.endCoordinates.height);
|
|
@@ -3725,31 +4781,31 @@ function useKeyboard() {
|
|
|
3725
4781
|
setVisible(false);
|
|
3726
4782
|
setHeight(0);
|
|
3727
4783
|
};
|
|
3728
|
-
const willShowSub =
|
|
3729
|
-
|
|
3730
|
-
|
|
4784
|
+
const willShowSub = import_react_native24.Keyboard.addListener(
|
|
4785
|
+
import_react_native24.Platform.OS === "ios" ? "keyboardWillShow" : "keyboardDidShow",
|
|
4786
|
+
import_react_native24.Platform.OS === "ios" ? handleKeyboardWillShow : handleKeyboardDidShow
|
|
3731
4787
|
);
|
|
3732
|
-
const willHideSub =
|
|
3733
|
-
|
|
3734
|
-
|
|
4788
|
+
const willHideSub = import_react_native24.Keyboard.addListener(
|
|
4789
|
+
import_react_native24.Platform.OS === "ios" ? "keyboardWillHide" : "keyboardDidHide",
|
|
4790
|
+
import_react_native24.Platform.OS === "ios" ? handleKeyboardWillHide : handleKeyboardDidHide
|
|
3735
4791
|
);
|
|
3736
4792
|
return () => {
|
|
3737
4793
|
willShowSub.remove();
|
|
3738
4794
|
willHideSub.remove();
|
|
3739
4795
|
};
|
|
3740
4796
|
}, []);
|
|
3741
|
-
const dismiss = (0,
|
|
3742
|
-
|
|
4797
|
+
const dismiss = (0, import_react34.useCallback)(() => {
|
|
4798
|
+
import_react_native24.Keyboard.dismiss();
|
|
3743
4799
|
}, []);
|
|
3744
4800
|
return { visible, height, dismiss };
|
|
3745
4801
|
}
|
|
3746
4802
|
|
|
3747
4803
|
// src/ui/hooks/useDimensions.ts
|
|
3748
|
-
var
|
|
3749
|
-
var
|
|
4804
|
+
var import_react35 = require("react");
|
|
4805
|
+
var import_react_native25 = require("react-native");
|
|
3750
4806
|
function useDimensions() {
|
|
3751
|
-
const [dimensions, setDimensions] = (0,
|
|
3752
|
-
const window =
|
|
4807
|
+
const [dimensions, setDimensions] = (0, import_react35.useState)(() => {
|
|
4808
|
+
const window = import_react_native25.Dimensions.get("window");
|
|
3753
4809
|
return {
|
|
3754
4810
|
width: window.width,
|
|
3755
4811
|
height: window.height,
|
|
@@ -3757,7 +4813,7 @@ function useDimensions() {
|
|
|
3757
4813
|
fontScale: window.fontScale
|
|
3758
4814
|
};
|
|
3759
4815
|
});
|
|
3760
|
-
(0,
|
|
4816
|
+
(0, import_react35.useEffect)(() => {
|
|
3761
4817
|
const handleChange = ({ window }) => {
|
|
3762
4818
|
setDimensions({
|
|
3763
4819
|
width: window.width,
|
|
@@ -3766,7 +4822,7 @@ function useDimensions() {
|
|
|
3766
4822
|
fontScale: window.fontScale
|
|
3767
4823
|
});
|
|
3768
4824
|
};
|
|
3769
|
-
const subscription =
|
|
4825
|
+
const subscription = import_react_native25.Dimensions.addEventListener("change", handleChange);
|
|
3770
4826
|
return () => {
|
|
3771
4827
|
subscription.remove();
|
|
3772
4828
|
};
|
|
@@ -3775,20 +4831,20 @@ function useDimensions() {
|
|
|
3775
4831
|
}
|
|
3776
4832
|
|
|
3777
4833
|
// src/ui/hooks/useOrientation.ts
|
|
3778
|
-
var
|
|
3779
|
-
var
|
|
4834
|
+
var import_react36 = require("react");
|
|
4835
|
+
var import_react_native26 = require("react-native");
|
|
3780
4836
|
function useOrientation() {
|
|
3781
4837
|
const getOrientation = () => {
|
|
3782
|
-
const { width, height } =
|
|
4838
|
+
const { width, height } = import_react_native26.Dimensions.get("window");
|
|
3783
4839
|
return width > height ? "landscape" : "portrait";
|
|
3784
4840
|
};
|
|
3785
|
-
const [orientation, setOrientation] = (0,
|
|
3786
|
-
(0,
|
|
4841
|
+
const [orientation, setOrientation] = (0, import_react36.useState)(getOrientation);
|
|
4842
|
+
(0, import_react36.useEffect)(() => {
|
|
3787
4843
|
const handleChange = ({ window }) => {
|
|
3788
4844
|
const newOrientation = window.width > window.height ? "landscape" : "portrait";
|
|
3789
4845
|
setOrientation(newOrientation);
|
|
3790
4846
|
};
|
|
3791
|
-
const subscription =
|
|
4847
|
+
const subscription = import_react_native26.Dimensions.addEventListener("change", handleChange);
|
|
3792
4848
|
return () => {
|
|
3793
4849
|
subscription.remove();
|
|
3794
4850
|
};
|
|
@@ -3801,7 +4857,7 @@ function useOrientation() {
|
|
|
3801
4857
|
}
|
|
3802
4858
|
|
|
3803
4859
|
// src/navigation/provider.tsx
|
|
3804
|
-
var
|
|
4860
|
+
var import_react37 = __toESM(require("react"));
|
|
3805
4861
|
var import_native = require("@react-navigation/native");
|
|
3806
4862
|
|
|
3807
4863
|
// src/navigation/utils/navigation-theme.ts
|
|
@@ -3827,7 +4883,7 @@ function createNavigationTheme(pantherTheme, isDark) {
|
|
|
3827
4883
|
}
|
|
3828
4884
|
|
|
3829
4885
|
// src/navigation/provider.tsx
|
|
3830
|
-
var
|
|
4886
|
+
var import_jsx_runtime34 = require("nativewind/jsx-runtime");
|
|
3831
4887
|
function NavigationProvider({
|
|
3832
4888
|
children,
|
|
3833
4889
|
linking,
|
|
@@ -3838,11 +4894,11 @@ function NavigationProvider({
|
|
|
3838
4894
|
theme: customTheme
|
|
3839
4895
|
}) {
|
|
3840
4896
|
const { theme, isDark } = useTheme();
|
|
3841
|
-
const navigationTheme =
|
|
4897
|
+
const navigationTheme = import_react37.default.useMemo(
|
|
3842
4898
|
() => customTheme || createNavigationTheme(theme, isDark),
|
|
3843
4899
|
[customTheme, theme, isDark]
|
|
3844
4900
|
);
|
|
3845
|
-
return /* @__PURE__ */ (0,
|
|
4901
|
+
return /* @__PURE__ */ (0, import_jsx_runtime34.jsx)(
|
|
3846
4902
|
import_native.NavigationContainer,
|
|
3847
4903
|
{
|
|
3848
4904
|
theme: navigationTheme,
|
|
@@ -3860,14 +4916,14 @@ function NavigationProvider({
|
|
|
3860
4916
|
var import_stack = require("@react-navigation/stack");
|
|
3861
4917
|
|
|
3862
4918
|
// src/navigation/navigators/StackNavigator.tsx
|
|
3863
|
-
var
|
|
4919
|
+
var import_jsx_runtime35 = require("nativewind/jsx-runtime");
|
|
3864
4920
|
var NativeStack = (0, import_stack.createStackNavigator)();
|
|
3865
4921
|
var defaultScreenOptions = {
|
|
3866
4922
|
headerShown: false,
|
|
3867
4923
|
...import_stack.TransitionPresets.SlideFromRightIOS
|
|
3868
4924
|
};
|
|
3869
4925
|
function StackNavigator({ initialRouteName, screenOptions, children }) {
|
|
3870
|
-
return /* @__PURE__ */ (0,
|
|
4926
|
+
return /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3871
4927
|
NativeStack.Navigator,
|
|
3872
4928
|
{
|
|
3873
4929
|
initialRouteName,
|
|
@@ -3879,7 +4935,7 @@ function StackNavigator({ initialRouteName, screenOptions, children }) {
|
|
|
3879
4935
|
StackNavigator.Screen = NativeStack.Screen;
|
|
3880
4936
|
StackNavigator.Group = NativeStack.Group;
|
|
3881
4937
|
function createStackScreens(routes) {
|
|
3882
|
-
return routes.map((route) => /* @__PURE__ */ (0,
|
|
4938
|
+
return routes.map((route) => /* @__PURE__ */ (0, import_jsx_runtime35.jsx)(
|
|
3883
4939
|
StackNavigator.Screen,
|
|
3884
4940
|
{
|
|
3885
4941
|
name: route.name,
|
|
@@ -3892,13 +4948,13 @@ function createStackScreens(routes) {
|
|
|
3892
4948
|
}
|
|
3893
4949
|
|
|
3894
4950
|
// src/navigation/navigators/TabNavigator.tsx
|
|
3895
|
-
var
|
|
4951
|
+
var import_react38 = __toESM(require("react"));
|
|
3896
4952
|
var import_bottom_tabs = require("@react-navigation/bottom-tabs");
|
|
3897
4953
|
|
|
3898
4954
|
// src/navigation/components/BottomTabBar.tsx
|
|
3899
|
-
var
|
|
4955
|
+
var import_react_native27 = require("react-native");
|
|
3900
4956
|
var import_react_native_safe_area_context2 = require("react-native-safe-area-context");
|
|
3901
|
-
var
|
|
4957
|
+
var import_jsx_runtime36 = require("nativewind/jsx-runtime");
|
|
3902
4958
|
var DEFAULT_TAB_BAR_HEIGHT = 65;
|
|
3903
4959
|
function BottomTabBar({
|
|
3904
4960
|
state,
|
|
@@ -3920,11 +4976,11 @@ function BottomTabBar({
|
|
|
3920
4976
|
const inactiveColor = inactiveTintColor || colors.textMuted;
|
|
3921
4977
|
const backgroundColor = style?.backgroundColor || colors.card;
|
|
3922
4978
|
const borderTopColor = colors.divider;
|
|
3923
|
-
return /* @__PURE__ */ (0,
|
|
3924
|
-
|
|
4979
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
4980
|
+
import_react_native27.View,
|
|
3925
4981
|
{
|
|
3926
4982
|
style: [
|
|
3927
|
-
|
|
4983
|
+
styles13.container,
|
|
3928
4984
|
{ borderTopColor },
|
|
3929
4985
|
{ backgroundColor, height: height + insets.bottom, paddingBottom: insets.bottom },
|
|
3930
4986
|
style
|
|
@@ -3955,8 +5011,8 @@ function BottomTabBar({
|
|
|
3955
5011
|
size: 24
|
|
3956
5012
|
}) : null;
|
|
3957
5013
|
const badge = options.tabBarBadge;
|
|
3958
|
-
return /* @__PURE__ */ (0,
|
|
3959
|
-
|
|
5014
|
+
return /* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(
|
|
5015
|
+
import_react_native27.TouchableOpacity,
|
|
3960
5016
|
{
|
|
3961
5017
|
accessibilityRole: "button",
|
|
3962
5018
|
accessibilityState: isFocused ? { selected: true } : {},
|
|
@@ -3965,21 +5021,21 @@ function BottomTabBar({
|
|
|
3965
5021
|
onPress,
|
|
3966
5022
|
onLongPress,
|
|
3967
5023
|
style: [
|
|
3968
|
-
|
|
5024
|
+
styles13.tab,
|
|
3969
5025
|
{
|
|
3970
5026
|
backgroundColor: isFocused ? activeBackgroundColor : inactiveBackgroundColor
|
|
3971
5027
|
}
|
|
3972
5028
|
],
|
|
3973
5029
|
children: [
|
|
3974
|
-
/* @__PURE__ */ (0,
|
|
5030
|
+
/* @__PURE__ */ (0, import_jsx_runtime36.jsxs)(import_react_native27.View, { style: [styles13.iconContainer, iconStyle], children: [
|
|
3975
5031
|
iconName,
|
|
3976
|
-
badge != null && /* @__PURE__ */ (0,
|
|
5032
|
+
badge != null && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(import_react_native27.View, { style: [styles13.badge, { backgroundColor: activeColor }], children: /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(AppText, { style: styles13.badgeText, children: typeof badge === "number" && badge > 99 ? "99+" : badge }) })
|
|
3977
5033
|
] }),
|
|
3978
|
-
showLabel && /* @__PURE__ */ (0,
|
|
5034
|
+
showLabel && /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(
|
|
3979
5035
|
AppText,
|
|
3980
5036
|
{
|
|
3981
5037
|
style: [
|
|
3982
|
-
|
|
5038
|
+
styles13.label,
|
|
3983
5039
|
{ color: isFocused ? activeColor : inactiveColor },
|
|
3984
5040
|
labelStyle
|
|
3985
5041
|
],
|
|
@@ -3995,7 +5051,7 @@ function BottomTabBar({
|
|
|
3995
5051
|
}
|
|
3996
5052
|
);
|
|
3997
5053
|
}
|
|
3998
|
-
var
|
|
5054
|
+
var styles13 = import_react_native27.StyleSheet.create({
|
|
3999
5055
|
container: {
|
|
4000
5056
|
flexDirection: "row",
|
|
4001
5057
|
borderTopWidth: 0.5,
|
|
@@ -4038,7 +5094,7 @@ var styles12 = import_react_native24.StyleSheet.create({
|
|
|
4038
5094
|
});
|
|
4039
5095
|
|
|
4040
5096
|
// src/navigation/navigators/TabNavigator.tsx
|
|
4041
|
-
var
|
|
5097
|
+
var import_jsx_runtime37 = require("nativewind/jsx-runtime");
|
|
4042
5098
|
var NativeTab = (0, import_bottom_tabs.createBottomTabNavigator)();
|
|
4043
5099
|
var defaultScreenOptions2 = {
|
|
4044
5100
|
headerShown: false,
|
|
@@ -4051,7 +5107,7 @@ function TabNavigator({
|
|
|
4051
5107
|
screenOptions,
|
|
4052
5108
|
children
|
|
4053
5109
|
}) {
|
|
4054
|
-
const mergedScreenOptions =
|
|
5110
|
+
const mergedScreenOptions = import_react38.default.useMemo(() => {
|
|
4055
5111
|
const options = { ...defaultScreenOptions2, ...screenOptions };
|
|
4056
5112
|
if (tabBarOptions) {
|
|
4057
5113
|
if (tabBarOptions.showLabel !== void 0) {
|
|
@@ -4084,9 +5140,9 @@ function TabNavigator({
|
|
|
4084
5140
|
}
|
|
4085
5141
|
return options;
|
|
4086
5142
|
}, [tabBarOptions, screenOptions]);
|
|
4087
|
-
const resolvedTabBar =
|
|
5143
|
+
const resolvedTabBar = import_react38.default.useMemo(() => {
|
|
4088
5144
|
if (tabBar) return tabBar;
|
|
4089
|
-
return (props) => /* @__PURE__ */ (0,
|
|
5145
|
+
return (props) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
4090
5146
|
BottomTabBar,
|
|
4091
5147
|
{
|
|
4092
5148
|
...props,
|
|
@@ -4113,7 +5169,7 @@ function TabNavigator({
|
|
|
4113
5169
|
tabBarOptions?.style,
|
|
4114
5170
|
tabBarOptions?.height
|
|
4115
5171
|
]);
|
|
4116
|
-
return /* @__PURE__ */ (0,
|
|
5172
|
+
return /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
4117
5173
|
NativeTab.Navigator,
|
|
4118
5174
|
{
|
|
4119
5175
|
initialRouteName,
|
|
@@ -4125,7 +5181,7 @@ function TabNavigator({
|
|
|
4125
5181
|
}
|
|
4126
5182
|
TabNavigator.Screen = NativeTab.Screen;
|
|
4127
5183
|
function createTabScreens(routes) {
|
|
4128
|
-
return routes.map((route) => /* @__PURE__ */ (0,
|
|
5184
|
+
return routes.map((route) => /* @__PURE__ */ (0, import_jsx_runtime37.jsx)(
|
|
4129
5185
|
TabNavigator.Screen,
|
|
4130
5186
|
{
|
|
4131
5187
|
name: route.name,
|
|
@@ -4138,9 +5194,9 @@ function createTabScreens(routes) {
|
|
|
4138
5194
|
}
|
|
4139
5195
|
|
|
4140
5196
|
// src/navigation/navigators/DrawerNavigator.tsx
|
|
4141
|
-
var
|
|
5197
|
+
var import_react39 = __toESM(require("react"));
|
|
4142
5198
|
var import_drawer = require("@react-navigation/drawer");
|
|
4143
|
-
var
|
|
5199
|
+
var import_jsx_runtime38 = require("nativewind/jsx-runtime");
|
|
4144
5200
|
var NativeDrawer = (0, import_drawer.createDrawerNavigator)();
|
|
4145
5201
|
function DrawerNavigator({
|
|
4146
5202
|
initialRouteName,
|
|
@@ -4151,7 +5207,7 @@ function DrawerNavigator({
|
|
|
4151
5207
|
}) {
|
|
4152
5208
|
const { theme, isDark } = useTheme();
|
|
4153
5209
|
const navigationTheme = createNavigationTheme(theme, isDark);
|
|
4154
|
-
const mergedScreenOptions =
|
|
5210
|
+
const mergedScreenOptions = import_react39.default.useMemo(() => {
|
|
4155
5211
|
return {
|
|
4156
5212
|
headerShown: false,
|
|
4157
5213
|
drawerStyle: {
|
|
@@ -4170,7 +5226,7 @@ function DrawerNavigator({
|
|
|
4170
5226
|
...screenOptions
|
|
4171
5227
|
};
|
|
4172
5228
|
}, [screenOptions, drawerOptions, navigationTheme, theme]);
|
|
4173
|
-
return /* @__PURE__ */ (0,
|
|
5229
|
+
return /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
4174
5230
|
NativeDrawer.Navigator,
|
|
4175
5231
|
{
|
|
4176
5232
|
initialRouteName,
|
|
@@ -4182,7 +5238,7 @@ function DrawerNavigator({
|
|
|
4182
5238
|
}
|
|
4183
5239
|
DrawerNavigator.Screen = NativeDrawer.Screen;
|
|
4184
5240
|
function createDrawerScreens(routes) {
|
|
4185
|
-
return routes.map((route) => /* @__PURE__ */ (0,
|
|
5241
|
+
return routes.map((route) => /* @__PURE__ */ (0, import_jsx_runtime38.jsx)(
|
|
4186
5242
|
DrawerNavigator.Screen,
|
|
4187
5243
|
{
|
|
4188
5244
|
name: route.name,
|
|
@@ -4195,16 +5251,16 @@ function createDrawerScreens(routes) {
|
|
|
4195
5251
|
}
|
|
4196
5252
|
|
|
4197
5253
|
// src/navigation/components/AppHeader.tsx
|
|
4198
|
-
var
|
|
5254
|
+
var import_react_native33 = require("react-native");
|
|
4199
5255
|
var import_react_native_safe_area_context4 = require("react-native-safe-area-context");
|
|
4200
5256
|
|
|
4201
5257
|
// src/overlay/AppProvider.tsx
|
|
4202
5258
|
var import_react_native_safe_area_context3 = require("react-native-safe-area-context");
|
|
4203
5259
|
|
|
4204
5260
|
// src/overlay/AppStatusBar.tsx
|
|
4205
|
-
var
|
|
5261
|
+
var import_react_native28 = require("react-native");
|
|
4206
5262
|
var import_native2 = require("@react-navigation/native");
|
|
4207
|
-
var
|
|
5263
|
+
var import_jsx_runtime39 = require("nativewind/jsx-runtime");
|
|
4208
5264
|
function AppStatusBar({
|
|
4209
5265
|
barStyle = "auto",
|
|
4210
5266
|
backgroundColor,
|
|
@@ -4214,8 +5270,8 @@ function AppStatusBar({
|
|
|
4214
5270
|
const { theme, isDark } = useTheme();
|
|
4215
5271
|
const resolvedBarStyle = barStyle === "auto" ? isDark ? "light-content" : "dark-content" : barStyle;
|
|
4216
5272
|
const resolvedBackgroundColor = backgroundColor ?? (translucent ? "transparent" : theme.colors.background?.[500] || "#ffffff");
|
|
4217
|
-
return /* @__PURE__ */ (0,
|
|
4218
|
-
|
|
5273
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(
|
|
5274
|
+
import_react_native28.StatusBar,
|
|
4219
5275
|
{
|
|
4220
5276
|
barStyle: resolvedBarStyle,
|
|
4221
5277
|
backgroundColor: resolvedBackgroundColor,
|
|
@@ -4227,31 +5283,58 @@ function AppStatusBar({
|
|
|
4227
5283
|
function AppFocusedStatusBar(props) {
|
|
4228
5284
|
const isFocused = (0, import_native2.useIsFocused)();
|
|
4229
5285
|
if (!isFocused) return null;
|
|
4230
|
-
return /* @__PURE__ */ (0,
|
|
5286
|
+
return /* @__PURE__ */ (0, import_jsx_runtime39.jsx)(AppStatusBar, { ...props });
|
|
4231
5287
|
}
|
|
4232
5288
|
|
|
4233
5289
|
// src/overlay/loading/provider.tsx
|
|
4234
|
-
var
|
|
5290
|
+
var import_react42 = require("react");
|
|
4235
5291
|
|
|
4236
5292
|
// src/overlay/loading/context.ts
|
|
4237
|
-
var
|
|
4238
|
-
var LoadingContext = (0,
|
|
5293
|
+
var import_react40 = require("react");
|
|
5294
|
+
var LoadingContext = (0, import_react40.createContext)(null);
|
|
4239
5295
|
function useLoadingContext() {
|
|
4240
|
-
const ctx = (0,
|
|
5296
|
+
const ctx = (0, import_react40.useContext)(LoadingContext);
|
|
4241
5297
|
if (!ctx) throw new Error("useLoading must be used within OverlayProvider");
|
|
4242
5298
|
return ctx;
|
|
4243
5299
|
}
|
|
4244
5300
|
|
|
4245
5301
|
// src/overlay/loading/component.tsx
|
|
4246
|
-
var
|
|
4247
|
-
var
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
5302
|
+
var import_react41 = require("react");
|
|
5303
|
+
var import_react_native29 = require("react-native");
|
|
5304
|
+
var import_jsx_runtime40 = require("nativewind/jsx-runtime");
|
|
5305
|
+
var LOADING_CLOSE_DELAY2 = 3e4;
|
|
5306
|
+
function LoadingModal({
|
|
5307
|
+
visible,
|
|
5308
|
+
text,
|
|
5309
|
+
onRequestClose
|
|
5310
|
+
}) {
|
|
5311
|
+
const [showCloseButton, setShowCloseButton] = (0, import_react41.useState)(false);
|
|
5312
|
+
(0, import_react41.useEffect)(() => {
|
|
5313
|
+
if (!visible) {
|
|
5314
|
+
setShowCloseButton(false);
|
|
5315
|
+
return;
|
|
5316
|
+
}
|
|
5317
|
+
setShowCloseButton(false);
|
|
5318
|
+
const timer = setTimeout(() => {
|
|
5319
|
+
setShowCloseButton(true);
|
|
5320
|
+
}, LOADING_CLOSE_DELAY2);
|
|
5321
|
+
return () => clearTimeout(timer);
|
|
5322
|
+
}, [visible]);
|
|
5323
|
+
return /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_react_native29.Modal, { transparent: true, visible, animationType: "fade", children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_react_native29.View, { style: styles14.overlay, children: /* @__PURE__ */ (0, import_jsx_runtime40.jsxs)(import_react_native29.View, { style: [styles14.loadingBox, { backgroundColor: "rgba(0,0,0,0.8)" }], children: [
|
|
5324
|
+
/* @__PURE__ */ (0, import_jsx_runtime40.jsx)(import_react_native29.ActivityIndicator, { size: "large", color: "#fff" }),
|
|
5325
|
+
text && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(AppText, { className: "text-white mt-3 text-sm", children: text }),
|
|
5326
|
+
showCloseButton && onRequestClose && /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(
|
|
5327
|
+
AppPressable,
|
|
5328
|
+
{
|
|
5329
|
+
testID: "loading-close",
|
|
5330
|
+
className: "mt-3 p-1",
|
|
5331
|
+
onPress: onRequestClose,
|
|
5332
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime40.jsx)(Icon, { name: "close", size: "md", color: "#ffffff" })
|
|
5333
|
+
}
|
|
5334
|
+
)
|
|
4252
5335
|
] }) }) });
|
|
4253
5336
|
}
|
|
4254
|
-
var
|
|
5337
|
+
var styles14 = import_react_native29.StyleSheet.create({
|
|
4255
5338
|
overlay: {
|
|
4256
5339
|
flex: 1,
|
|
4257
5340
|
backgroundColor: "rgba(0,0,0,0.5)",
|
|
@@ -4267,55 +5350,112 @@ var styles13 = import_react_native26.StyleSheet.create({
|
|
|
4267
5350
|
});
|
|
4268
5351
|
|
|
4269
5352
|
// src/overlay/loading/provider.tsx
|
|
4270
|
-
var
|
|
5353
|
+
var import_jsx_runtime41 = require("nativewind/jsx-runtime");
|
|
5354
|
+
var MIN_VISIBLE_DURATION = 500;
|
|
4271
5355
|
function LoadingProvider({ children }) {
|
|
4272
|
-
const [state, setState] = (0,
|
|
4273
|
-
const
|
|
4274
|
-
|
|
5356
|
+
const [state, setState] = (0, import_react42.useState)({ visible: false });
|
|
5357
|
+
const shownAtRef = (0, import_react42.useRef)(0);
|
|
5358
|
+
const pendingCountRef = (0, import_react42.useRef)(0);
|
|
5359
|
+
const hideTimerRef = (0, import_react42.useRef)(null);
|
|
5360
|
+
const clearHideTimer = (0, import_react42.useCallback)(() => {
|
|
5361
|
+
if (!hideTimerRef.current) return;
|
|
5362
|
+
clearTimeout(hideTimerRef.current);
|
|
5363
|
+
hideTimerRef.current = null;
|
|
4275
5364
|
}, []);
|
|
4276
|
-
const
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
5365
|
+
const show = (0, import_react42.useCallback)((text) => {
|
|
5366
|
+
pendingCountRef.current += 1;
|
|
5367
|
+
clearHideTimer();
|
|
5368
|
+
setState((previous) => {
|
|
5369
|
+
if (!previous.visible) {
|
|
5370
|
+
shownAtRef.current = Date.now();
|
|
5371
|
+
}
|
|
5372
|
+
return { visible: true, text };
|
|
5373
|
+
});
|
|
5374
|
+
}, [clearHideTimer]);
|
|
5375
|
+
const hide = (0, import_react42.useCallback)(() => {
|
|
5376
|
+
pendingCountRef.current = Math.max(0, pendingCountRef.current - 1);
|
|
5377
|
+
if (pendingCountRef.current > 0) return;
|
|
5378
|
+
const elapsed = Date.now() - shownAtRef.current;
|
|
5379
|
+
const remaining = Math.max(0, MIN_VISIBLE_DURATION - elapsed);
|
|
5380
|
+
clearHideTimer();
|
|
5381
|
+
if (remaining === 0) {
|
|
5382
|
+
setState({ visible: false });
|
|
5383
|
+
return;
|
|
5384
|
+
}
|
|
5385
|
+
hideTimerRef.current = setTimeout(() => {
|
|
5386
|
+
hideTimerRef.current = null;
|
|
5387
|
+
setState({ visible: false });
|
|
5388
|
+
}, remaining);
|
|
5389
|
+
}, [clearHideTimer]);
|
|
5390
|
+
(0, import_react42.useEffect)(() => () => clearHideTimer(), [clearHideTimer]);
|
|
5391
|
+
return /* @__PURE__ */ (0, import_jsx_runtime41.jsxs)(LoadingContext.Provider, { value: { show, hide }, children: [
|
|
4280
5392
|
children,
|
|
4281
|
-
/* @__PURE__ */ (0,
|
|
5393
|
+
/* @__PURE__ */ (0, import_jsx_runtime41.jsx)(LoadingModal, { ...state, onRequestClose: hide })
|
|
4282
5394
|
] });
|
|
4283
5395
|
}
|
|
4284
5396
|
|
|
4285
5397
|
// src/overlay/toast/provider.tsx
|
|
4286
|
-
var
|
|
4287
|
-
var
|
|
5398
|
+
var import_react45 = require("react");
|
|
5399
|
+
var import_react_native31 = require("react-native");
|
|
4288
5400
|
|
|
4289
5401
|
// src/overlay/toast/context.ts
|
|
4290
|
-
var
|
|
4291
|
-
var ToastContext = (0,
|
|
5402
|
+
var import_react43 = require("react");
|
|
5403
|
+
var ToastContext = (0, import_react43.createContext)(null);
|
|
4292
5404
|
function useToastContext() {
|
|
4293
|
-
const ctx = (0,
|
|
5405
|
+
const ctx = (0, import_react43.useContext)(ToastContext);
|
|
4294
5406
|
if (!ctx) throw new Error("useToast must be used within OverlayProvider");
|
|
4295
5407
|
return ctx;
|
|
4296
5408
|
}
|
|
4297
5409
|
|
|
4298
5410
|
// src/overlay/toast/component.tsx
|
|
4299
|
-
var
|
|
4300
|
-
var
|
|
4301
|
-
var
|
|
5411
|
+
var import_react44 = require("react");
|
|
5412
|
+
var import_react_native30 = require("react-native");
|
|
5413
|
+
var import_jsx_runtime42 = require("nativewind/jsx-runtime");
|
|
5414
|
+
function createAnimatedValue4(value) {
|
|
5415
|
+
const AnimatedValue = import_react_native30.Animated.Value;
|
|
5416
|
+
try {
|
|
5417
|
+
return new AnimatedValue(value);
|
|
5418
|
+
} catch {
|
|
5419
|
+
return AnimatedValue(value);
|
|
5420
|
+
}
|
|
5421
|
+
}
|
|
4302
5422
|
function ToastItemView({ message, type, onHide }) {
|
|
4303
|
-
const fadeAnim = (0,
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
5423
|
+
const fadeAnim = (0, import_react44.useRef)(createAnimatedValue4(0)).current;
|
|
5424
|
+
const { theme } = useOptionalTheme();
|
|
5425
|
+
(0, import_react44.useEffect)(() => {
|
|
5426
|
+
import_react_native30.Animated.sequence([
|
|
5427
|
+
import_react_native30.Animated.timing(fadeAnim, { toValue: 1, duration: 200, useNativeDriver: true }),
|
|
5428
|
+
import_react_native30.Animated.delay(2500),
|
|
5429
|
+
import_react_native30.Animated.timing(fadeAnim, { toValue: 0, duration: 200, useNativeDriver: true })
|
|
4309
5430
|
]).start(onHide);
|
|
4310
5431
|
}, []);
|
|
4311
|
-
const
|
|
4312
|
-
success:
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
5432
|
+
const palette = {
|
|
5433
|
+
success: {
|
|
5434
|
+
backgroundColor: theme.colors.success?.[500] || "#22c55e",
|
|
5435
|
+
textColor: "#ffffff"
|
|
5436
|
+
},
|
|
5437
|
+
error: {
|
|
5438
|
+
backgroundColor: theme.colors.error?.[500] || "#ef4444",
|
|
5439
|
+
textColor: "#ffffff"
|
|
5440
|
+
},
|
|
5441
|
+
warning: {
|
|
5442
|
+
backgroundColor: theme.colors.warning?.[500] || "#f59e0b",
|
|
5443
|
+
textColor: "#111827"
|
|
5444
|
+
},
|
|
5445
|
+
info: {
|
|
5446
|
+
backgroundColor: theme.colors.info?.[500] || theme.colors.primary?.[500] || "#3b82f6",
|
|
5447
|
+
textColor: "#ffffff"
|
|
5448
|
+
}
|
|
4316
5449
|
};
|
|
4317
|
-
|
|
4318
|
-
|
|
5450
|
+
const currentPalette = palette[type];
|
|
5451
|
+
const bgStyles = {
|
|
5452
|
+
success: "bg-green-500",
|
|
5453
|
+
error: "bg-red-500",
|
|
5454
|
+
warning: "bg-yellow-500",
|
|
5455
|
+
info: "bg-blue-500"
|
|
5456
|
+
};
|
|
5457
|
+
return /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
5458
|
+
import_react_native30.Animated.View,
|
|
4319
5459
|
{
|
|
4320
5460
|
style: {
|
|
4321
5461
|
opacity: fadeAnim,
|
|
@@ -4328,17 +5468,25 @@ function ToastItemView({ message, type, onHide }) {
|
|
|
4328
5468
|
}
|
|
4329
5469
|
]
|
|
4330
5470
|
},
|
|
4331
|
-
children: /* @__PURE__ */ (0,
|
|
5471
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(
|
|
5472
|
+
AppView,
|
|
5473
|
+
{
|
|
5474
|
+
testID: `toast-item-${type}`,
|
|
5475
|
+
className: `${bgStyles[type]} px-4 py-3 rounded-lg mb-2 mx-4 shadow-lg`,
|
|
5476
|
+
style: { backgroundColor: currentPalette.backgroundColor },
|
|
5477
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime42.jsx)(AppText, { className: "text-center", style: { color: currentPalette.textColor }, children: message })
|
|
5478
|
+
}
|
|
5479
|
+
)
|
|
4332
5480
|
}
|
|
4333
5481
|
);
|
|
4334
5482
|
}
|
|
4335
5483
|
|
|
4336
5484
|
// src/overlay/toast/provider.tsx
|
|
4337
|
-
var
|
|
5485
|
+
var import_jsx_runtime43 = require("nativewind/jsx-runtime");
|
|
4338
5486
|
function ToastProvider({ children }) {
|
|
4339
|
-
const [toasts, setToasts] = (0,
|
|
4340
|
-
const timersRef = (0,
|
|
4341
|
-
const remove = (0,
|
|
5487
|
+
const [toasts, setToasts] = (0, import_react45.useState)([]);
|
|
5488
|
+
const timersRef = (0, import_react45.useRef)(/* @__PURE__ */ new Map());
|
|
5489
|
+
const remove = (0, import_react45.useCallback)((id) => {
|
|
4342
5490
|
setToasts((prev) => prev.filter((t) => t.id !== id));
|
|
4343
5491
|
const timer = timersRef.current.get(id);
|
|
4344
5492
|
if (timer) {
|
|
@@ -4346,7 +5494,7 @@ function ToastProvider({ children }) {
|
|
|
4346
5494
|
timersRef.current.delete(id);
|
|
4347
5495
|
}
|
|
4348
5496
|
}, []);
|
|
4349
|
-
const show = (0,
|
|
5497
|
+
const show = (0, import_react45.useCallback)(
|
|
4350
5498
|
(message, type = "info", duration = 3e3) => {
|
|
4351
5499
|
const id = Math.random().toString(36).substring(7);
|
|
4352
5500
|
const toast = { id, message, type, duration };
|
|
@@ -4356,28 +5504,28 @@ function ToastProvider({ children }) {
|
|
|
4356
5504
|
},
|
|
4357
5505
|
[remove]
|
|
4358
5506
|
);
|
|
4359
|
-
const success = (0,
|
|
5507
|
+
const success = (0, import_react45.useCallback)(
|
|
4360
5508
|
(message, duration) => show(message, "success", duration),
|
|
4361
5509
|
[show]
|
|
4362
5510
|
);
|
|
4363
|
-
const error = (0,
|
|
5511
|
+
const error = (0, import_react45.useCallback)(
|
|
4364
5512
|
(message, duration) => show(message, "error", duration),
|
|
4365
5513
|
[show]
|
|
4366
5514
|
);
|
|
4367
|
-
const info = (0,
|
|
5515
|
+
const info = (0, import_react45.useCallback)(
|
|
4368
5516
|
(message, duration) => show(message, "info", duration),
|
|
4369
5517
|
[show]
|
|
4370
5518
|
);
|
|
4371
|
-
const warning = (0,
|
|
5519
|
+
const warning = (0, import_react45.useCallback)(
|
|
4372
5520
|
(message, duration) => show(message, "warning", duration),
|
|
4373
5521
|
[show]
|
|
4374
5522
|
);
|
|
4375
|
-
return /* @__PURE__ */ (0,
|
|
5523
|
+
return /* @__PURE__ */ (0, import_jsx_runtime43.jsxs)(ToastContext.Provider, { value: { show, success, error, info, warning }, children: [
|
|
4376
5524
|
children,
|
|
4377
|
-
/* @__PURE__ */ (0,
|
|
5525
|
+
/* @__PURE__ */ (0, import_jsx_runtime43.jsx)(import_react_native31.View, { style: styles15.toastContainer, pointerEvents: "none", children: toasts.map((toast) => /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(ToastItemView, { ...toast, onHide: () => remove(toast.id) }, toast.id)) })
|
|
4378
5526
|
] });
|
|
4379
5527
|
}
|
|
4380
|
-
var
|
|
5528
|
+
var styles15 = import_react_native31.StyleSheet.create({
|
|
4381
5529
|
toastContainer: {
|
|
4382
5530
|
position: "absolute",
|
|
4383
5531
|
top: 60,
|
|
@@ -4388,20 +5536,29 @@ var styles14 = import_react_native28.StyleSheet.create({
|
|
|
4388
5536
|
});
|
|
4389
5537
|
|
|
4390
5538
|
// src/overlay/alert/provider.tsx
|
|
4391
|
-
var
|
|
5539
|
+
var import_react48 = require("react");
|
|
4392
5540
|
|
|
4393
5541
|
// src/overlay/alert/context.ts
|
|
4394
|
-
var
|
|
4395
|
-
var AlertContext = (0,
|
|
5542
|
+
var import_react46 = require("react");
|
|
5543
|
+
var AlertContext = (0, import_react46.createContext)(null);
|
|
4396
5544
|
function useAlertContext() {
|
|
4397
|
-
const ctx = (0,
|
|
5545
|
+
const ctx = (0, import_react46.useContext)(AlertContext);
|
|
4398
5546
|
if (!ctx) throw new Error("useAlert must be used within OverlayProvider");
|
|
4399
5547
|
return ctx;
|
|
4400
5548
|
}
|
|
4401
5549
|
|
|
4402
5550
|
// src/overlay/alert/component.tsx
|
|
4403
|
-
var
|
|
4404
|
-
var
|
|
5551
|
+
var import_react47 = require("react");
|
|
5552
|
+
var import_react_native32 = require("react-native");
|
|
5553
|
+
var import_jsx_runtime44 = require("nativewind/jsx-runtime");
|
|
5554
|
+
function createAnimatedValue5(value) {
|
|
5555
|
+
const AnimatedValue = import_react_native32.Animated.Value;
|
|
5556
|
+
try {
|
|
5557
|
+
return new AnimatedValue(value);
|
|
5558
|
+
} catch {
|
|
5559
|
+
return AnimatedValue(value);
|
|
5560
|
+
}
|
|
5561
|
+
}
|
|
4405
5562
|
function AlertModal({
|
|
4406
5563
|
visible,
|
|
4407
5564
|
title,
|
|
@@ -4412,23 +5569,67 @@ function AlertModal({
|
|
|
4412
5569
|
onConfirm,
|
|
4413
5570
|
onCancel
|
|
4414
5571
|
}) {
|
|
5572
|
+
const progress = (0, import_react47.useRef)(createAnimatedValue5(0)).current;
|
|
5573
|
+
(0, import_react47.useEffect)(() => {
|
|
5574
|
+
if (!visible) {
|
|
5575
|
+
progress.setValue(0);
|
|
5576
|
+
return;
|
|
5577
|
+
}
|
|
5578
|
+
progress.setValue(0);
|
|
5579
|
+
import_react_native32.Animated.timing(progress, {
|
|
5580
|
+
toValue: 1,
|
|
5581
|
+
duration: 220,
|
|
5582
|
+
useNativeDriver: true
|
|
5583
|
+
}).start();
|
|
5584
|
+
}, [progress, visible]);
|
|
4415
5585
|
if (!visible) return null;
|
|
4416
|
-
return /* @__PURE__ */ (0,
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
5586
|
+
return /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native32.Modal, { transparent: true, visible: true, animationType: "none", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(import_react_native32.View, { style: styles16.container, children: [
|
|
5587
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(import_react_native32.Animated.View, { style: [styles16.overlay, { opacity: progress }] }),
|
|
5588
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(
|
|
5589
|
+
import_react_native32.Animated.View,
|
|
5590
|
+
{
|
|
5591
|
+
style: [
|
|
5592
|
+
styles16.alertBox,
|
|
5593
|
+
{
|
|
5594
|
+
opacity: progress,
|
|
5595
|
+
transform: [
|
|
5596
|
+
{
|
|
5597
|
+
translateY: progress.interpolate({
|
|
5598
|
+
inputRange: [0, 1],
|
|
5599
|
+
outputRange: [16, 0]
|
|
5600
|
+
})
|
|
5601
|
+
},
|
|
5602
|
+
{
|
|
5603
|
+
scale: progress.interpolate({
|
|
5604
|
+
inputRange: [0, 1],
|
|
5605
|
+
outputRange: [0.96, 1]
|
|
5606
|
+
})
|
|
5607
|
+
}
|
|
5608
|
+
]
|
|
5609
|
+
}
|
|
5610
|
+
],
|
|
5611
|
+
children: [
|
|
5612
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AppText, { className: "text-lg font-semibold text-center mb-2", children: title }),
|
|
5613
|
+
message && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AppText, { className: "text-gray-600 text-center mb-4", children: message }),
|
|
5614
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsxs)(AppView, { row: true, gap: 3, className: "mt-2", children: [
|
|
5615
|
+
showCancel && /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AppPressable, { onPress: onCancel, className: "flex-1 py-3 bg-gray-100 rounded-lg", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AppText, { className: "text-center text-gray-700", children: cancelText || "\u53D6\u6D88" }) }),
|
|
5616
|
+
/* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AppPressable, { onPress: onConfirm, className: "flex-1 py-3 bg-primary-500 rounded-lg", children: /* @__PURE__ */ (0, import_jsx_runtime44.jsx)(AppText, { className: "text-center text-white", children: confirmText || "\u786E\u5B9A" }) })
|
|
5617
|
+
] })
|
|
5618
|
+
]
|
|
5619
|
+
}
|
|
5620
|
+
)
|
|
5621
|
+
] }) });
|
|
4424
5622
|
}
|
|
4425
|
-
var
|
|
4426
|
-
|
|
5623
|
+
var styles16 = import_react_native32.StyleSheet.create({
|
|
5624
|
+
container: {
|
|
4427
5625
|
flex: 1,
|
|
4428
|
-
backgroundColor: "rgba(0,0,0,0.5)",
|
|
4429
5626
|
justifyContent: "center",
|
|
4430
5627
|
alignItems: "center"
|
|
4431
5628
|
},
|
|
5629
|
+
overlay: {
|
|
5630
|
+
...import_react_native32.StyleSheet.absoluteFillObject,
|
|
5631
|
+
backgroundColor: "rgba(0,0,0,0.5)"
|
|
5632
|
+
},
|
|
4432
5633
|
alertBox: {
|
|
4433
5634
|
backgroundColor: "white",
|
|
4434
5635
|
borderRadius: 12,
|
|
@@ -4444,32 +5645,32 @@ var styles15 = import_react_native29.StyleSheet.create({
|
|
|
4444
5645
|
});
|
|
4445
5646
|
|
|
4446
5647
|
// src/overlay/alert/provider.tsx
|
|
4447
|
-
var
|
|
5648
|
+
var import_jsx_runtime45 = require("nativewind/jsx-runtime");
|
|
4448
5649
|
function AlertProvider({ children }) {
|
|
4449
|
-
const [alert, setAlert] = (0,
|
|
4450
|
-
const showAlert = (0,
|
|
5650
|
+
const [alert, setAlert] = (0, import_react48.useState)(null);
|
|
5651
|
+
const showAlert = (0, import_react48.useCallback)((options) => {
|
|
4451
5652
|
setAlert({ ...options, visible: true });
|
|
4452
5653
|
}, []);
|
|
4453
|
-
const confirm = (0,
|
|
5654
|
+
const confirm = (0, import_react48.useCallback)(
|
|
4454
5655
|
(options) => {
|
|
4455
5656
|
showAlert({ ...options, showCancel: true });
|
|
4456
5657
|
},
|
|
4457
5658
|
[showAlert]
|
|
4458
5659
|
);
|
|
4459
|
-
const hide = (0,
|
|
5660
|
+
const hide = (0, import_react48.useCallback)(() => {
|
|
4460
5661
|
setAlert(null);
|
|
4461
5662
|
}, []);
|
|
4462
|
-
const handleConfirm = (0,
|
|
5663
|
+
const handleConfirm = (0, import_react48.useCallback)(() => {
|
|
4463
5664
|
alert?.onConfirm?.();
|
|
4464
5665
|
hide();
|
|
4465
5666
|
}, [alert, hide]);
|
|
4466
|
-
const handleCancel = (0,
|
|
5667
|
+
const handleCancel = (0, import_react48.useCallback)(() => {
|
|
4467
5668
|
alert?.onCancel?.();
|
|
4468
5669
|
hide();
|
|
4469
5670
|
}, [alert, hide]);
|
|
4470
|
-
return /* @__PURE__ */ (0,
|
|
5671
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(AlertContext.Provider, { value: { alert: showAlert, confirm }, children: [
|
|
4471
5672
|
children,
|
|
4472
|
-
/* @__PURE__ */ (0,
|
|
5673
|
+
/* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
4473
5674
|
AlertModal,
|
|
4474
5675
|
{
|
|
4475
5676
|
visible: alert?.visible ?? false,
|
|
@@ -4485,14 +5686,378 @@ function AlertProvider({ children }) {
|
|
|
4485
5686
|
] });
|
|
4486
5687
|
}
|
|
4487
5688
|
|
|
5689
|
+
// src/overlay/logger/provider.tsx
|
|
5690
|
+
var import_react51 = require("react");
|
|
5691
|
+
|
|
5692
|
+
// src/overlay/logger/context.ts
|
|
5693
|
+
var import_react49 = require("react");
|
|
5694
|
+
var LoggerContext = (0, import_react49.createContext)(null);
|
|
5695
|
+
function useLoggerContext() {
|
|
5696
|
+
const ctx = (0, import_react49.useContext)(LoggerContext);
|
|
5697
|
+
if (!ctx) throw new Error("useLogger must be used within LoggerProvider");
|
|
5698
|
+
return ctx;
|
|
5699
|
+
}
|
|
5700
|
+
|
|
5701
|
+
// src/overlay/logger/component.tsx
|
|
5702
|
+
var import_react50 = require("react");
|
|
5703
|
+
var import_jsx_runtime46 = require("nativewind/jsx-runtime");
|
|
5704
|
+
var FILTERS = ["all", "error", "warn", "info", "debug"];
|
|
5705
|
+
var ALL_NAMESPACE = "all";
|
|
5706
|
+
var DEFAULT_SEARCH_PLACEHOLDER = "\u641C\u7D22\u65E5\u5FD7";
|
|
5707
|
+
function withAlpha(color, alpha = "20") {
|
|
5708
|
+
return color.startsWith("#") && color.length === 7 ? `${color}${alpha}` : color;
|
|
5709
|
+
}
|
|
5710
|
+
function matchesSearch(entry, keyword) {
|
|
5711
|
+
if (!keyword.trim()) return true;
|
|
5712
|
+
const normalized = keyword.trim().toLowerCase();
|
|
5713
|
+
const detail = stringifyLogData(entry.data).toLowerCase();
|
|
5714
|
+
return [entry.message, entry.namespace ?? "", detail].join(" ").toLowerCase().includes(normalized);
|
|
5715
|
+
}
|
|
5716
|
+
function LogOverlay({
|
|
5717
|
+
entries,
|
|
5718
|
+
onClear,
|
|
5719
|
+
defaultExpanded = false,
|
|
5720
|
+
exportEnabled = true,
|
|
5721
|
+
onExport
|
|
5722
|
+
}) {
|
|
5723
|
+
const colors = useThemeColors();
|
|
5724
|
+
const [expanded, setExpanded] = (0, import_react50.useState)(defaultExpanded);
|
|
5725
|
+
const [filter, setFilter] = (0, import_react50.useState)("all");
|
|
5726
|
+
const [namespaceFilter, setNamespaceFilter] = (0, import_react50.useState)(ALL_NAMESPACE);
|
|
5727
|
+
const [keyword, setKeyword] = (0, import_react50.useState)("");
|
|
5728
|
+
const namespaces = (0, import_react50.useMemo)(
|
|
5729
|
+
() => [
|
|
5730
|
+
ALL_NAMESPACE,
|
|
5731
|
+
...Array.from(
|
|
5732
|
+
new Set(
|
|
5733
|
+
entries.map((entry) => entry.namespace).filter((value) => Boolean(value))
|
|
5734
|
+
)
|
|
5735
|
+
)
|
|
5736
|
+
],
|
|
5737
|
+
[entries]
|
|
5738
|
+
);
|
|
5739
|
+
const filteredEntries = (0, import_react50.useMemo)(() => {
|
|
5740
|
+
return entries.filter((entry) => {
|
|
5741
|
+
const levelMatched = filter === "all" ? true : entry.level === filter;
|
|
5742
|
+
const namespaceMatched = namespaceFilter === ALL_NAMESPACE ? true : entry.namespace === namespaceFilter;
|
|
5743
|
+
const searchMatched = matchesSearch(entry, keyword);
|
|
5744
|
+
return levelMatched && namespaceMatched && searchMatched;
|
|
5745
|
+
});
|
|
5746
|
+
}, [entries, filter, keyword, namespaceFilter]);
|
|
5747
|
+
const levelStyles = {
|
|
5748
|
+
debug: { text: colors.muted, bg: colors.cardElevated },
|
|
5749
|
+
info: { text: colors.info, bg: withAlpha(colors.info) },
|
|
5750
|
+
warn: { text: colors.warning, bg: withAlpha(colors.warning) },
|
|
5751
|
+
error: { text: colors.error, bg: withAlpha(colors.error) }
|
|
5752
|
+
};
|
|
5753
|
+
const handleExport = () => {
|
|
5754
|
+
const payload = {
|
|
5755
|
+
entries: filteredEntries,
|
|
5756
|
+
serialized: serializeLogEntries(filteredEntries)
|
|
5757
|
+
};
|
|
5758
|
+
if (onExport) {
|
|
5759
|
+
onExport(payload);
|
|
5760
|
+
return;
|
|
5761
|
+
}
|
|
5762
|
+
console.info("[LoggerExport]", payload.serialized);
|
|
5763
|
+
};
|
|
5764
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(AppView, { pointerEvents: "box-none", style: { position: "absolute", right: 12, bottom: 24, left: 12, zIndex: 9998 }, children: [
|
|
5765
|
+
expanded && /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
5766
|
+
AppView,
|
|
5767
|
+
{
|
|
5768
|
+
testID: "logger-overlay-panel",
|
|
5769
|
+
style: {
|
|
5770
|
+
maxHeight: 360,
|
|
5771
|
+
borderRadius: 16,
|
|
5772
|
+
backgroundColor: colors.card,
|
|
5773
|
+
borderWidth: 0.5,
|
|
5774
|
+
borderColor: colors.border,
|
|
5775
|
+
shadowColor: "#000000",
|
|
5776
|
+
shadowOpacity: 0.15,
|
|
5777
|
+
shadowRadius: 16,
|
|
5778
|
+
shadowOffset: { width: 0, height: 8 },
|
|
5779
|
+
elevation: 12,
|
|
5780
|
+
marginBottom: 12
|
|
5781
|
+
},
|
|
5782
|
+
children: [
|
|
5783
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(AppView, { row: true, items: "center", justify: "between", className: "px-4 py-3", style: { borderBottomWidth: 0.5, borderBottomColor: colors.divider }, children: [
|
|
5784
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppText, { weight: "semibold", children: "\u5F00\u53D1\u65E5\u5FD7" }),
|
|
5785
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(AppView, { row: true, gap: 2, children: [
|
|
5786
|
+
exportEnabled ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppPressable, { testID: "logger-overlay-export", onPress: handleExport, className: "px-3 py-1 rounded-full", style: { backgroundColor: colors.cardElevated }, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppText, { size: "xs", tone: "muted", children: "\u5BFC\u51FA" }) }) : null,
|
|
5787
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppPressable, { onPress: onClear, className: "px-3 py-1 rounded-full", style: { backgroundColor: colors.cardElevated }, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppText, { size: "xs", tone: "muted", children: "\u6E05\u7A7A" }) }),
|
|
5788
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppPressable, { onPress: () => setExpanded(false), className: "px-3 py-1 rounded-full", style: { backgroundColor: colors.cardElevated }, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppText, { size: "xs", tone: "muted", children: "\u6536\u8D77" }) })
|
|
5789
|
+
] })
|
|
5790
|
+
] }),
|
|
5791
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, className: "px-3 py-2", contentContainerStyle: { gap: 8 }, children: FILTERS.map((item) => {
|
|
5792
|
+
const active = filter === item;
|
|
5793
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
5794
|
+
AppPressable,
|
|
5795
|
+
{
|
|
5796
|
+
onPress: () => setFilter(item),
|
|
5797
|
+
className: "px-3 py-1 rounded-full",
|
|
5798
|
+
style: { backgroundColor: active ? colors.primary : colors.cardElevated },
|
|
5799
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppText, { size: "xs", style: { color: active ? colors.textInverse : colors.textSecondary }, children: item.toUpperCase() })
|
|
5800
|
+
},
|
|
5801
|
+
item
|
|
5802
|
+
);
|
|
5803
|
+
}) }),
|
|
5804
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppScrollView, { horizontal: true, showsHorizontalScrollIndicator: false, className: "px-3 pb-2", contentContainerStyle: { gap: 8 }, children: namespaces.map((item) => {
|
|
5805
|
+
const active = namespaceFilter === item;
|
|
5806
|
+
const label = item === ALL_NAMESPACE ? "\u5168\u90E8\u6A21\u5757" : String(item);
|
|
5807
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
5808
|
+
AppPressable,
|
|
5809
|
+
{
|
|
5810
|
+
testID: `logger-namespace-${item}`,
|
|
5811
|
+
onPress: () => setNamespaceFilter(item),
|
|
5812
|
+
className: "px-3 py-1 rounded-full",
|
|
5813
|
+
style: { backgroundColor: active ? colors.info : colors.cardElevated },
|
|
5814
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppText, { size: "xs", style: { color: active ? colors.textInverse : colors.textSecondary }, children: label })
|
|
5815
|
+
},
|
|
5816
|
+
item
|
|
5817
|
+
);
|
|
5818
|
+
}) }),
|
|
5819
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppView, { className: "px-3 pb-2", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
5820
|
+
AppInput,
|
|
5821
|
+
{
|
|
5822
|
+
placeholder: DEFAULT_SEARCH_PLACEHOLDER,
|
|
5823
|
+
value: keyword,
|
|
5824
|
+
onChangeText: setKeyword
|
|
5825
|
+
}
|
|
5826
|
+
) }),
|
|
5827
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppScrollView, { className: "px-3 pb-3", showsVerticalScrollIndicator: false, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppView, { gap: 2, children: filteredEntries.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppView, { className: "py-8 items-center", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppText, { tone: "muted", children: "\u6682\u65E0\u65E5\u5FD7" }) }) : filteredEntries.map((entry) => {
|
|
5828
|
+
const palette = levelStyles[entry.level];
|
|
5829
|
+
const detail = stringifyLogData(entry.data);
|
|
5830
|
+
return /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(
|
|
5831
|
+
AppView,
|
|
5832
|
+
{
|
|
5833
|
+
className: "px-3 py-3 rounded-xl",
|
|
5834
|
+
style: { backgroundColor: colors.cardElevated, borderWidth: 0.5, borderColor: colors.divider },
|
|
5835
|
+
children: [
|
|
5836
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(AppView, { row: true, items: "center", justify: "between", children: [
|
|
5837
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(AppView, { row: true, items: "center", gap: 2, children: [
|
|
5838
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppView, { className: "px-2 py-1 rounded-full", style: { backgroundColor: palette.bg }, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppText, { size: "xs", style: { color: palette.text }, children: entry.level.toUpperCase() }) }),
|
|
5839
|
+
entry.namespace ? /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(AppText, { size: "xs", tone: "muted", children: [
|
|
5840
|
+
"[",
|
|
5841
|
+
entry.namespace,
|
|
5842
|
+
"]"
|
|
5843
|
+
] }) : null
|
|
5844
|
+
] }),
|
|
5845
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppText, { size: "xs", tone: "muted", children: formatLogTime(entry.timestamp) })
|
|
5846
|
+
] }),
|
|
5847
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppText, { className: "mt-2", size: "sm", children: entry.message }),
|
|
5848
|
+
detail ? /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppView, { className: "mt-2 px-2 py-2 rounded-lg", style: { backgroundColor: colors.background }, children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppText, { size: "xs", tone: "muted", children: detail }) }) : null
|
|
5849
|
+
]
|
|
5850
|
+
},
|
|
5851
|
+
entry.id
|
|
5852
|
+
);
|
|
5853
|
+
}) }) })
|
|
5854
|
+
]
|
|
5855
|
+
}
|
|
5856
|
+
),
|
|
5857
|
+
/* @__PURE__ */ (0, import_jsx_runtime46.jsx)(AppView, { pointerEvents: "box-none", row: true, justify: "end", children: /* @__PURE__ */ (0, import_jsx_runtime46.jsx)(
|
|
5858
|
+
AppPressable,
|
|
5859
|
+
{
|
|
5860
|
+
testID: "logger-overlay-toggle",
|
|
5861
|
+
onPress: () => setExpanded((value) => !value),
|
|
5862
|
+
className: "px-4 py-3 rounded-full",
|
|
5863
|
+
style: { backgroundColor: colors.primary, shadowColor: "#000000", shadowOpacity: 0.18, shadowRadius: 12, shadowOffset: { width: 0, height: 4 }, elevation: 8 },
|
|
5864
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime46.jsxs)(AppText, { weight: "semibold", style: { color: colors.textInverse }, children: [
|
|
5865
|
+
"Logs ",
|
|
5866
|
+
entries.length
|
|
5867
|
+
] })
|
|
5868
|
+
}
|
|
5869
|
+
) })
|
|
5870
|
+
] });
|
|
5871
|
+
}
|
|
5872
|
+
|
|
5873
|
+
// src/overlay/logger/provider.tsx
|
|
5874
|
+
var import_jsx_runtime47 = require("nativewind/jsx-runtime");
|
|
5875
|
+
function LoggerProvider({
|
|
5876
|
+
children,
|
|
5877
|
+
enabled = false,
|
|
5878
|
+
level = "debug",
|
|
5879
|
+
maxEntries = 200,
|
|
5880
|
+
overlayEnabled = false,
|
|
5881
|
+
defaultExpanded = false,
|
|
5882
|
+
consoleEnabled = true,
|
|
5883
|
+
transports = [],
|
|
5884
|
+
exportEnabled = true,
|
|
5885
|
+
onExport
|
|
5886
|
+
}) {
|
|
5887
|
+
const [entries, setEntries] = (0, import_react51.useState)([]);
|
|
5888
|
+
const clear = (0, import_react51.useCallback)(() => {
|
|
5889
|
+
setEntries([]);
|
|
5890
|
+
}, []);
|
|
5891
|
+
const resolvedTransports = (0, import_react51.useMemo)(() => {
|
|
5892
|
+
const list = [];
|
|
5893
|
+
if (enabled && consoleEnabled) {
|
|
5894
|
+
list.push(createConsoleTransport());
|
|
5895
|
+
}
|
|
5896
|
+
if (transports.length > 0) {
|
|
5897
|
+
list.push(...transports);
|
|
5898
|
+
}
|
|
5899
|
+
return list;
|
|
5900
|
+
}, [consoleEnabled, enabled, transports]);
|
|
5901
|
+
const write = (0, import_react51.useCallback)(
|
|
5902
|
+
(nextLevel, message, data, namespace) => {
|
|
5903
|
+
if (!enabled || !shouldLog(level, nextLevel)) return;
|
|
5904
|
+
const entry = createLogEntry({ level: nextLevel, message, data, namespace, source: "logger" });
|
|
5905
|
+
setEntries((prev) => [entry, ...prev].slice(0, maxEntries));
|
|
5906
|
+
resolvedTransports.forEach((transport) => transport(entry));
|
|
5907
|
+
},
|
|
5908
|
+
[enabled, level, maxEntries, resolvedTransports]
|
|
5909
|
+
);
|
|
5910
|
+
const contextValue = (0, import_react51.useMemo)(
|
|
5911
|
+
() => ({
|
|
5912
|
+
entries,
|
|
5913
|
+
enabled,
|
|
5914
|
+
level,
|
|
5915
|
+
clear,
|
|
5916
|
+
log: write,
|
|
5917
|
+
debug: (message, data, namespace) => write("debug", message, data, namespace),
|
|
5918
|
+
info: (message, data, namespace) => write("info", message, data, namespace),
|
|
5919
|
+
warn: (message, data, namespace) => write("warn", message, data, namespace),
|
|
5920
|
+
error: (message, data, namespace) => write("error", message, data, namespace)
|
|
5921
|
+
}),
|
|
5922
|
+
[clear, enabled, entries, level, write]
|
|
5923
|
+
);
|
|
5924
|
+
(0, import_react51.useEffect)(() => {
|
|
5925
|
+
if (!enabled) {
|
|
5926
|
+
setGlobalLogger(null);
|
|
5927
|
+
return;
|
|
5928
|
+
}
|
|
5929
|
+
setGlobalLogger(contextValue);
|
|
5930
|
+
return () => {
|
|
5931
|
+
setGlobalLogger(null);
|
|
5932
|
+
};
|
|
5933
|
+
}, [contextValue, enabled]);
|
|
5934
|
+
return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(LoggerContext.Provider, { value: contextValue, children: [
|
|
5935
|
+
children,
|
|
5936
|
+
enabled && overlayEnabled ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(
|
|
5937
|
+
LogOverlay,
|
|
5938
|
+
{
|
|
5939
|
+
entries,
|
|
5940
|
+
onClear: clear,
|
|
5941
|
+
defaultExpanded,
|
|
5942
|
+
exportEnabled,
|
|
5943
|
+
onExport
|
|
5944
|
+
}
|
|
5945
|
+
) : null
|
|
5946
|
+
] });
|
|
5947
|
+
}
|
|
5948
|
+
|
|
5949
|
+
// src/overlay/error-boundary/component.tsx
|
|
5950
|
+
var import_react52 = __toESM(require("react"));
|
|
5951
|
+
var import_jsx_runtime48 = require("nativewind/jsx-runtime");
|
|
5952
|
+
function areResetKeysChanged(prev = [], next = []) {
|
|
5953
|
+
if (prev.length !== next.length) return true;
|
|
5954
|
+
return prev.some((item, index) => !Object.is(item, next[index]));
|
|
5955
|
+
}
|
|
5956
|
+
function DefaultFallback({
|
|
5957
|
+
error,
|
|
5958
|
+
onReset,
|
|
5959
|
+
title = "\u9875\u9762\u53D1\u751F\u5F02\u5E38",
|
|
5960
|
+
description = "\u5DF2\u81EA\u52A8\u6355\u83B7\u6E32\u67D3\u9519\u8BEF\uFF0C\u4F60\u53EF\u4EE5\u91CD\u8BD5\u5E76\u7ED3\u5408\u5F00\u53D1\u65E5\u5FD7\u7EE7\u7EED\u6392\u67E5\u3002",
|
|
5961
|
+
resetText = "\u91CD\u8BD5",
|
|
5962
|
+
showDetails = isDevelopment()
|
|
5963
|
+
}) {
|
|
5964
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(AppView, { testID: "app-error-boundary", flex: true, center: true, className: "px-6 py-8", gap: 4, children: [
|
|
5965
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(AppView, { className: "items-center", gap: 2, children: [
|
|
5966
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(AppText, { size: "xl", weight: "semibold", children: title }),
|
|
5967
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(AppText, { tone: "muted", style: { textAlign: "center" }, children: description })
|
|
5968
|
+
] }),
|
|
5969
|
+
showDetails ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
5970
|
+
AppView,
|
|
5971
|
+
{
|
|
5972
|
+
className: "w-full px-4 py-3 rounded-xl",
|
|
5973
|
+
style: { maxWidth: 560, borderWidth: 0.5 },
|
|
5974
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(AppText, { testID: "app-error-boundary-detail", size: "sm", children: error.message || String(error) })
|
|
5975
|
+
}
|
|
5976
|
+
) : null,
|
|
5977
|
+
/* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
5978
|
+
AppPressable,
|
|
5979
|
+
{
|
|
5980
|
+
testID: "app-error-boundary-reset",
|
|
5981
|
+
onPress: onReset,
|
|
5982
|
+
className: "px-4 py-3 rounded-lg",
|
|
5983
|
+
style: { borderWidth: 0.5 },
|
|
5984
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(AppText, { weight: "semibold", children: resetText })
|
|
5985
|
+
}
|
|
5986
|
+
)
|
|
5987
|
+
] });
|
|
5988
|
+
}
|
|
5989
|
+
var AppErrorBoundary = class extends import_react52.default.Component {
|
|
5990
|
+
constructor() {
|
|
5991
|
+
super(...arguments);
|
|
5992
|
+
this.state = {
|
|
5993
|
+
error: null
|
|
5994
|
+
};
|
|
5995
|
+
this.handleReset = () => {
|
|
5996
|
+
this.setState({ error: null });
|
|
5997
|
+
this.props.onReset?.();
|
|
5998
|
+
};
|
|
5999
|
+
}
|
|
6000
|
+
static getDerivedStateFromError(error) {
|
|
6001
|
+
return { error };
|
|
6002
|
+
}
|
|
6003
|
+
componentDidCatch(error, errorInfo) {
|
|
6004
|
+
this.context?.error(
|
|
6005
|
+
"React ErrorBoundary \u6355\u83B7\u6E32\u67D3\u5F02\u5E38",
|
|
6006
|
+
{
|
|
6007
|
+
name: error.name,
|
|
6008
|
+
message: error.message,
|
|
6009
|
+
stack: error.stack,
|
|
6010
|
+
componentStack: errorInfo.componentStack
|
|
6011
|
+
},
|
|
6012
|
+
"react"
|
|
6013
|
+
);
|
|
6014
|
+
this.props.onError?.(error, errorInfo);
|
|
6015
|
+
}
|
|
6016
|
+
componentDidUpdate(prevProps) {
|
|
6017
|
+
if (!this.state.error) return;
|
|
6018
|
+
if (areResetKeysChanged(prevProps.resetKeys, this.props.resetKeys)) {
|
|
6019
|
+
this.handleReset();
|
|
6020
|
+
}
|
|
6021
|
+
}
|
|
6022
|
+
render() {
|
|
6023
|
+
const {
|
|
6024
|
+
children,
|
|
6025
|
+
enabled = false,
|
|
6026
|
+
fallback,
|
|
6027
|
+
title,
|
|
6028
|
+
description,
|
|
6029
|
+
showDetails,
|
|
6030
|
+
resetText
|
|
6031
|
+
} = this.props;
|
|
6032
|
+
if (!enabled) return children;
|
|
6033
|
+
if (!this.state.error) return children;
|
|
6034
|
+
if (typeof fallback === "function") {
|
|
6035
|
+
return fallback({ error: this.state.error, reset: this.handleReset });
|
|
6036
|
+
}
|
|
6037
|
+
if (fallback) return fallback;
|
|
6038
|
+
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
6039
|
+
DefaultFallback,
|
|
6040
|
+
{
|
|
6041
|
+
error: this.state.error,
|
|
6042
|
+
onReset: this.handleReset,
|
|
6043
|
+
title,
|
|
6044
|
+
description,
|
|
6045
|
+
showDetails,
|
|
6046
|
+
resetText
|
|
6047
|
+
}
|
|
6048
|
+
);
|
|
6049
|
+
}
|
|
6050
|
+
};
|
|
6051
|
+
AppErrorBoundary.contextType = LoggerContext;
|
|
6052
|
+
|
|
4488
6053
|
// src/overlay/provider.tsx
|
|
4489
|
-
var
|
|
4490
|
-
function OverlayProvider({ children }) {
|
|
4491
|
-
return /* @__PURE__ */ (0,
|
|
6054
|
+
var import_jsx_runtime49 = require("nativewind/jsx-runtime");
|
|
6055
|
+
function OverlayProvider({ children, loggerProps, errorBoundaryProps }) {
|
|
6056
|
+
return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(LoggerProvider, { ...loggerProps, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(AppErrorBoundary, { ...errorBoundaryProps, children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(LoadingProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(ToastProvider, { children: /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(AlertProvider, { children }) }) }) }) });
|
|
4492
6057
|
}
|
|
4493
6058
|
|
|
4494
6059
|
// src/overlay/AppProvider.tsx
|
|
4495
|
-
var
|
|
6060
|
+
var import_jsx_runtime50 = require("nativewind/jsx-runtime");
|
|
4496
6061
|
var defaultLightTheme = {
|
|
4497
6062
|
colors: {
|
|
4498
6063
|
primary: "#f38b32",
|
|
@@ -4518,6 +6083,8 @@ function AppProvider({
|
|
|
4518
6083
|
enableNavigation = true,
|
|
4519
6084
|
enableOverlay = true,
|
|
4520
6085
|
enableTheme = true,
|
|
6086
|
+
enableLogger = isDevelopment(),
|
|
6087
|
+
enableErrorBoundary = isDevelopment(),
|
|
4521
6088
|
enableStatusBar = true,
|
|
4522
6089
|
enableSafeArea = true,
|
|
4523
6090
|
lightTheme = defaultLightTheme,
|
|
@@ -4525,25 +6092,41 @@ function AppProvider({
|
|
|
4525
6092
|
defaultDark = false,
|
|
4526
6093
|
isDark,
|
|
4527
6094
|
statusBarProps,
|
|
6095
|
+
loggerProps,
|
|
6096
|
+
errorBoundaryProps,
|
|
4528
6097
|
...navigationProps
|
|
4529
6098
|
}) {
|
|
4530
6099
|
let content = children;
|
|
4531
6100
|
if (enableOverlay) {
|
|
4532
|
-
content = /* @__PURE__ */ (0,
|
|
6101
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
|
|
6102
|
+
OverlayProvider,
|
|
6103
|
+
{
|
|
6104
|
+
loggerProps: enableLogger ? { enabled: true, overlayEnabled: true, ...loggerProps } : { enabled: false, overlayEnabled: false, ...loggerProps },
|
|
6105
|
+
errorBoundaryProps: enableErrorBoundary ? { enabled: true, ...errorBoundaryProps } : { enabled: false, ...errorBoundaryProps },
|
|
6106
|
+
children: content
|
|
6107
|
+
}
|
|
6108
|
+
);
|
|
6109
|
+
} else {
|
|
6110
|
+
if (enableErrorBoundary) {
|
|
6111
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(AppErrorBoundary, { enabled: true, ...errorBoundaryProps, children: content });
|
|
6112
|
+
}
|
|
6113
|
+
if (enableLogger) {
|
|
6114
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(LoggerProvider, { enabled: true, overlayEnabled: true, ...loggerProps, children: content });
|
|
6115
|
+
}
|
|
4533
6116
|
}
|
|
4534
6117
|
if (enableNavigation) {
|
|
4535
|
-
content = /* @__PURE__ */ (0,
|
|
6118
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(NavigationProvider, { ...navigationProps, children: content });
|
|
4536
6119
|
}
|
|
4537
6120
|
if (enableTheme) {
|
|
4538
|
-
content = /* @__PURE__ */ (0,
|
|
4539
|
-
enableStatusBar && /* @__PURE__ */ (0,
|
|
6121
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ThemeProvider, { light: lightTheme, dark: darkTheme, defaultDark, isDark, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_jsx_runtime50.Fragment, { children: [
|
|
6122
|
+
enableStatusBar && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(AppStatusBar, { testID: "status-bar", ...statusBarProps }),
|
|
4540
6123
|
content
|
|
4541
6124
|
] }) });
|
|
4542
6125
|
}
|
|
4543
6126
|
if (enableSafeArea) {
|
|
4544
|
-
content = /* @__PURE__ */ (0,
|
|
6127
|
+
content = /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_react_native_safe_area_context3.SafeAreaProvider, { children: content });
|
|
4545
6128
|
}
|
|
4546
|
-
return /* @__PURE__ */ (0,
|
|
6129
|
+
return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(import_jsx_runtime50.Fragment, { children: content });
|
|
4547
6130
|
}
|
|
4548
6131
|
|
|
4549
6132
|
// src/overlay/loading/hooks.ts
|
|
@@ -4561,8 +6144,29 @@ function useAlert() {
|
|
|
4561
6144
|
return useAlertContext();
|
|
4562
6145
|
}
|
|
4563
6146
|
|
|
6147
|
+
// src/overlay/logger/hooks.ts
|
|
6148
|
+
var import_react53 = require("react");
|
|
6149
|
+
function useLogger(namespace) {
|
|
6150
|
+
const logger = useLoggerContext();
|
|
6151
|
+
return (0, import_react53.useMemo)(
|
|
6152
|
+
() => ({
|
|
6153
|
+
entries: logger.entries,
|
|
6154
|
+
enabled: logger.enabled,
|
|
6155
|
+
level: logger.level,
|
|
6156
|
+
clear: logger.clear,
|
|
6157
|
+
namespace,
|
|
6158
|
+
log: (level, message, data) => logger.log(level, message, data, namespace),
|
|
6159
|
+
debug: (message, data) => logger.debug(message, data, namespace),
|
|
6160
|
+
info: (message, data) => logger.info(message, data, namespace),
|
|
6161
|
+
warn: (message, data) => logger.warn(message, data, namespace),
|
|
6162
|
+
error: (message, data) => logger.error(message, data, namespace)
|
|
6163
|
+
}),
|
|
6164
|
+
[logger, namespace]
|
|
6165
|
+
);
|
|
6166
|
+
}
|
|
6167
|
+
|
|
4564
6168
|
// src/navigation/components/AppHeader.tsx
|
|
4565
|
-
var
|
|
6169
|
+
var import_jsx_runtime51 = require("nativewind/jsx-runtime");
|
|
4566
6170
|
function AppHeader({
|
|
4567
6171
|
title,
|
|
4568
6172
|
subtitle,
|
|
@@ -4576,9 +6180,9 @@ function AppHeader({
|
|
|
4576
6180
|
const colors = useThemeColors();
|
|
4577
6181
|
const insets = (0, import_react_native_safe_area_context4.useSafeAreaInsets)();
|
|
4578
6182
|
const backgroundColor = transparent ? "transparent" : colors.card;
|
|
4579
|
-
return /* @__PURE__ */ (0,
|
|
4580
|
-
/* @__PURE__ */ (0,
|
|
4581
|
-
/* @__PURE__ */ (0,
|
|
6183
|
+
return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_jsx_runtime51.Fragment, { children: [
|
|
6184
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(AppFocusedStatusBar, { translucent: true, backgroundColor: "transparent" }),
|
|
6185
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
4582
6186
|
AppView,
|
|
4583
6187
|
{
|
|
4584
6188
|
style: [
|
|
@@ -4588,39 +6192,39 @@ function AppHeader({
|
|
|
4588
6192
|
},
|
|
4589
6193
|
style
|
|
4590
6194
|
],
|
|
4591
|
-
children: /* @__PURE__ */ (0,
|
|
4592
|
-
/* @__PURE__ */ (0,
|
|
4593
|
-
/* @__PURE__ */ (0,
|
|
4594
|
-
title && /* @__PURE__ */ (0,
|
|
6195
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(AppView, { row: true, items: "center", px: 4, style: styles17.container, children: [
|
|
6196
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(AppView, { style: [styles17.sideContainer, styles17.leftContainer], children: leftIcon && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(AppPressable, { onPress: onLeftPress, style: styles17.iconButton, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(Icon, { name: leftIcon, size: 24, color: colors.text }) }) }),
|
|
6197
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(AppView, { style: styles17.centerContainer, children: [
|
|
6198
|
+
title && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
4595
6199
|
AppText,
|
|
4596
6200
|
{
|
|
4597
6201
|
size: "lg",
|
|
4598
6202
|
weight: "semibold",
|
|
4599
|
-
style: [
|
|
6203
|
+
style: [styles17.title, { color: colors.text }],
|
|
4600
6204
|
numberOfLines: 1,
|
|
4601
6205
|
children: title
|
|
4602
6206
|
}
|
|
4603
6207
|
),
|
|
4604
|
-
subtitle && /* @__PURE__ */ (0,
|
|
6208
|
+
subtitle && /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(
|
|
4605
6209
|
AppText,
|
|
4606
6210
|
{
|
|
4607
6211
|
size: "xs",
|
|
4608
|
-
style: [
|
|
6212
|
+
style: [styles17.subtitle, { color: colors.textMuted }],
|
|
4609
6213
|
numberOfLines: 1,
|
|
4610
6214
|
children: subtitle
|
|
4611
6215
|
}
|
|
4612
6216
|
)
|
|
4613
6217
|
] }),
|
|
4614
|
-
/* @__PURE__ */ (0,
|
|
4615
|
-
/* @__PURE__ */ (0,
|
|
4616
|
-
icon.badge ? /* @__PURE__ */ (0,
|
|
6218
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(AppView, { row: true, items: "center", style: [styles17.sideContainer, styles17.rightContainer], children: rightIcons.map((icon, index) => /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(AppPressable, { onPress: icon.onPress, style: styles17.iconButton, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(AppView, { children: [
|
|
6219
|
+
/* @__PURE__ */ (0, import_jsx_runtime51.jsx)(Icon, { name: icon.icon, size: 24, color: colors.text }),
|
|
6220
|
+
icon.badge ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(AppView, { style: styles17.badge, children: /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(AppText, { size: "xs", color: "white", style: styles17.badgeText, children: icon.badge > 99 ? "99+" : icon.badge }) }) : null
|
|
4617
6221
|
] }) }, index)) })
|
|
4618
6222
|
] })
|
|
4619
6223
|
}
|
|
4620
6224
|
)
|
|
4621
6225
|
] });
|
|
4622
6226
|
}
|
|
4623
|
-
var
|
|
6227
|
+
var styles17 = import_react_native33.StyleSheet.create({
|
|
4624
6228
|
container: {
|
|
4625
6229
|
height: 44
|
|
4626
6230
|
// iOS 标准导航栏高度
|
|
@@ -4671,9 +6275,9 @@ var styles16 = import_react_native30.StyleSheet.create({
|
|
|
4671
6275
|
});
|
|
4672
6276
|
|
|
4673
6277
|
// src/navigation/components/DrawerContent.tsx
|
|
4674
|
-
var
|
|
6278
|
+
var import_react_native34 = require("react-native");
|
|
4675
6279
|
var import_drawer2 = require("@react-navigation/drawer");
|
|
4676
|
-
var
|
|
6280
|
+
var import_jsx_runtime52 = require("nativewind/jsx-runtime");
|
|
4677
6281
|
function DrawerContent({
|
|
4678
6282
|
state,
|
|
4679
6283
|
descriptors,
|
|
@@ -4702,20 +6306,20 @@ function DrawerContent({
|
|
|
4702
6306
|
badge: options.tabBarBadge
|
|
4703
6307
|
};
|
|
4704
6308
|
});
|
|
4705
|
-
return /* @__PURE__ */ (0,
|
|
4706
|
-
header && /* @__PURE__ */ (0,
|
|
4707
|
-
/* @__PURE__ */ (0,
|
|
6309
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(import_drawer2.DrawerContentScrollView, { style: [styles18.container, { backgroundColor }], children: [
|
|
6310
|
+
header && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_react_native34.View, { style: [styles18.header, { borderBottomColor: dividerColor }], children: header }),
|
|
6311
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(AppView, { className: "py-2", children: drawerItems.map((item) => {
|
|
4708
6312
|
const isFocused = state.routes[state.index].name === item.name;
|
|
4709
6313
|
const onPress = () => {
|
|
4710
6314
|
navigation.navigate(item.name);
|
|
4711
6315
|
};
|
|
4712
|
-
return /* @__PURE__ */ (0,
|
|
4713
|
-
|
|
6316
|
+
return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)(
|
|
6317
|
+
import_react_native34.TouchableOpacity,
|
|
4714
6318
|
{
|
|
4715
6319
|
onPress,
|
|
4716
|
-
style: [
|
|
6320
|
+
style: [styles18.item, isFocused && { backgroundColor: activeBgColor }],
|
|
4717
6321
|
children: [
|
|
4718
|
-
item.icon && /* @__PURE__ */ (0,
|
|
6322
|
+
item.icon && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_react_native34.View, { style: styles18.iconContainer, children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
4719
6323
|
Icon,
|
|
4720
6324
|
{
|
|
4721
6325
|
name: item.icon,
|
|
@@ -4723,28 +6327,28 @@ function DrawerContent({
|
|
|
4723
6327
|
color: isFocused ? activeColor : inactiveColor
|
|
4724
6328
|
}
|
|
4725
6329
|
) }),
|
|
4726
|
-
/* @__PURE__ */ (0,
|
|
6330
|
+
/* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
|
|
4727
6331
|
AppText,
|
|
4728
6332
|
{
|
|
4729
6333
|
style: [
|
|
4730
|
-
|
|
6334
|
+
styles18.label,
|
|
4731
6335
|
{ color: isFocused ? activeColor : inactiveColor },
|
|
4732
|
-
isFocused &&
|
|
6336
|
+
isFocused && styles18.activeLabel
|
|
4733
6337
|
],
|
|
4734
6338
|
numberOfLines: 1,
|
|
4735
6339
|
children: item.label
|
|
4736
6340
|
}
|
|
4737
6341
|
),
|
|
4738
|
-
item.badge != null && /* @__PURE__ */ (0,
|
|
6342
|
+
item.badge != null && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_react_native34.View, { style: [styles18.badge, { backgroundColor: activeColor }], children: /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(AppText, { style: styles18.badgeText, children: typeof item.badge === "number" && item.badge > 99 ? "99+" : item.badge }) })
|
|
4739
6343
|
]
|
|
4740
6344
|
},
|
|
4741
6345
|
item.name
|
|
4742
6346
|
);
|
|
4743
6347
|
}) }),
|
|
4744
|
-
footer && /* @__PURE__ */ (0,
|
|
6348
|
+
footer && /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(import_react_native34.View, { style: [styles18.footer, { borderTopColor: dividerColor }], children: footer })
|
|
4745
6349
|
] });
|
|
4746
6350
|
}
|
|
4747
|
-
var
|
|
6351
|
+
var styles18 = import_react_native34.StyleSheet.create({
|
|
4748
6352
|
container: {
|
|
4749
6353
|
flex: 1
|
|
4750
6354
|
},
|
|
@@ -4794,7 +6398,7 @@ var styles17 = import_react_native31.StyleSheet.create({
|
|
|
4794
6398
|
});
|
|
4795
6399
|
|
|
4796
6400
|
// src/navigation/hooks/useNavigation.ts
|
|
4797
|
-
var
|
|
6401
|
+
var import_react54 = require("react");
|
|
4798
6402
|
var import_native3 = require("@react-navigation/native");
|
|
4799
6403
|
function useNavigation() {
|
|
4800
6404
|
return (0, import_native3.useNavigation)();
|
|
@@ -4810,7 +6414,7 @@ function useDrawerNavigation() {
|
|
|
4810
6414
|
}
|
|
4811
6415
|
function useBackHandler(handler) {
|
|
4812
6416
|
const navigation = (0, import_native3.useNavigation)();
|
|
4813
|
-
(0,
|
|
6417
|
+
(0, import_react54.useEffect)(() => {
|
|
4814
6418
|
const unsubscribe = navigation.addListener("beforeRemove", (e) => {
|
|
4815
6419
|
if (!handler()) {
|
|
4816
6420
|
e.preventDefault();
|
|
@@ -4842,6 +6446,7 @@ var import_react_native_safe_area_context5 = require("react-native-safe-area-con
|
|
|
4842
6446
|
ActionIcons,
|
|
4843
6447
|
Alert,
|
|
4844
6448
|
AppButton,
|
|
6449
|
+
AppErrorBoundary,
|
|
4845
6450
|
AppFocusedStatusBar,
|
|
4846
6451
|
AppHeader,
|
|
4847
6452
|
AppImage,
|
|
@@ -4869,13 +6474,18 @@ var import_react_native_safe_area_context5 = require("react-native-safe-area-con
|
|
|
4869
6474
|
FormItem,
|
|
4870
6475
|
GradientView,
|
|
4871
6476
|
Icon,
|
|
6477
|
+
KeyboardDismissView,
|
|
6478
|
+
LOG_LEVEL_WEIGHT,
|
|
4872
6479
|
Loading,
|
|
6480
|
+
LogOverlay,
|
|
6481
|
+
LoggerProvider,
|
|
4873
6482
|
MemoryStorage,
|
|
4874
6483
|
NavigationContainer,
|
|
4875
6484
|
NavigationIcons,
|
|
4876
6485
|
NavigationProvider,
|
|
4877
6486
|
OverlayProvider,
|
|
4878
6487
|
PageDrawer,
|
|
6488
|
+
Picker,
|
|
4879
6489
|
Progress,
|
|
4880
6490
|
Radio,
|
|
4881
6491
|
RadioGroup,
|
|
@@ -4897,7 +6507,10 @@ var import_react_native_safe_area_context5 = require("react-native-safe-area-con
|
|
|
4897
6507
|
clsx,
|
|
4898
6508
|
cn,
|
|
4899
6509
|
createAPI,
|
|
6510
|
+
createApiLoggerTransport,
|
|
6511
|
+
createConsoleTransport,
|
|
4900
6512
|
createDrawerScreens,
|
|
6513
|
+
createLogEntry,
|
|
4901
6514
|
createNavigationTheme,
|
|
4902
6515
|
createStackScreens,
|
|
4903
6516
|
createTabScreens,
|
|
@@ -4906,10 +6519,12 @@ var import_react_native_safe_area_context5 = require("react-native-safe-area-con
|
|
|
4906
6519
|
enhanceError,
|
|
4907
6520
|
formatCurrency,
|
|
4908
6521
|
formatDate,
|
|
6522
|
+
formatLogTime,
|
|
4909
6523
|
formatNumber,
|
|
4910
6524
|
formatPercent,
|
|
4911
6525
|
formatRelativeTime,
|
|
4912
6526
|
generateColorPalette,
|
|
6527
|
+
getGlobalLogger,
|
|
4913
6528
|
getThemeColors,
|
|
4914
6529
|
getValidationErrors,
|
|
4915
6530
|
hexToRgb,
|
|
@@ -4917,11 +6532,16 @@ var import_react_native_safe_area_context5 = require("react-native-safe-area-con
|
|
|
4917
6532
|
isValidEmail,
|
|
4918
6533
|
isValidPhone,
|
|
4919
6534
|
mapHttpStatus,
|
|
6535
|
+
normalizeConsoleArgs,
|
|
4920
6536
|
omit,
|
|
4921
6537
|
pick,
|
|
4922
6538
|
rgbToHex,
|
|
6539
|
+
serializeLogEntries,
|
|
6540
|
+
setGlobalLogger,
|
|
6541
|
+
shouldLog,
|
|
4923
6542
|
slugify,
|
|
4924
6543
|
storage,
|
|
6544
|
+
stringifyLogData,
|
|
4925
6545
|
truncate,
|
|
4926
6546
|
twMerge,
|
|
4927
6547
|
useAlert,
|
|
@@ -4936,6 +6556,7 @@ var import_react_native_safe_area_context5 = require("react-native-safe-area-con
|
|
|
4936
6556
|
useIsFocused,
|
|
4937
6557
|
useKeyboard,
|
|
4938
6558
|
useLoading,
|
|
6559
|
+
useLogger,
|
|
4939
6560
|
useMemoizedFn,
|
|
4940
6561
|
useMutation,
|
|
4941
6562
|
useNavigation,
|