persian-data-grid 0.5.0 → 0.6.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/OFL.txt +93 -0
- package/README.md +179 -22
- package/dist/ERPTableGroupRow-J5Z2LRC5.cjs +131 -0
- package/dist/ERPTableGroupRow-J5Z2LRC5.cjs.map +1 -0
- package/dist/ERPTableGroupRow-PSAPAHGL.js +125 -0
- package/dist/ERPTableGroupRow-PSAPAHGL.js.map +1 -0
- package/dist/GridPlugin-CJCaYnlw.d.ts +57 -0
- package/dist/GridPlugin-oxhq8AsM.d.cts +57 -0
- package/dist/GridPresenceService-GEH6535Q.js +3 -0
- package/dist/GridPresenceService-GEH6535Q.js.map +1 -0
- package/dist/GridPresenceService-RDN5FXHQ.cjs +12 -0
- package/dist/GridPresenceService-RDN5FXHQ.cjs.map +1 -0
- package/dist/GridSession-B-9lLcoB.d.cts +2492 -0
- package/dist/GridSession-Bc7UIawO.d.ts +2492 -0
- package/dist/GridSyncService-KTLB4KP3.js +3 -0
- package/dist/GridSyncService-KTLB4KP3.js.map +1 -0
- package/dist/GridSyncService-TAPAHABV.cjs +12 -0
- package/dist/GridSyncService-TAPAHABV.cjs.map +1 -0
- package/dist/PdfRenderer-1HFh6UeR.d.ts +22 -0
- package/dist/PdfRenderer-CBg7hWNS.d.cts +22 -0
- package/dist/RemoteApi-CCQxiSf1.d.cts +28 -0
- package/dist/RemoteApi-CCQxiSf1.d.ts +28 -0
- package/dist/SelectImpl-NM4O4IGW.js +447 -0
- package/dist/SelectImpl-NM4O4IGW.js.map +1 -0
- package/dist/SelectImpl-W2EI4T7O.cjs +453 -0
- package/dist/SelectImpl-W2EI4T7O.cjs.map +1 -0
- package/dist/UITableController-Cuwq481K.d.cts +632 -0
- package/dist/UITableController-DU8RopUM.d.ts +632 -0
- package/dist/VazirmatnPdfRenderer-BCMpC1zy.d.cts +96 -0
- package/dist/VazirmatnPdfRenderer-Dz_G-m3c.d.ts +96 -0
- package/dist/adapters/arian-erp.cjs +77 -0
- package/dist/adapters/arian-erp.cjs.map +1 -0
- package/dist/adapters/arian-erp.d.cts +60 -0
- package/dist/adapters/arian-erp.d.ts +60 -0
- package/dist/adapters/arian-erp.js +71 -0
- package/dist/adapters/arian-erp.js.map +1 -0
- package/dist/appendAtEnd-RHIQRG2W.cjs +35 -0
- package/dist/appendAtEnd-RHIQRG2W.cjs.map +1 -0
- package/dist/appendAtEnd-TJEABLGD.js +33 -0
- package/dist/appendAtEnd-TJEABLGD.js.map +1 -0
- package/dist/applyImportedRows-BO6yxoAN.d.cts +135 -0
- package/dist/applyImportedRows-D4zVY8uD.d.ts +135 -0
- package/dist/applyRowVisibilityHandler-KS6TMCBN.js +83 -0
- package/dist/applyRowVisibilityHandler-KS6TMCBN.js.map +1 -0
- package/dist/applyRowVisibilityHandler-LXCOGESZ.cjs +85 -0
- package/dist/applyRowVisibilityHandler-LXCOGESZ.cjs.map +1 -0
- package/dist/broadcastChannelTransport-FHUMV76O.cjs +12 -0
- package/dist/broadcastChannelTransport-FHUMV76O.cjs.map +1 -0
- package/dist/broadcastChannelTransport-MIH53VNZ.js +3 -0
- package/dist/broadcastChannelTransport-MIH53VNZ.js.map +1 -0
- package/dist/callbackRemoteApi-BlXO5NJz.d.ts +30 -0
- package/dist/callbackRemoteApi-DgnXH-i0.d.cts +30 -0
- package/dist/cellRenderContext-DB7V_mlu.d.ts +42 -0
- package/dist/cellRenderContext-DG5BOlxK.d.cts +42 -0
- package/dist/chunk-2BJCRYOS.cjs +936 -0
- package/dist/chunk-2BJCRYOS.cjs.map +1 -0
- package/dist/chunk-3Y3KKGEC.js +3 -0
- package/dist/chunk-3Y3KKGEC.js.map +1 -0
- package/dist/chunk-5ALMNLUR.cjs +1408 -0
- package/dist/chunk-5ALMNLUR.cjs.map +1 -0
- package/dist/chunk-5HKVMPBD.js +937 -0
- package/dist/chunk-5HKVMPBD.js.map +1 -0
- package/dist/chunk-633KP74Z.js +189 -0
- package/dist/chunk-633KP74Z.js.map +1 -0
- package/dist/chunk-6XBXZPBW.js +298 -0
- package/dist/chunk-6XBXZPBW.js.map +1 -0
- package/dist/chunk-77UXAJII.js +112 -0
- package/dist/chunk-77UXAJII.js.map +1 -0
- package/dist/chunk-ASPTRYRD.cjs +21 -0
- package/dist/chunk-ASPTRYRD.cjs.map +1 -0
- package/dist/chunk-AU3RDJYQ.js +243 -0
- package/dist/chunk-AU3RDJYQ.js.map +1 -0
- package/dist/chunk-BHDRUZH5.cjs +33 -0
- package/dist/chunk-BHDRUZH5.cjs.map +1 -0
- package/dist/chunk-BLYVOV3G.cjs +191 -0
- package/dist/chunk-BLYVOV3G.cjs.map +1 -0
- package/dist/chunk-CILNIWYW.cjs +100 -0
- package/dist/chunk-CILNIWYW.cjs.map +1 -0
- package/dist/chunk-DFFP7SJ6.cjs +257 -0
- package/dist/chunk-DFFP7SJ6.cjs.map +1 -0
- package/dist/chunk-DXRCYW42.cjs +568 -0
- package/dist/chunk-DXRCYW42.cjs.map +1 -0
- package/dist/chunk-EBV6HGZB.cjs +33 -0
- package/dist/chunk-EBV6HGZB.cjs.map +1 -0
- package/dist/chunk-EHHHC5JV.js +832 -0
- package/dist/chunk-EHHHC5JV.js.map +1 -0
- package/dist/chunk-F4PYOYHR.js +112 -0
- package/dist/chunk-F4PYOYHR.js.map +1 -0
- package/dist/chunk-GQEDLUMB.js +168 -0
- package/dist/chunk-GQEDLUMB.js.map +1 -0
- package/dist/chunk-H2LESGMX.cjs +319 -0
- package/dist/chunk-H2LESGMX.cjs.map +1 -0
- package/dist/chunk-HTNJT2QU.js +11674 -0
- package/dist/chunk-HTNJT2QU.js.map +1 -0
- package/dist/chunk-IIISFUW4.cjs +11786 -0
- package/dist/chunk-IIISFUW4.cjs.map +1 -0
- package/dist/chunk-IMPCRWYP.cjs +251 -0
- package/dist/chunk-IMPCRWYP.cjs.map +1 -0
- package/dist/chunk-IPPIXOVQ.js +317 -0
- package/dist/chunk-IPPIXOVQ.js.map +1 -0
- package/dist/chunk-J4XJ4UBC.js +1404 -0
- package/dist/chunk-J4XJ4UBC.js.map +1 -0
- package/dist/chunk-J7CPPFXT.cjs +89 -0
- package/dist/chunk-J7CPPFXT.cjs.map +1 -0
- package/dist/chunk-JOICD47Q.cjs +41 -0
- package/dist/chunk-JOICD47Q.cjs.map +1 -0
- package/dist/chunk-KHMG6EI2.js +13 -0
- package/dist/chunk-KHMG6EI2.js.map +1 -0
- package/dist/chunk-KMRURD5J.cjs +15 -0
- package/dist/chunk-KMRURD5J.cjs.map +1 -0
- package/dist/chunk-KRJG3KMP.cjs +174 -0
- package/dist/chunk-KRJG3KMP.cjs.map +1 -0
- package/dist/chunk-KUBVDIF7.cjs +653 -0
- package/dist/chunk-KUBVDIF7.cjs.map +1 -0
- package/dist/chunk-KYAOSBQN.js +31 -0
- package/dist/chunk-KYAOSBQN.js.map +1 -0
- package/dist/chunk-LJ7LMEXO.js +36 -0
- package/dist/chunk-LJ7LMEXO.js.map +1 -0
- package/dist/chunk-MT3KLB2Q.cjs +944 -0
- package/dist/chunk-MT3KLB2Q.cjs.map +1 -0
- package/dist/chunk-MU3RY46O.js +932 -0
- package/dist/chunk-MU3RY46O.js.map +1 -0
- package/dist/chunk-MUQQKPWR.js +84 -0
- package/dist/chunk-MUQQKPWR.js.map +1 -0
- package/dist/chunk-N7SJTINL.cjs +4 -0
- package/dist/chunk-N7SJTINL.cjs.map +1 -0
- package/dist/chunk-NTV2UUAJ.cjs +149 -0
- package/dist/chunk-NTV2UUAJ.cjs.map +1 -0
- package/dist/chunk-PJQWHF6T.js +31 -0
- package/dist/chunk-PJQWHF6T.js.map +1 -0
- package/dist/chunk-PQY54EL5.js +248 -0
- package/dist/chunk-PQY54EL5.js.map +1 -0
- package/dist/chunk-PXCHPZTP.cjs +839 -0
- package/dist/chunk-PXCHPZTP.cjs.map +1 -0
- package/dist/chunk-Q7TBBUTX.cjs +110 -0
- package/dist/chunk-Q7TBBUTX.cjs.map +1 -0
- package/dist/chunk-QQMU44KJ.js +612 -0
- package/dist/chunk-QQMU44KJ.js.map +1 -0
- package/dist/chunk-QZN7R2WP.cjs +114 -0
- package/dist/chunk-QZN7R2WP.cjs.map +1 -0
- package/dist/chunk-RKVSJU46.js +35 -0
- package/dist/chunk-RKVSJU46.js.map +1 -0
- package/dist/chunk-RM6ZWNT3.js +561 -0
- package/dist/chunk-RM6ZWNT3.js.map +1 -0
- package/dist/chunk-SX4VQXAA.cjs +114 -0
- package/dist/chunk-SX4VQXAA.cjs.map +1 -0
- package/dist/chunk-SZ7BLAY3.js +92 -0
- package/dist/chunk-SZ7BLAY3.js.map +1 -0
- package/dist/chunk-TN4MG6FY.js +112 -0
- package/dist/chunk-TN4MG6FY.js.map +1 -0
- package/dist/chunk-UC7PHDM6.cjs +331 -0
- package/dist/chunk-UC7PHDM6.cjs.map +1 -0
- package/dist/chunk-UXVLYUUW.js +108 -0
- package/dist/chunk-UXVLYUUW.js.map +1 -0
- package/dist/chunk-VVGYRZ7S.cjs +38 -0
- package/dist/chunk-VVGYRZ7S.cjs.map +1 -0
- package/dist/chunk-W5256BJ4.js +56 -0
- package/dist/chunk-W5256BJ4.js.map +1 -0
- package/dist/chunk-WUMOSOEK.cjs +62 -0
- package/dist/chunk-WUMOSOEK.cjs.map +1 -0
- package/dist/chunk-XLRE2J25.js +140 -0
- package/dist/chunk-XLRE2J25.js.map +1 -0
- package/dist/chunk-Y6W5V2CI.js +19 -0
- package/dist/chunk-Y6W5V2CI.js.map +1 -0
- package/dist/chunk-Z4QPZ3Z3.cjs +114 -0
- package/dist/chunk-Z4QPZ3Z3.cjs.map +1 -0
- package/dist/createEngineGridQuery-Dmq3i5v3.d.cts +884 -0
- package/dist/createEngineGridQuery-Mt1hc33m.d.ts +884 -0
- package/dist/date-picker-jalali.cjs +263 -0
- package/dist/date-picker-jalali.cjs.map +1 -0
- package/dist/date-picker-jalali.d.cts +62 -0
- package/dist/date-picker-jalali.d.ts +62 -0
- package/dist/date-picker-jalali.js +256 -0
- package/dist/date-picker-jalali.js.map +1 -0
- package/dist/finance.cjs +205 -0
- package/dist/finance.cjs.map +1 -0
- package/dist/finance.d.cts +90 -0
- package/dist/finance.d.ts +90 -0
- package/dist/finance.js +157 -0
- package/dist/finance.js.map +1 -0
- package/dist/foldedColumn-IHDT4ARZ.cjs +66 -0
- package/dist/foldedColumn-IHDT4ARZ.cjs.map +1 -0
- package/dist/foldedColumn-TFURUKFG.js +64 -0
- package/dist/foldedColumn-TFURUKFG.js.map +1 -0
- package/dist/headless.cjs +729 -0
- package/dist/headless.cjs.map +1 -0
- package/dist/headless.d.cts +504 -0
- package/dist/headless.d.ts +504 -0
- package/dist/headless.js +226 -0
- package/dist/headless.js.map +1 -0
- package/dist/index-DN8M8Jkq.d.cts +14 -0
- package/dist/index-DmzL-F_o.d.ts +14 -0
- package/dist/index.cjs +8002 -11409
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +437 -2305
- package/dist/index.d.ts +437 -2305
- package/dist/index.js +7244 -11083
- package/dist/index.js.map +1 -1
- package/dist/locales/ar.cjs +12 -0
- package/dist/locales/ar.cjs.map +1 -0
- package/dist/locales/ar.d.cts +6 -0
- package/dist/locales/ar.d.ts +6 -0
- package/dist/locales/ar.js +3 -0
- package/dist/locales/ar.js.map +1 -0
- package/dist/locales/en.cjs +12 -0
- package/dist/locales/en.cjs.map +1 -0
- package/dist/locales/en.d.cts +6 -0
- package/dist/locales/en.d.ts +6 -0
- package/dist/locales/en.js +3 -0
- package/dist/locales/en.js.map +1 -0
- package/dist/locales/fa.cjs +12 -0
- package/dist/locales/fa.cjs.map +1 -0
- package/dist/locales/fa.d.cts +6 -0
- package/dist/locales/fa.d.ts +6 -0
- package/dist/locales/fa.js +3 -0
- package/dist/locales/fa.js.map +1 -0
- package/dist/locales/index.cjs +51 -0
- package/dist/locales/index.cjs.map +1 -0
- package/dist/locales/index.d.cts +5 -0
- package/dist/locales/index.d.ts +5 -0
- package/dist/locales/index.js +6 -0
- package/dist/locales/index.js.map +1 -0
- package/dist/memoryRecords-AWDKUJ2F.cjs +50 -0
- package/dist/memoryRecords-AWDKUJ2F.cjs.map +1 -0
- package/dist/memoryRecords-OJTGXLRH.js +47 -0
- package/dist/memoryRecords-OJTGXLRH.js.map +1 -0
- package/dist/pagedFooterTotals-DXCGDO6F.cjs +27 -0
- package/dist/pagedFooterTotals-DXCGDO6F.cjs.map +1 -0
- package/dist/pagedFooterTotals-ORWKUNE7.js +25 -0
- package/dist/pagedFooterTotals-ORWKUNE7.js.map +1 -0
- package/dist/pagedKit-MFGAJFSK.cjs +134 -0
- package/dist/pagedKit-MFGAJFSK.cjs.map +1 -0
- package/dist/pagedKit-WYWY4LRV.js +127 -0
- package/dist/pagedKit-WYWY4LRV.js.map +1 -0
- package/dist/pagedSearch-HCPJW7VM.js +38 -0
- package/dist/pagedSearch-HCPJW7VM.js.map +1 -0
- package/dist/pagedSearch-U3WCG4GN.cjs +42 -0
- package/dist/pagedSearch-U3WCG4GN.cjs.map +1 -0
- package/dist/plugins/csv.cjs +124 -0
- package/dist/plugins/csv.cjs.map +1 -0
- package/dist/plugins/csv.d.cts +44 -0
- package/dist/plugins/csv.d.ts +44 -0
- package/dist/plugins/csv.js +120 -0
- package/dist/plugins/csv.js.map +1 -0
- package/dist/plugins/excel.cjs +52 -0
- package/dist/plugins/excel.cjs.map +1 -0
- package/dist/plugins/excel.d.cts +14 -0
- package/dist/plugins/excel.d.ts +14 -0
- package/dist/plugins/excel.js +7 -0
- package/dist/plugins/excel.js.map +1 -0
- package/dist/plugins/pdf/fonts/vazirmatn.cjs +50 -0
- package/dist/plugins/pdf/fonts/vazirmatn.cjs.map +1 -0
- package/dist/plugins/pdf/fonts/vazirmatn.d.cts +24 -0
- package/dist/plugins/pdf/fonts/vazirmatn.d.ts +24 -0
- package/dist/plugins/pdf/fonts/vazirmatn.js +39 -0
- package/dist/plugins/pdf/fonts/vazirmatn.js.map +1 -0
- package/dist/plugins/pdf.cjs +24 -0
- package/dist/plugins/pdf.cjs.map +1 -0
- package/dist/plugins/pdf.d.cts +21 -0
- package/dist/plugins/pdf.d.ts +21 -0
- package/dist/plugins/pdf.js +7 -0
- package/dist/plugins/pdf.js.map +1 -0
- package/dist/presence.cjs +56 -0
- package/dist/presence.cjs.map +1 -0
- package/dist/presence.d.cts +17 -0
- package/dist/presence.d.ts +17 -0
- package/dist/presence.js +54 -0
- package/dist/presence.js.map +1 -0
- package/dist/rebuildRowVisibility-66EAZ356.cjs +21 -0
- package/dist/rebuildRowVisibility-66EAZ356.cjs.map +1 -0
- package/dist/rebuildRowVisibility-6TYM5BP2.js +19 -0
- package/dist/rebuildRowVisibility-6TYM5BP2.js.map +1 -0
- package/dist/styles.css +1440 -0
- package/dist/sync.cjs +148 -0
- package/dist/sync.cjs.map +1 -0
- package/dist/sync.d.cts +17 -0
- package/dist/sync.d.ts +17 -0
- package/dist/sync.js +146 -0
- package/dist/sync.js.map +1 -0
- package/dist/types-D__47BKv.d.cts +23 -0
- package/dist/types-D__47BKv.d.ts +23 -0
- package/package.json +184 -28
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// engine/dataOps/sortModel.ts
|
|
2
|
+
var INDEX_COL_ID = "index";
|
|
3
|
+
var FA_COLLATOR = new Intl.Collator("fa", {
|
|
4
|
+
numeric: true,
|
|
5
|
+
sensitivity: "base"
|
|
6
|
+
});
|
|
7
|
+
var EASTERN_DIGITS = /[۰-۹٠-٩]/g;
|
|
8
|
+
var EASTERN_DIGIT_MAP = {
|
|
9
|
+
"\u06F0": "0",
|
|
10
|
+
"\u06F1": "1",
|
|
11
|
+
"\u06F2": "2",
|
|
12
|
+
"\u06F3": "3",
|
|
13
|
+
"\u06F4": "4",
|
|
14
|
+
"\u06F5": "5",
|
|
15
|
+
"\u06F6": "6",
|
|
16
|
+
"\u06F7": "7",
|
|
17
|
+
"\u06F8": "8",
|
|
18
|
+
"\u06F9": "9",
|
|
19
|
+
"\u0660": "0",
|
|
20
|
+
"\u0661": "1",
|
|
21
|
+
"\u0662": "2",
|
|
22
|
+
"\u0663": "3",
|
|
23
|
+
"\u0664": "4",
|
|
24
|
+
"\u0665": "5",
|
|
25
|
+
"\u0666": "6",
|
|
26
|
+
"\u0667": "7",
|
|
27
|
+
"\u0668": "8",
|
|
28
|
+
"\u0669": "9"
|
|
29
|
+
};
|
|
30
|
+
function normalizeDigits(value) {
|
|
31
|
+
return value.replace(EASTERN_DIGITS, (ch) => EASTERN_DIGIT_MAP[ch] ?? ch);
|
|
32
|
+
}
|
|
33
|
+
function isBlankSortValue(value) {
|
|
34
|
+
if (value == null) return true;
|
|
35
|
+
if (typeof value === "number" && Number.isNaN(value)) return true;
|
|
36
|
+
if (typeof value === "string" && value.trim() === "") return true;
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
function toNumber(value) {
|
|
40
|
+
if (typeof value === "number") {
|
|
41
|
+
return Number.isFinite(value) ? value : null;
|
|
42
|
+
}
|
|
43
|
+
if (typeof value === "boolean") return value ? 1 : 0;
|
|
44
|
+
if (typeof value === "string") {
|
|
45
|
+
const n = Number(normalizeDigits(value).replace(/,/g, "").trim());
|
|
46
|
+
return Number.isFinite(n) ? n : null;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
function toDateKey(value) {
|
|
51
|
+
if (value instanceof Date) {
|
|
52
|
+
const t = value.getTime();
|
|
53
|
+
return Number.isNaN(t) ? null : t;
|
|
54
|
+
}
|
|
55
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
56
|
+
if (typeof value === "string") {
|
|
57
|
+
const text = normalizeDigits(value).trim();
|
|
58
|
+
if (!text) return null;
|
|
59
|
+
const parsed = Date.parse(text);
|
|
60
|
+
if (!Number.isNaN(parsed)) return parsed;
|
|
61
|
+
const digits = text.replace(/\D/g, "");
|
|
62
|
+
if (digits.length >= 8) return Number(digits.slice(0, 8));
|
|
63
|
+
}
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
function toBoolean(value) {
|
|
67
|
+
if (typeof value === "boolean") return value;
|
|
68
|
+
if (value === 1 || value === "1" || value === "true") return true;
|
|
69
|
+
if (value === 0 || value === "0" || value === "false") return false;
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
function compareText(a, b) {
|
|
73
|
+
return FA_COLLATOR.compare(String(a), String(b));
|
|
74
|
+
}
|
|
75
|
+
function compareFinite(a, b) {
|
|
76
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
77
|
+
}
|
|
78
|
+
function compareTypedValues(a, b, fieldType) {
|
|
79
|
+
switch (fieldType) {
|
|
80
|
+
case "number":
|
|
81
|
+
case "price":
|
|
82
|
+
case "index": {
|
|
83
|
+
const na = toNumber(a);
|
|
84
|
+
const nb = toNumber(b);
|
|
85
|
+
if (na == null && nb == null) return compareText(a, b);
|
|
86
|
+
if (na == null) return 1;
|
|
87
|
+
if (nb == null) return -1;
|
|
88
|
+
return compareFinite(na, nb);
|
|
89
|
+
}
|
|
90
|
+
case "date": {
|
|
91
|
+
const da = toDateKey(a);
|
|
92
|
+
const db = toDateKey(b);
|
|
93
|
+
if (da == null && db == null) return compareText(a, b);
|
|
94
|
+
if (da == null) return 1;
|
|
95
|
+
if (db == null) return -1;
|
|
96
|
+
return compareFinite(da, db);
|
|
97
|
+
}
|
|
98
|
+
case "checkbox": {
|
|
99
|
+
const ba = toBoolean(a);
|
|
100
|
+
const bb = toBoolean(b);
|
|
101
|
+
if (ba == null && bb == null) return compareText(a, b);
|
|
102
|
+
if (ba == null) return 1;
|
|
103
|
+
if (bb == null) return -1;
|
|
104
|
+
return Number(ba) - Number(bb);
|
|
105
|
+
}
|
|
106
|
+
default:
|
|
107
|
+
return compareText(a, b);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function compareSortValues(a, b, fieldType, comparator) {
|
|
111
|
+
if (comparator) return comparator(a, b);
|
|
112
|
+
return compareTypedValues(a, b, fieldType);
|
|
113
|
+
}
|
|
114
|
+
function isSortDirection(value) {
|
|
115
|
+
return value === "asc" || value === "desc";
|
|
116
|
+
}
|
|
117
|
+
function resolveKeys(sortModel) {
|
|
118
|
+
const keys = [];
|
|
119
|
+
const seen = /* @__PURE__ */ new Set();
|
|
120
|
+
for (const item of sortModel) {
|
|
121
|
+
if (!item || typeof item.colId !== "string" || item.colId.length === 0) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (!isSortDirection(item.sort) || seen.has(item.colId)) continue;
|
|
125
|
+
seen.add(item.colId);
|
|
126
|
+
keys.push({ colId: item.colId, sort: item.sort });
|
|
127
|
+
}
|
|
128
|
+
if (!seen.has(INDEX_COL_ID)) {
|
|
129
|
+
keys.push({ colId: INDEX_COL_ID, sort: "asc" });
|
|
130
|
+
}
|
|
131
|
+
return keys;
|
|
132
|
+
}
|
|
133
|
+
function applySort(rowIds, sortModel, accessor) {
|
|
134
|
+
const keys = resolveKeys(sortModel);
|
|
135
|
+
const decorated = rowIds.map((rowId, originalIndex) => ({
|
|
136
|
+
rowId,
|
|
137
|
+
originalIndex
|
|
138
|
+
}));
|
|
139
|
+
decorated.sort((left, right) => {
|
|
140
|
+
for (const key of keys) {
|
|
141
|
+
const a = accessor.getValue(left.rowId, key.colId);
|
|
142
|
+
const b = accessor.getValue(right.rowId, key.colId);
|
|
143
|
+
const aBlank = isBlankSortValue(a);
|
|
144
|
+
const bBlank = isBlankSortValue(b);
|
|
145
|
+
if (aBlank || bBlank) {
|
|
146
|
+
if (aBlank && bBlank) continue;
|
|
147
|
+
return aBlank ? 1 : -1;
|
|
148
|
+
}
|
|
149
|
+
const fieldType = accessor.getFieldType?.(key.colId) ?? (key.colId === INDEX_COL_ID ? "index" : void 0);
|
|
150
|
+
const cmp = compareSortValues(
|
|
151
|
+
a,
|
|
152
|
+
b,
|
|
153
|
+
fieldType,
|
|
154
|
+
accessor.getComparator?.(key.colId)
|
|
155
|
+
);
|
|
156
|
+
if (cmp !== 0) return key.sort === "desc" ? -cmp : cmp;
|
|
157
|
+
}
|
|
158
|
+
return left.originalIndex - right.originalIndex;
|
|
159
|
+
});
|
|
160
|
+
return decorated.map((row) => row.rowId);
|
|
161
|
+
}
|
|
162
|
+
function compareRowIdsForSort(leftId, rightId, sortModel, accessor) {
|
|
163
|
+
const keys = resolveKeys(sortModel);
|
|
164
|
+
for (const key of keys) {
|
|
165
|
+
const a = accessor.getValue(leftId, key.colId);
|
|
166
|
+
const b = accessor.getValue(rightId, key.colId);
|
|
167
|
+
const aBlank = isBlankSortValue(a);
|
|
168
|
+
const bBlank = isBlankSortValue(b);
|
|
169
|
+
if (aBlank || bBlank) {
|
|
170
|
+
if (aBlank && bBlank) continue;
|
|
171
|
+
return aBlank ? 1 : -1;
|
|
172
|
+
}
|
|
173
|
+
const fieldType = accessor.getFieldType?.(key.colId) ?? (key.colId === INDEX_COL_ID ? "index" : void 0);
|
|
174
|
+
const cmp = compareSortValues(
|
|
175
|
+
a,
|
|
176
|
+
b,
|
|
177
|
+
fieldType,
|
|
178
|
+
accessor.getComparator?.(key.colId)
|
|
179
|
+
);
|
|
180
|
+
if (cmp !== 0) return key.sort === "desc" ? -cmp : cmp;
|
|
181
|
+
}
|
|
182
|
+
return leftId - rightId;
|
|
183
|
+
}
|
|
184
|
+
function findSortedInsertIndex(orderedIds, rowId, sortModel, accessor) {
|
|
185
|
+
let lo = 0;
|
|
186
|
+
let hi = orderedIds.length;
|
|
187
|
+
while (lo < hi) {
|
|
188
|
+
const mid = lo + hi >> 1;
|
|
189
|
+
const midId = orderedIds[mid];
|
|
190
|
+
if (compareRowIdsForSort(midId, rowId, sortModel, accessor) <= 0) {
|
|
191
|
+
lo = mid + 1;
|
|
192
|
+
} else {
|
|
193
|
+
hi = mid;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
return lo;
|
|
197
|
+
}
|
|
198
|
+
var HEADER_SORT_CLICK_MAX_MOVE_PX = 5;
|
|
199
|
+
function shouldCommitHeaderSortClick(movedPx) {
|
|
200
|
+
return Number.isFinite(movedPx) && movedPx < HEADER_SORT_CLICK_MAX_MOVE_PX;
|
|
201
|
+
}
|
|
202
|
+
function cycleSortModel(current, colId, options = {}) {
|
|
203
|
+
if (typeof colId !== "string" || colId.length === 0) {
|
|
204
|
+
return current.slice();
|
|
205
|
+
}
|
|
206
|
+
if (colId === INDEX_COL_ID) return current.slice();
|
|
207
|
+
const multi = Boolean(options.multi);
|
|
208
|
+
const existing = current.findIndex((item2) => item2.colId === colId);
|
|
209
|
+
if (!multi) {
|
|
210
|
+
const only = current.length === 1 && current[0]?.colId === colId ? current[0] : null;
|
|
211
|
+
if (!only) return [{ colId, sort: "asc" }];
|
|
212
|
+
if (only.sort === "asc") return [{ colId, sort: "desc" }];
|
|
213
|
+
return [];
|
|
214
|
+
}
|
|
215
|
+
if (existing === -1) {
|
|
216
|
+
return [...current, { colId, sort: "asc" }];
|
|
217
|
+
}
|
|
218
|
+
const item = current[existing];
|
|
219
|
+
if (item?.sort === "asc") {
|
|
220
|
+
return current.map(
|
|
221
|
+
(entry, index) => index === existing ? { colId, sort: "desc" } : entry
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
return current.filter((_, index) => index !== existing);
|
|
225
|
+
}
|
|
226
|
+
function ariaSortForColumn(sortModel, colId) {
|
|
227
|
+
const item = sortModel.find((entry) => entry.colId === colId);
|
|
228
|
+
if (!item) return "none";
|
|
229
|
+
return item.sort === "asc" ? "ascending" : "descending";
|
|
230
|
+
}
|
|
231
|
+
function sortPriorityForColumn(sortModel, colId) {
|
|
232
|
+
const index = sortModel.findIndex((entry) => entry.colId === colId);
|
|
233
|
+
return index >= 0 ? index + 1 : void 0;
|
|
234
|
+
}
|
|
235
|
+
function isHeaderColumnSortable(col) {
|
|
236
|
+
if (col.fieldName === INDEX_COL_ID || col.fieldType === "index") return false;
|
|
237
|
+
if (col.columnDef?.sortable === false) return false;
|
|
238
|
+
return true;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export { HEADER_SORT_CLICK_MAX_MOVE_PX, INDEX_COL_ID, applySort, ariaSortForColumn, compareSortValues, compareTypedValues, cycleSortModel, findSortedInsertIndex, isBlankSortValue, isHeaderColumnSortable, normalizeDigits, shouldCommitHeaderSortClick, sortPriorityForColumn };
|
|
242
|
+
//# sourceMappingURL=chunk-AU3RDJYQ.js.map
|
|
243
|
+
//# sourceMappingURL=chunk-AU3RDJYQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../engine/dataOps/sortModel.ts"],"names":["item"],"mappings":"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","file":"chunk-AU3RDJYQ.js","sourcesContent":["import type { FieldType } from '../../domain/types/ColumnSchema';\r\n\r\n/** Document-order column used as the final tie-breaker (PR-89). */\r\nexport const INDEX_COL_ID = 'index';\r\n\r\nexport type SortDirection = 'asc' | 'desc';\r\n\r\nexport type SortModelItem = {\r\n colId: string;\r\n sort: SortDirection;\r\n};\r\n\r\nexport type SortModel = readonly SortModelItem[];\r\n\r\nexport type SortValueComparator = (a: unknown, b: unknown) => number;\r\n\r\nexport type SortAccessor = {\r\n getValue: (rowId: number, colId: string) => unknown;\r\n getFieldType?: (colId: string) => FieldType | undefined;\r\n getComparator?: (colId: string) => SortValueComparator | undefined;\r\n};\r\n\r\nconst FA_COLLATOR = new Intl.Collator('fa', {\r\n numeric: true,\r\n sensitivity: 'base',\r\n});\r\n\r\nconst EASTERN_DIGITS = /[۰-۹٠-٩]/g;\r\nconst EASTERN_DIGIT_MAP: Record<string, string> = {\r\n '۰': '0',\r\n '۱': '1',\r\n '۲': '2',\r\n '۳': '3',\r\n '۴': '4',\r\n '۵': '5',\r\n '۶': '6',\r\n '۷': '7',\r\n '۸': '8',\r\n '۹': '9',\r\n '٠': '0',\r\n '١': '1',\r\n '٢': '2',\r\n '٣': '3',\r\n '٤': '4',\r\n '٥': '5',\r\n '٦': '6',\r\n '٧': '7',\r\n '٨': '8',\r\n '٩': '9',\r\n};\r\n\r\nexport function normalizeDigits(value: string): string {\r\n return value.replace(EASTERN_DIGITS, (ch) => EASTERN_DIGIT_MAP[ch] ?? ch);\r\n}\r\n\r\nexport function isBlankSortValue(value: unknown): boolean {\r\n if (value == null) return true;\r\n if (typeof value === 'number' && Number.isNaN(value)) return true;\r\n if (typeof value === 'string' && value.trim() === '') return true;\r\n return false;\r\n}\r\n\r\nfunction toNumber(value: unknown): number | null {\r\n if (typeof value === 'number') {\r\n return Number.isFinite(value) ? value : null;\r\n }\r\n if (typeof value === 'boolean') return value ? 1 : 0;\r\n if (typeof value === 'string') {\r\n const n = Number(normalizeDigits(value).replace(/,/g, '').trim());\r\n return Number.isFinite(n) ? n : null;\r\n }\r\n return null;\r\n}\r\n\r\nfunction toDateKey(value: unknown): number | null {\r\n if (value instanceof Date) {\r\n const t = value.getTime();\r\n return Number.isNaN(t) ? null : t;\r\n }\r\n if (typeof value === 'number' && Number.isFinite(value)) return value;\r\n if (typeof value === 'string') {\r\n const text = normalizeDigits(value).trim();\r\n if (!text) return null;\r\n const parsed = Date.parse(text);\r\n if (!Number.isNaN(parsed)) return parsed;\r\n const digits = text.replace(/\\D/g, '');\r\n if (digits.length >= 8) return Number(digits.slice(0, 8));\r\n }\r\n return null;\r\n}\r\n\r\nfunction toBoolean(value: unknown): boolean | null {\r\n if (typeof value === 'boolean') return value;\r\n if (value === 1 || value === '1' || value === 'true') return true;\r\n if (value === 0 || value === '0' || value === 'false') return false;\r\n return null;\r\n}\r\n\r\nfunction compareText(a: unknown, b: unknown): number {\r\n return FA_COLLATOR.compare(String(a), String(b));\r\n}\r\n\r\nfunction compareFinite(a: number, b: number): number {\r\n return a < b ? -1 : a > b ? 1 : 0;\r\n}\r\n\r\n/**\r\n * Ascending compare for a FieldType. Blank handling is done by `compareSortValues`.\r\n */\r\nexport function compareTypedValues(\r\n a: unknown,\r\n b: unknown,\r\n fieldType: FieldType | undefined,\r\n): number {\r\n switch (fieldType) {\r\n case 'number':\r\n case 'price':\r\n case 'index': {\r\n const na = toNumber(a);\r\n const nb = toNumber(b);\r\n if (na == null && nb == null) return compareText(a, b);\r\n if (na == null) return 1;\r\n if (nb == null) return -1;\r\n return compareFinite(na, nb);\r\n }\r\n case 'date': {\r\n const da = toDateKey(a);\r\n const db = toDateKey(b);\r\n if (da == null && db == null) return compareText(a, b);\r\n if (da == null) return 1;\r\n if (db == null) return -1;\r\n return compareFinite(da, db);\r\n }\r\n case 'checkbox': {\r\n const ba = toBoolean(a);\r\n const bb = toBoolean(b);\r\n if (ba == null && bb == null) return compareText(a, b);\r\n if (ba == null) return 1;\r\n if (bb == null) return -1;\r\n return Number(ba) - Number(bb);\r\n }\r\n default:\r\n return compareText(a, b);\r\n }\r\n}\r\n\r\nexport function compareSortValues(\r\n a: unknown,\r\n b: unknown,\r\n fieldType: FieldType | undefined,\r\n comparator: SortValueComparator | undefined,\r\n): number {\r\n if (comparator) return comparator(a, b);\r\n return compareTypedValues(a, b, fieldType);\r\n}\r\n\r\nfunction isSortDirection(value: string): value is SortDirection {\r\n return value === 'asc' || value === 'desc';\r\n}\r\n\r\nfunction resolveKeys(sortModel: SortModel): SortModelItem[] {\r\n const keys: SortModelItem[] = [];\r\n const seen = new Set<string>();\r\n for (const item of sortModel) {\r\n if (!item || typeof item.colId !== 'string' || item.colId.length === 0) {\r\n continue;\r\n }\r\n if (!isSortDirection(item.sort) || seen.has(item.colId)) continue;\r\n seen.add(item.colId);\r\n keys.push({ colId: item.colId, sort: item.sort });\r\n }\r\n if (!seen.has(INDEX_COL_ID)) {\r\n keys.push({ colId: INDEX_COL_ID, sort: 'asc' });\r\n }\r\n return keys;\r\n}\r\n\r\n/**\r\n * Pure multi-sort (PR-89). Does not mutate `rowIds`.\r\n * Null/blank values sort last in both directions. `index` is the last\r\n * tie-breaker so document order is preserved when sort keys match.\r\n */\r\nexport function applySort(\r\n rowIds: readonly number[],\r\n sortModel: SortModel,\r\n accessor: SortAccessor,\r\n): number[] {\r\n const keys = resolveKeys(sortModel);\r\n const decorated = rowIds.map((rowId, originalIndex) => ({\r\n rowId,\r\n originalIndex,\r\n }));\r\n\r\n decorated.sort((left, right) => {\r\n for (const key of keys) {\r\n const a = accessor.getValue(left.rowId, key.colId);\r\n const b = accessor.getValue(right.rowId, key.colId);\r\n const aBlank = isBlankSortValue(a);\r\n const bBlank = isBlankSortValue(b);\r\n if (aBlank || bBlank) {\r\n if (aBlank && bBlank) continue;\r\n return aBlank ? 1 : -1;\r\n }\r\n const fieldType =\r\n accessor.getFieldType?.(key.colId) ??\r\n (key.colId === INDEX_COL_ID ? 'index' : undefined);\r\n const cmp = compareSortValues(\r\n a,\r\n b,\r\n fieldType,\r\n accessor.getComparator?.(key.colId),\r\n );\r\n if (cmp !== 0) return key.sort === 'desc' ? -cmp : cmp;\r\n }\r\n return left.originalIndex - right.originalIndex;\r\n });\r\n\r\n return decorated.map((row) => row.rowId);\r\n}\r\n\r\n/**\r\n * Compare two row ids under the same rules as {@link applySort}\r\n * (without original-index stability — uses id as final tie-break).\r\n * Used for O(log n) binary insert into an already-sorted UI index (PR-99).\r\n */\r\nexport function compareRowIdsForSort(\r\n leftId: number,\r\n rightId: number,\r\n sortModel: SortModel,\r\n accessor: SortAccessor,\r\n): number {\r\n const keys = resolveKeys(sortModel);\r\n for (const key of keys) {\r\n const a = accessor.getValue(leftId, key.colId);\r\n const b = accessor.getValue(rightId, key.colId);\r\n const aBlank = isBlankSortValue(a);\r\n const bBlank = isBlankSortValue(b);\r\n if (aBlank || bBlank) {\r\n if (aBlank && bBlank) continue;\r\n return aBlank ? 1 : -1;\r\n }\r\n const fieldType =\r\n accessor.getFieldType?.(key.colId) ??\r\n (key.colId === INDEX_COL_ID ? 'index' : undefined);\r\n const cmp = compareSortValues(\r\n a,\r\n b,\r\n fieldType,\r\n accessor.getComparator?.(key.colId),\r\n );\r\n if (cmp !== 0) return key.sort === 'desc' ? -cmp : cmp;\r\n }\r\n return leftId - rightId;\r\n}\r\n\r\n/** Binary-search insert position for `rowId` into an already-sorted id list. */\r\nexport function findSortedInsertIndex(\r\n orderedIds: readonly number[],\r\n rowId: number,\r\n sortModel: SortModel,\r\n accessor: SortAccessor,\r\n): number {\r\n let lo = 0;\r\n let hi = orderedIds.length;\r\n while (lo < hi) {\r\n const mid = (lo + hi) >> 1;\r\n const midId = orderedIds[mid]!;\r\n if (compareRowIdsForSort(midId, rowId, sortModel, accessor) <= 0) {\r\n lo = mid + 1;\r\n } else {\r\n hi = mid;\r\n }\r\n }\r\n return lo;\r\n}\r\n\r\n/** Max pointer movement (px) that still counts as a header sort click (PR-91). */\r\nexport const HEADER_SORT_CLICK_MAX_MOVE_PX = 5;\r\n\r\n/**\r\n * True when pointer travel is below the drag threshold so a header click\r\n * should change sort (not a column reorder gesture).\r\n */\r\nexport function shouldCommitHeaderSortClick(movedPx: number): boolean {\r\n return Number.isFinite(movedPx) && movedPx < HEADER_SORT_CLICK_MAX_MOVE_PX;\r\n}\r\n\r\nexport type CycleSortModelOptions = {\r\n /** Shift+Click: keep other columns; otherwise replace with this column. */\r\n multi?: boolean;\r\n};\r\n\r\n/**\r\n * Header click cycle (PR-91): none → asc → desc → none.\r\n * Without `multi`, the model becomes a single column (or empty).\r\n * With `multi`, the column is appended / toggled / removed in place.\r\n */\r\nexport function cycleSortModel(\r\n current: SortModel,\r\n colId: string,\r\n options: CycleSortModelOptions = {},\r\n): SortModel {\r\n if (typeof colId !== 'string' || colId.length === 0) {\r\n return current.slice();\r\n }\r\n if (colId === INDEX_COL_ID) return current.slice();\r\n\r\n const multi = Boolean(options.multi);\r\n const existing = current.findIndex((item) => item.colId === colId);\r\n\r\n if (!multi) {\r\n const only =\r\n current.length === 1 && current[0]?.colId === colId ? current[0] : null;\r\n if (!only) return [{ colId, sort: 'asc' }];\r\n if (only.sort === 'asc') return [{ colId, sort: 'desc' }];\r\n return [];\r\n }\r\n\r\n if (existing === -1) {\r\n return [...current, { colId, sort: 'asc' }];\r\n }\r\n const item = current[existing];\r\n if (item?.sort === 'asc') {\r\n return current.map((entry, index) =>\r\n index === existing ? { colId, sort: 'desc' } : entry,\r\n );\r\n }\r\n return current.filter((_, index) => index !== existing);\r\n}\r\n\r\nexport type AriaSortValue = 'ascending' | 'descending' | 'none';\r\n\r\nexport function ariaSortForColumn(\r\n sortModel: SortModel,\r\n colId: string,\r\n): AriaSortValue {\r\n const item = sortModel.find((entry) => entry.colId === colId);\r\n if (!item) return 'none';\r\n return item.sort === 'asc' ? 'ascending' : 'descending';\r\n}\r\n\r\n/** 1-based priority for multi-sort badge; undefined when column is unsorted. */\r\nexport function sortPriorityForColumn(\r\n sortModel: SortModel,\r\n colId: string,\r\n): number | undefined {\r\n const index = sortModel.findIndex((entry) => entry.colId === colId);\r\n return index >= 0 ? index + 1 : undefined;\r\n}\r\n\r\n/** Index column and `sortable: false` are never header-sortable. */\r\nexport function isHeaderColumnSortable(col: {\r\n fieldName: string;\r\n fieldType?: string;\r\n columnDef?: { sortable?: boolean } | null;\r\n}): boolean {\r\n if (col.fieldName === INDEX_COL_ID || col.fieldType === 'index') return false;\r\n if (col.columnDef?.sortable === false) return false;\r\n return true;\r\n}\r\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// packages/plugins/excel/src/formatExportValue.ts
|
|
4
|
+
function formatExportValue(val, fieldType) {
|
|
5
|
+
if (val == null || val === "") {
|
|
6
|
+
return fieldType === "selectOption" ? "" : "";
|
|
7
|
+
}
|
|
8
|
+
switch (fieldType) {
|
|
9
|
+
case "checkbox":
|
|
10
|
+
return val ? "\u2714" : "\u2718";
|
|
11
|
+
case "price":
|
|
12
|
+
return `${val}`.replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
|
13
|
+
case "date":
|
|
14
|
+
if (typeof val === "string" && val.length > 0) {
|
|
15
|
+
try {
|
|
16
|
+
return new Intl.DateTimeFormat("fa-IR-u-ca-persian", {
|
|
17
|
+
year: "numeric",
|
|
18
|
+
month: "2-digit",
|
|
19
|
+
day: "2-digit"
|
|
20
|
+
}).format(new Date(val));
|
|
21
|
+
} catch {
|
|
22
|
+
return String(val);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
return "";
|
|
26
|
+
default:
|
|
27
|
+
return String(val);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
exports.formatExportValue = formatExportValue;
|
|
32
|
+
//# sourceMappingURL=chunk-BHDRUZH5.cjs.map
|
|
33
|
+
//# sourceMappingURL=chunk-BHDRUZH5.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../packages/plugins/excel/src/formatExportValue.ts"],"names":[],"mappings":";;;AAIO,SAAS,iBAAA,CACd,KACA,SAAA,EACQ;AACR,EAAA,IAAI,GAAA,IAAO,IAAA,IAAQ,GAAA,KAAQ,EAAA,EAAI;AAC7B,IAAA,OAAO,SAAA,KAAc,iBAAiB,EAAA,GAAK,EAAA;AAAA,EAC7C;AAEA,EAAA,QAAQ,SAAA;AAAW,IACjB,KAAK,UAAA;AACH,MAAA,OAAO,MAAM,QAAA,GAAM,QAAA;AAAA,IACrB,KAAK,OAAA;AACH,MAAA,OAAO,CAAA,EAAG,GAAG,CAAA,CAAA,CAAG,OAAA,CAAQ,yBAAyB,GAAG,CAAA;AAAA,IACtD,KAAK,MAAA;AACH,MAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,GAAA,CAAI,SAAS,CAAA,EAAG;AAC7C,QAAA,IAAI;AACF,UAAA,OAAO,IAAI,IAAA,CAAK,cAAA,CAAe,oBAAA,EAAsB;AAAA,YACnD,IAAA,EAAM,SAAA;AAAA,YACN,KAAA,EAAO,SAAA;AAAA,YACP,GAAA,EAAK;AAAA,WACN,CAAA,CAAE,MAAA,CAAO,IAAI,IAAA,CAAK,GAAG,CAAC,CAAA;AAAA,QACzB,CAAA,CAAA,MAAQ;AACN,UAAA,OAAO,OAAO,GAAG,CAAA;AAAA,QACnB;AAAA,MACF;AACA,MAAA,OAAO,EAAA;AAAA,IACT;AACE,MAAA,OAAO,OAAO,GAAG,CAAA;AAAA;AAEvB","file":"chunk-BHDRUZH5.cjs","sourcesContent":["/**\r\n * Pure string formatter for Excel/PDF export (no React).\r\n * Mirrors ui/helper valueParser for common field types.\r\n */\r\nexport function formatExportValue(\r\n val: unknown,\r\n fieldType?: string,\r\n): string {\r\n if (val == null || val === '') {\r\n return fieldType === 'selectOption' ? '' : '';\r\n }\r\n\r\n switch (fieldType) {\r\n case 'checkbox':\r\n return val ? '✔' : '✘';\r\n case 'price':\r\n return `${val}`.replace(/\\B(?=(\\d{3})+(?!\\d))/g, ',');\r\n case 'date':\r\n if (typeof val === 'string' && val.length > 0) {\r\n try {\r\n return new Intl.DateTimeFormat('fa-IR-u-ca-persian', {\r\n year: 'numeric',\r\n month: '2-digit',\r\n day: '2-digit',\r\n }).format(new Date(val));\r\n } catch {\r\n return String(val);\r\n }\r\n }\r\n return '';\r\n default:\r\n return String(val);\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// application/sync/resolveCellConflicts.ts
|
|
4
|
+
function resolveConflictChoice(conflict, policy) {
|
|
5
|
+
if (policy === "manual") return "unresolved";
|
|
6
|
+
if (policy === "serverWins") return "remote";
|
|
7
|
+
if (conflict.remote.version !== conflict.local.version) {
|
|
8
|
+
return conflict.remote.version > conflict.local.version ? "remote" : "local";
|
|
9
|
+
}
|
|
10
|
+
if (conflict.remote.occurredAt !== conflict.local.occurredAt) {
|
|
11
|
+
return conflict.remote.occurredAt > conflict.local.occurredAt ? "remote" : "local";
|
|
12
|
+
}
|
|
13
|
+
return "remote";
|
|
14
|
+
}
|
|
15
|
+
function cellKeyFromPayload(payload) {
|
|
16
|
+
if (!payload || typeof payload !== "object") return null;
|
|
17
|
+
const p = payload;
|
|
18
|
+
const columnId = p.columnId;
|
|
19
|
+
if (typeof columnId !== "string" || !columnId) return null;
|
|
20
|
+
const rowRaw = p.rowId;
|
|
21
|
+
const rowId = typeof rowRaw === "number" ? rowRaw : typeof rowRaw === "string" ? Number(rowRaw) : NaN;
|
|
22
|
+
if (!Number.isFinite(rowId)) return null;
|
|
23
|
+
return { rowId, columnId };
|
|
24
|
+
}
|
|
25
|
+
function cellKeyId(rowId, columnId) {
|
|
26
|
+
return `${rowId}:${columnId}`;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// application/sync/GridSyncService.ts
|
|
30
|
+
function isCellChanged(event) {
|
|
31
|
+
return event.type === "CELL_CHANGED";
|
|
32
|
+
}
|
|
33
|
+
function toSide(event) {
|
|
34
|
+
const payload = event.payload;
|
|
35
|
+
return {
|
|
36
|
+
eventId: event.eventId,
|
|
37
|
+
value: payload?.newValue,
|
|
38
|
+
occurredAt: event.occurredAt,
|
|
39
|
+
version: event.version
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
var GridSyncService = class {
|
|
43
|
+
constructor(options) {
|
|
44
|
+
this.options = options;
|
|
45
|
+
this.openConflicts = [];
|
|
46
|
+
this.conflictListeners = /* @__PURE__ */ new Set();
|
|
47
|
+
/** Remote events waiting on manual resolution (by conflict id). */
|
|
48
|
+
this.deferredRemote = /* @__PURE__ */ new Map();
|
|
49
|
+
this.policy = options.policy ?? "lastWriteWins";
|
|
50
|
+
this.cursor = options.initialCursor ?? 0;
|
|
51
|
+
}
|
|
52
|
+
getPolicy() {
|
|
53
|
+
return this.policy;
|
|
54
|
+
}
|
|
55
|
+
setPolicy(policy) {
|
|
56
|
+
this.policy = policy;
|
|
57
|
+
}
|
|
58
|
+
getOpenConflicts() {
|
|
59
|
+
return this.openConflicts;
|
|
60
|
+
}
|
|
61
|
+
subscribeConflicts(listener) {
|
|
62
|
+
this.conflictListeners.add(listener);
|
|
63
|
+
listener(this.openConflicts);
|
|
64
|
+
return () => this.conflictListeners.delete(listener);
|
|
65
|
+
}
|
|
66
|
+
async sync() {
|
|
67
|
+
const pending = this.options.offlineStatus.getPendingChanges();
|
|
68
|
+
const pushable = pending.map((p) => p.event).filter(
|
|
69
|
+
(e) => Boolean(e) && e.tableId === this.options.tableId
|
|
70
|
+
);
|
|
71
|
+
const { acceptedIds } = await this.options.transport.push(pushable);
|
|
72
|
+
if (acceptedIds.length > 0) {
|
|
73
|
+
this.options.offlineStatus.markSynced([...acceptedIds]);
|
|
74
|
+
}
|
|
75
|
+
const localByCell = /* @__PURE__ */ new Map();
|
|
76
|
+
for (const event of pushable) {
|
|
77
|
+
if (!isCellChanged(event)) continue;
|
|
78
|
+
const key = cellKeyFromPayload(event.payload);
|
|
79
|
+
if (!key) continue;
|
|
80
|
+
localByCell.set(cellKeyId(key.rowId, key.columnId), event);
|
|
81
|
+
}
|
|
82
|
+
for (const event of this.options.offlineStatus.getPendingChanges().map((p) => p.event).filter((e) => Boolean(e))) {
|
|
83
|
+
if (!isCellChanged(event) || event.tableId !== this.options.tableId) {
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
const key = cellKeyFromPayload(event.payload);
|
|
87
|
+
if (!key) continue;
|
|
88
|
+
localByCell.set(cellKeyId(key.rowId, key.columnId), event);
|
|
89
|
+
}
|
|
90
|
+
const pulled = await this.options.transport.pull(this.cursor);
|
|
91
|
+
this.cursor = pulled.cursor;
|
|
92
|
+
let applied = 0;
|
|
93
|
+
const conflicts = [];
|
|
94
|
+
for (const remote of pulled.events) {
|
|
95
|
+
if (remote.tableId !== this.options.tableId) continue;
|
|
96
|
+
if (!isCellChanged(remote)) {
|
|
97
|
+
await this.ingestRemote(remote);
|
|
98
|
+
applied += 1;
|
|
99
|
+
continue;
|
|
100
|
+
}
|
|
101
|
+
const key = cellKeyFromPayload(remote.payload);
|
|
102
|
+
if (!key) continue;
|
|
103
|
+
const id = cellKeyId(key.rowId, key.columnId);
|
|
104
|
+
const local = localByCell.get(id);
|
|
105
|
+
if (local && toSide(local).value !== toSide(remote).value) {
|
|
106
|
+
const conflict = {
|
|
107
|
+
id: `conflict:${id}:${remote.eventId}`,
|
|
108
|
+
key,
|
|
109
|
+
local: toSide(local),
|
|
110
|
+
remote: toSide(remote)
|
|
111
|
+
};
|
|
112
|
+
const choice = resolveConflictChoice(conflict, this.policy);
|
|
113
|
+
if (choice === "unresolved") {
|
|
114
|
+
conflicts.push(conflict);
|
|
115
|
+
this.deferredRemote.set(conflict.id, remote);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (choice === "remote") {
|
|
119
|
+
await this.applyRemoteCell(remote, key.rowId, key.columnId);
|
|
120
|
+
this.options.offlineStatus.markSynced([local.eventId]);
|
|
121
|
+
applied += 1;
|
|
122
|
+
} else {
|
|
123
|
+
await this.ingestRemote(remote);
|
|
124
|
+
}
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
await this.applyRemoteCell(remote, key.rowId, key.columnId);
|
|
128
|
+
applied += 1;
|
|
129
|
+
}
|
|
130
|
+
this.openConflicts = [
|
|
131
|
+
...this.openConflicts.filter((c) => this.deferredRemote.has(c.id)),
|
|
132
|
+
...conflicts
|
|
133
|
+
];
|
|
134
|
+
this.emitConflicts();
|
|
135
|
+
return {
|
|
136
|
+
pushed: acceptedIds.length,
|
|
137
|
+
pulled: pulled.events.length,
|
|
138
|
+
applied,
|
|
139
|
+
conflicts: this.openConflicts
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
async resolveConflict(conflictId, choice) {
|
|
143
|
+
const conflict = this.openConflicts.find((c) => c.id === conflictId);
|
|
144
|
+
const remote = this.deferredRemote.get(conflictId);
|
|
145
|
+
if (!conflict || !remote) return;
|
|
146
|
+
if (choice === "remote") {
|
|
147
|
+
await this.applyRemoteCell(
|
|
148
|
+
remote,
|
|
149
|
+
conflict.key.rowId,
|
|
150
|
+
conflict.key.columnId
|
|
151
|
+
);
|
|
152
|
+
this.options.offlineStatus.markSynced([conflict.local.eventId]);
|
|
153
|
+
} else {
|
|
154
|
+
await this.ingestRemote(remote);
|
|
155
|
+
}
|
|
156
|
+
this.deferredRemote.delete(conflictId);
|
|
157
|
+
this.openConflicts = this.openConflicts.filter((c) => c.id !== conflictId);
|
|
158
|
+
this.emitConflicts();
|
|
159
|
+
}
|
|
160
|
+
async applyRemoteCell(remote, rowId, columnId) {
|
|
161
|
+
await this.ingestRemote(remote);
|
|
162
|
+
const before = new Set(
|
|
163
|
+
this.options.offlineStatus.getPendingChanges().map((p) => p.eventId)
|
|
164
|
+
);
|
|
165
|
+
const value = remote.payload?.newValue;
|
|
166
|
+
await this.options.applyCellValue(rowId, columnId, value);
|
|
167
|
+
const created = this.options.offlineStatus.getPendingChanges().filter((p) => !before.has(p.eventId)).map((p) => p.eventId);
|
|
168
|
+
if (created.length > 0) {
|
|
169
|
+
this.options.offlineStatus.markSynced(created);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async ingestRemote(remote) {
|
|
173
|
+
const streamId = remote.streamId || `table:${remote.tableId}`;
|
|
174
|
+
const existing = await this.options.eventStore.read(streamId);
|
|
175
|
+
if (existing.some((e) => e.eventId === remote.eventId)) {
|
|
176
|
+
this.options.offlineStatus.markSynced([remote.eventId]);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
await this.options.eventStore.append(streamId, [remote], -1);
|
|
180
|
+
this.options.offlineStatus.markSynced([remote.eventId]);
|
|
181
|
+
}
|
|
182
|
+
emitConflicts() {
|
|
183
|
+
for (const listener of this.conflictListeners) {
|
|
184
|
+
listener(this.openConflicts);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
exports.GridSyncService = GridSyncService;
|
|
190
|
+
//# sourceMappingURL=chunk-BLYVOV3G.cjs.map
|
|
191
|
+
//# sourceMappingURL=chunk-BLYVOV3G.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../application/sync/resolveCellConflicts.ts","../application/sync/GridSyncService.ts"],"names":[],"mappings":"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","file":"chunk-BLYVOV3G.cjs","sourcesContent":["import type {\r\n SyncConflict,\r\n SyncConflictPolicy,\r\n ManualResolution,\r\n} from '../ports/SyncPort';\r\n\r\n/**\r\n * Pure conflict resolution (PR-138).\r\n * `manual` always returns unresolved so the UI can choose.\r\n */\r\nexport function resolveConflictChoice(\r\n conflict: SyncConflict,\r\n policy: SyncConflictPolicy,\r\n): ManualResolution | 'unresolved' {\r\n if (policy === 'manual') return 'unresolved';\r\n if (policy === 'serverWins') return 'remote';\r\n // lastWriteWins — tie-break on version then occurredAt\r\n if (conflict.remote.version !== conflict.local.version) {\r\n return conflict.remote.version > conflict.local.version\r\n ? 'remote'\r\n : 'local';\r\n }\r\n if (conflict.remote.occurredAt !== conflict.local.occurredAt) {\r\n return conflict.remote.occurredAt > conflict.local.occurredAt\r\n ? 'remote'\r\n : 'local';\r\n }\r\n return 'remote';\r\n}\r\n\r\nexport function cellKeyFromPayload(\r\n payload: unknown,\r\n): { rowId: number; columnId: string } | null {\r\n if (!payload || typeof payload !== 'object') return null;\r\n const p = payload as Record<string, unknown>;\r\n const columnId = p.columnId;\r\n if (typeof columnId !== 'string' || !columnId) return null;\r\n const rowRaw = p.rowId;\r\n const rowId =\r\n typeof rowRaw === 'number'\r\n ? rowRaw\r\n : typeof rowRaw === 'string'\r\n ? Number(rowRaw)\r\n : NaN;\r\n if (!Number.isFinite(rowId)) return null;\r\n return { rowId, columnId };\r\n}\r\n\r\nexport function cellKeyId(rowId: number, columnId: string): string {\r\n return `${rowId}:${columnId}`;\r\n}\r\n","import type { EventStore } from '../ports/EventStore';\r\nimport type { GridEvent } from '../../domain/types/GridEvent';\r\nimport type { OfflineStatus } from '../offline/OfflineStatus';\r\nimport type {\r\n ManualResolution,\r\n SyncConflict,\r\n SyncConflictPolicy,\r\n SyncPort,\r\n SyncResult,\r\n SyncTransport,\r\n} from '../ports/SyncPort';\r\nimport {\r\n cellKeyFromPayload,\r\n cellKeyId,\r\n resolveConflictChoice,\r\n} from './resolveCellConflicts';\r\n\r\nexport type GridSyncServiceOptions = {\r\n readonly tableId: string;\r\n readonly eventStore: EventStore;\r\n readonly offlineStatus: OfflineStatus;\r\n readonly transport: SyncTransport;\r\n /** Apply a winning remote CELL_CHANGED into the local domain. */\r\n readonly applyCellValue: (\r\n rowId: number,\r\n columnId: string,\r\n value: unknown,\r\n ) => Promise<void>;\r\n /** Initial pull cursor (default 0). */\r\n readonly initialCursor?: number;\r\n readonly policy?: SyncConflictPolicy;\r\n};\r\n\r\nfunction isCellChanged(event: GridEvent): boolean {\r\n return event.type === 'CELL_CHANGED';\r\n}\r\n\r\nfunction toSide(event: GridEvent): SyncConflict['local'] {\r\n const payload = event.payload as { newValue?: unknown };\r\n return {\r\n eventId: event.eventId,\r\n value: payload?.newValue,\r\n occurredAt: event.occurredAt,\r\n version: event.version,\r\n };\r\n}\r\n\r\n/**\r\n * SyncPort implementation over EventStore + OfflineStatus + SyncTransport (PR-138).\r\n */\r\nexport class GridSyncService implements SyncPort {\r\n private policy: SyncConflictPolicy;\r\n private cursor: number;\r\n private openConflicts: SyncConflict[] = [];\r\n private readonly conflictListeners = new Set<\r\n (conflicts: readonly SyncConflict[]) => void\r\n >();\r\n /** Remote events waiting on manual resolution (by conflict id). */\r\n private readonly deferredRemote = new Map<string, GridEvent>();\r\n\r\n constructor(private readonly options: GridSyncServiceOptions) {\r\n this.policy = options.policy ?? 'lastWriteWins';\r\n this.cursor = options.initialCursor ?? 0;\r\n }\r\n\r\n getPolicy(): SyncConflictPolicy {\r\n return this.policy;\r\n }\r\n\r\n setPolicy(policy: SyncConflictPolicy): void {\r\n this.policy = policy;\r\n }\r\n\r\n getOpenConflicts(): readonly SyncConflict[] {\r\n return this.openConflicts;\r\n }\r\n\r\n subscribeConflicts(\r\n listener: (conflicts: readonly SyncConflict[]) => void,\r\n ): () => void {\r\n this.conflictListeners.add(listener);\r\n listener(this.openConflicts);\r\n return () => this.conflictListeners.delete(listener);\r\n }\r\n\r\n async sync(): Promise<SyncResult> {\r\n const pending = this.options.offlineStatus.getPendingChanges();\r\n const pushable = pending\r\n .map((p) => p.event)\r\n .filter(\r\n (e): e is GridEvent =>\r\n Boolean(e) && e.tableId === this.options.tableId,\r\n );\r\n\r\n const { acceptedIds } = await this.options.transport.push(pushable);\r\n if (acceptedIds.length > 0) {\r\n this.options.offlineStatus.markSynced([...acceptedIds]);\r\n }\r\n\r\n // Locals just pushed (or still pending) — used to detect cell conflicts on pull.\r\n const localByCell = new Map<string, GridEvent>();\r\n for (const event of pushable) {\r\n if (!isCellChanged(event)) continue;\r\n const key = cellKeyFromPayload(event.payload);\r\n if (!key) continue;\r\n localByCell.set(cellKeyId(key.rowId, key.columnId), event);\r\n }\r\n for (const event of this.options.offlineStatus\r\n .getPendingChanges()\r\n .map((p) => p.event)\r\n .filter((e): e is GridEvent => Boolean(e))) {\r\n if (!isCellChanged(event) || event.tableId !== this.options.tableId) {\r\n continue;\r\n }\r\n const key = cellKeyFromPayload(event.payload);\r\n if (!key) continue;\r\n localByCell.set(cellKeyId(key.rowId, key.columnId), event);\r\n }\r\n\r\n const pulled = await this.options.transport.pull(this.cursor);\r\n this.cursor = pulled.cursor;\r\n\r\n let applied = 0;\r\n const conflicts: SyncConflict[] = [];\r\n\r\n for (const remote of pulled.events) {\r\n if (remote.tableId !== this.options.tableId) continue;\r\n if (!isCellChanged(remote)) {\r\n await this.ingestRemote(remote);\r\n applied += 1;\r\n continue;\r\n }\r\n const key = cellKeyFromPayload(remote.payload);\r\n if (!key) continue;\r\n const id = cellKeyId(key.rowId, key.columnId);\r\n const local = localByCell.get(id);\r\n if (local && toSide(local).value !== toSide(remote).value) {\r\n const conflict: SyncConflict = {\r\n id: `conflict:${id}:${remote.eventId}`,\r\n key,\r\n local: toSide(local),\r\n remote: toSide(remote),\r\n };\r\n const choice = resolveConflictChoice(conflict, this.policy);\r\n if (choice === 'unresolved') {\r\n conflicts.push(conflict);\r\n this.deferredRemote.set(conflict.id, remote);\r\n continue;\r\n }\r\n if (choice === 'remote') {\r\n await this.applyRemoteCell(remote, key.rowId, key.columnId);\r\n this.options.offlineStatus.markSynced([local.eventId]);\r\n applied += 1;\r\n } else {\r\n // Keep local — acknowledge remote without applying its value\r\n await this.ingestRemote(remote);\r\n }\r\n continue;\r\n }\r\n await this.applyRemoteCell(remote, key.rowId, key.columnId);\r\n applied += 1;\r\n }\r\n\r\n this.openConflicts = [\r\n ...this.openConflicts.filter((c) => this.deferredRemote.has(c.id)),\r\n ...conflicts,\r\n ];\r\n this.emitConflicts();\r\n\r\n return {\r\n pushed: acceptedIds.length,\r\n pulled: pulled.events.length,\r\n applied,\r\n conflicts: this.openConflicts,\r\n };\r\n }\r\n\r\n async resolveConflict(\r\n conflictId: string,\r\n choice: ManualResolution,\r\n ): Promise<void> {\r\n const conflict = this.openConflicts.find((c) => c.id === conflictId);\r\n const remote = this.deferredRemote.get(conflictId);\r\n if (!conflict || !remote) return;\r\n\r\n if (choice === 'remote') {\r\n await this.applyRemoteCell(\r\n remote,\r\n conflict.key.rowId,\r\n conflict.key.columnId,\r\n );\r\n this.options.offlineStatus.markSynced([conflict.local.eventId]);\r\n } else {\r\n await this.ingestRemote(remote);\r\n }\r\n\r\n this.deferredRemote.delete(conflictId);\r\n this.openConflicts = this.openConflicts.filter((c) => c.id !== conflictId);\r\n this.emitConflicts();\r\n }\r\n\r\n private async applyRemoteCell(\r\n remote: GridEvent,\r\n rowId: number,\r\n columnId: string,\r\n ): Promise<void> {\r\n await this.ingestRemote(remote);\r\n const before = new Set(\r\n this.options.offlineStatus.getPendingChanges().map((p) => p.eventId),\r\n );\r\n const value = (remote.payload as { newValue?: unknown })?.newValue;\r\n await this.options.applyCellValue(rowId, columnId, value);\r\n // CHANGE_CELL_VALUE may dual-write a new local event — treat as synced.\r\n const created = this.options.offlineStatus\r\n .getPendingChanges()\r\n .filter((p) => !before.has(p.eventId))\r\n .map((p) => p.eventId);\r\n if (created.length > 0) {\r\n this.options.offlineStatus.markSynced(created);\r\n }\r\n }\r\n\r\n private async ingestRemote(remote: GridEvent): Promise<void> {\r\n const streamId = remote.streamId || `table:${remote.tableId}`;\r\n const existing = await this.options.eventStore.read(streamId);\r\n if (existing.some((e) => e.eventId === remote.eventId)) {\r\n this.options.offlineStatus.markSynced([remote.eventId]);\r\n return;\r\n }\r\n await this.options.eventStore.append(streamId, [remote], -1);\r\n // Remote ingest must not look like a local pending mutation.\r\n this.options.offlineStatus.markSynced([remote.eventId]);\r\n }\r\n\r\n private emitConflicts(): void {\r\n for (const listener of this.conflictListeners) {\r\n listener(this.openConflicts);\r\n }\r\n }\r\n}\r\n"]}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkSX4VQXAA_cjs = require('./chunk-SX4VQXAA.cjs');
|
|
4
|
+
var chunkQZN7R2WP_cjs = require('./chunk-QZN7R2WP.cjs');
|
|
5
|
+
var chunkZ4QPZ3Z3_cjs = require('./chunk-Z4QPZ3Z3.cjs');
|
|
6
|
+
|
|
7
|
+
// ui/locales/types.ts
|
|
8
|
+
var LOCALE_META = {
|
|
9
|
+
fa: {
|
|
10
|
+
locale: "fa",
|
|
11
|
+
dir: "rtl",
|
|
12
|
+
intlLocale: "fa-IR",
|
|
13
|
+
numberingSystem: "arabext",
|
|
14
|
+
calendar: "persian"
|
|
15
|
+
},
|
|
16
|
+
en: {
|
|
17
|
+
locale: "en",
|
|
18
|
+
dir: "ltr",
|
|
19
|
+
intlLocale: "en-US",
|
|
20
|
+
numberingSystem: "latn",
|
|
21
|
+
calendar: "gregory"
|
|
22
|
+
},
|
|
23
|
+
ar: {
|
|
24
|
+
locale: "ar",
|
|
25
|
+
dir: "rtl",
|
|
26
|
+
intlLocale: "ar-SA",
|
|
27
|
+
numberingSystem: "arab",
|
|
28
|
+
calendar: "gregory"
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
function resolveLocaleMeta(locale, overrides) {
|
|
32
|
+
const base = LOCALE_META[locale] ?? LOCALE_META.fa;
|
|
33
|
+
if (!overrides?.numberingSystem) return base;
|
|
34
|
+
return { ...base, numberingSystem: overrides.numberingSystem };
|
|
35
|
+
}
|
|
36
|
+
function resolveDirection(locale, override) {
|
|
37
|
+
if (override === "rtl" || override === "ltr") return override;
|
|
38
|
+
return (LOCALE_META[locale] ?? LOCALE_META.fa).dir;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// ui/locales/index.ts
|
|
42
|
+
var LOCALE_PACKS = {
|
|
43
|
+
fa: chunkSX4VQXAA_cjs.faMessages,
|
|
44
|
+
en: chunkQZN7R2WP_cjs.enMessages,
|
|
45
|
+
ar: chunkZ4QPZ3Z3_cjs.arMessages
|
|
46
|
+
};
|
|
47
|
+
function getLocalePack(locale) {
|
|
48
|
+
return LOCALE_PACKS[locale] ?? chunkSX4VQXAA_cjs.faMessages;
|
|
49
|
+
}
|
|
50
|
+
function metaFor(options) {
|
|
51
|
+
const locale = options?.locale ?? "fa";
|
|
52
|
+
return resolveLocaleMeta(locale, {
|
|
53
|
+
numberingSystem: options?.numberingSystem
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
function formatLocaleNumber(value, options) {
|
|
57
|
+
if (value == null || value === "") return "";
|
|
58
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
59
|
+
if (!Number.isFinite(n)) return String(value);
|
|
60
|
+
const meta = metaFor(options);
|
|
61
|
+
const {
|
|
62
|
+
locale: _l,
|
|
63
|
+
numberingSystem: ns,
|
|
64
|
+
...intlOpts
|
|
65
|
+
} = options ?? {};
|
|
66
|
+
return new Intl.NumberFormat(meta.intlLocale, {
|
|
67
|
+
numberingSystem: ns ?? meta.numberingSystem,
|
|
68
|
+
...intlOpts
|
|
69
|
+
}).format(n);
|
|
70
|
+
}
|
|
71
|
+
function formatLocaleDate(value, options) {
|
|
72
|
+
if (value == null || value === "") return null;
|
|
73
|
+
const date = typeof value === "number" ? new Date(value) : new Date(String(value));
|
|
74
|
+
if (Number.isNaN(date.getTime())) return null;
|
|
75
|
+
const meta = metaFor(options);
|
|
76
|
+
const {
|
|
77
|
+
locale: _l,
|
|
78
|
+
numberingSystem: ns,
|
|
79
|
+
...intlOpts
|
|
80
|
+
} = options ?? {};
|
|
81
|
+
const calendar = meta.calendar === "persian" ? "persian" : meta.calendar === "islamic" ? "islamic" : "gregory";
|
|
82
|
+
return new Intl.DateTimeFormat(meta.intlLocale, {
|
|
83
|
+
calendar,
|
|
84
|
+
numberingSystem: ns ?? meta.numberingSystem,
|
|
85
|
+
year: "numeric",
|
|
86
|
+
month: "2-digit",
|
|
87
|
+
day: "2-digit",
|
|
88
|
+
...intlOpts
|
|
89
|
+
}).format(date);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
exports.LOCALE_META = LOCALE_META;
|
|
93
|
+
exports.LOCALE_PACKS = LOCALE_PACKS;
|
|
94
|
+
exports.formatLocaleDate = formatLocaleDate;
|
|
95
|
+
exports.formatLocaleNumber = formatLocaleNumber;
|
|
96
|
+
exports.getLocalePack = getLocalePack;
|
|
97
|
+
exports.resolveDirection = resolveDirection;
|
|
98
|
+
exports.resolveLocaleMeta = resolveLocaleMeta;
|
|
99
|
+
//# sourceMappingURL=chunk-CILNIWYW.cjs.map
|
|
100
|
+
//# sourceMappingURL=chunk-CILNIWYW.cjs.map
|