persian-data-grid 0.6.0 → 0.7.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.
Files changed (137) hide show
  1. package/README.md +1 -1
  2. package/dist/{ERPTableGroupRow-PSAPAHGL.js → ERPTableGroupRow-E5Q6FYDS.js} +4 -4
  3. package/dist/{ERPTableGroupRow-PSAPAHGL.js.map → ERPTableGroupRow-E5Q6FYDS.js.map} +1 -1
  4. package/dist/{ERPTableGroupRow-J5Z2LRC5.cjs → ERPTableGroupRow-F2IPDYL5.cjs} +9 -9
  5. package/dist/{ERPTableGroupRow-J5Z2LRC5.cjs.map → ERPTableGroupRow-F2IPDYL5.cjs.map} +1 -1
  6. package/dist/{GridPlugin-CJCaYnlw.d.ts → GridPlugin-Bewn0X51.d.ts} +1 -1
  7. package/dist/{GridPlugin-oxhq8AsM.d.cts → GridPlugin-DewWufGZ.d.cts} +1 -1
  8. package/dist/{GridSession-Bc7UIawO.d.ts → GridSession-CeIfVFck.d.ts} +142 -9
  9. package/dist/{GridSession-B-9lLcoB.d.cts → GridSession-CmQn2RnL.d.cts} +142 -9
  10. package/dist/GridSyncService-3JQLEY65.cjs +12 -0
  11. package/dist/{GridSyncService-TAPAHABV.cjs.map → GridSyncService-3JQLEY65.cjs.map} +1 -1
  12. package/dist/GridSyncService-GECXGEKL.js +3 -0
  13. package/dist/{GridSyncService-KTLB4KP3.js.map → GridSyncService-GECXGEKL.js.map} +1 -1
  14. package/dist/{PdfRenderer-CBg7hWNS.d.cts → PdfRenderer-B9FJaCo_.d.cts} +1 -1
  15. package/dist/{PdfRenderer-1HFh6UeR.d.ts → PdfRenderer-bN7ca_Aj.d.ts} +1 -1
  16. package/dist/{UITableController-DU8RopUM.d.ts → UITableController-C71LXBiX.d.ts} +48 -2
  17. package/dist/{UITableController-Cuwq481K.d.cts → UITableController-CIwnHIw8.d.cts} +48 -2
  18. package/dist/{VazirmatnPdfRenderer-BCMpC1zy.d.cts → VazirmatnPdfRenderer-CpCqA-Wh.d.cts} +2 -2
  19. package/dist/{VazirmatnPdfRenderer-Dz_G-m3c.d.ts → VazirmatnPdfRenderer-D46smncn.d.ts} +2 -2
  20. package/dist/adapters/arian-erp.cjs +16 -4
  21. package/dist/adapters/arian-erp.cjs.map +1 -1
  22. package/dist/adapters/arian-erp.d.cts +3 -1
  23. package/dist/adapters/arian-erp.d.ts +3 -1
  24. package/dist/adapters/arian-erp.js +11 -3
  25. package/dist/adapters/arian-erp.js.map +1 -1
  26. package/dist/{applyImportedRows-BO6yxoAN.d.cts → applyImportedRows-C2fWYoPy.d.cts} +3 -3
  27. package/dist/{applyImportedRows-D4zVY8uD.d.ts → applyImportedRows-Cqh_N_0k.d.ts} +3 -3
  28. package/dist/{applyRowVisibilityHandler-LXCOGESZ.cjs → applyRowVisibilityHandler-Q64ZFC7A.cjs} +7 -6
  29. package/dist/applyRowVisibilityHandler-Q64ZFC7A.cjs.map +1 -0
  30. package/dist/{applyRowVisibilityHandler-KS6TMCBN.js → applyRowVisibilityHandler-ZLZXQEGY.js} +6 -5
  31. package/dist/applyRowVisibilityHandler-ZLZXQEGY.js.map +1 -0
  32. package/dist/callbackRemoteApi-BYLjmSI6.d.ts +51 -0
  33. package/dist/callbackRemoteApi-Cv26MmSD.d.cts +51 -0
  34. package/dist/{cellRenderContext-DB7V_mlu.d.ts → cellRenderContext-BaNh4qn_.d.ts} +2 -2
  35. package/dist/{cellRenderContext-DG5BOlxK.d.cts → cellRenderContext-DvngkptV.d.cts} +2 -2
  36. package/dist/{chunk-HTNJT2QU.js → chunk-27ALJSZP.js} +617 -104
  37. package/dist/chunk-27ALJSZP.js.map +1 -0
  38. package/dist/{chunk-KUBVDIF7.cjs → chunk-3HP3HQCW.cjs} +52 -17
  39. package/dist/chunk-3HP3HQCW.cjs.map +1 -0
  40. package/dist/{chunk-DXRCYW42.cjs → chunk-52LFOPXD.cjs} +43 -23
  41. package/dist/chunk-52LFOPXD.cjs.map +1 -0
  42. package/dist/{chunk-VVGYRZ7S.cjs → chunk-72IVAOTK.cjs} +4 -4
  43. package/dist/{chunk-VVGYRZ7S.cjs.map → chunk-72IVAOTK.cjs.map} +1 -1
  44. package/dist/{chunk-LJ7LMEXO.js → chunk-7GWV5HGO.js} +3 -3
  45. package/dist/{chunk-LJ7LMEXO.js.map → chunk-7GWV5HGO.js.map} +1 -1
  46. package/dist/{chunk-RM6ZWNT3.js → chunk-7T6AWRPU.js} +43 -23
  47. package/dist/chunk-7T6AWRPU.js.map +1 -0
  48. package/dist/{chunk-PXCHPZTP.cjs → chunk-CMQ4VLCW.cjs} +8 -7
  49. package/dist/{chunk-EHHHC5JV.js.map → chunk-CMQ4VLCW.cjs.map} +1 -1
  50. package/dist/chunk-E2J533UH.cjs +53 -0
  51. package/dist/chunk-E2J533UH.cjs.map +1 -0
  52. package/dist/chunk-F6EMC75A.cjs +34 -0
  53. package/dist/chunk-F6EMC75A.cjs.map +1 -0
  54. package/dist/chunk-GKE33FOJ.js +32 -0
  55. package/dist/chunk-GKE33FOJ.js.map +1 -0
  56. package/dist/{chunk-QQMU44KJ.js → chunk-HLOHWFOA.js} +52 -19
  57. package/dist/chunk-HLOHWFOA.js.map +1 -0
  58. package/dist/{chunk-633KP74Z.js → chunk-KCNTKYUY.js} +19 -2
  59. package/dist/chunk-KCNTKYUY.js.map +1 -0
  60. package/dist/{chunk-BLYVOV3G.cjs → chunk-LY27YAXE.cjs} +19 -2
  61. package/dist/chunk-LY27YAXE.cjs.map +1 -0
  62. package/dist/{chunk-EHHHC5JV.js → chunk-NB5GCGHL.js} +5 -4
  63. package/dist/chunk-NB5GCGHL.js.map +1 -0
  64. package/dist/{chunk-6XBXZPBW.js → chunk-NQUVAJQA.js} +3 -3
  65. package/dist/{chunk-6XBXZPBW.js.map → chunk-NQUVAJQA.js.map} +1 -1
  66. package/dist/chunk-SVO62ZV2.js +50 -0
  67. package/dist/chunk-SVO62ZV2.js.map +1 -0
  68. package/dist/{chunk-MU3RY46O.js → chunk-VBAZ77Q4.js} +3 -3
  69. package/dist/{chunk-MU3RY46O.js.map → chunk-VBAZ77Q4.js.map} +1 -1
  70. package/dist/{chunk-H2LESGMX.cjs → chunk-VSAFQTW5.cjs} +4 -4
  71. package/dist/{chunk-H2LESGMX.cjs.map → chunk-VSAFQTW5.cjs.map} +1 -1
  72. package/dist/{chunk-2BJCRYOS.cjs → chunk-VYJQ2HTA.cjs} +5 -5
  73. package/dist/{chunk-2BJCRYOS.cjs.map → chunk-VYJQ2HTA.cjs.map} +1 -1
  74. package/dist/{chunk-IIISFUW4.cjs → chunk-WTHTVKVI.cjs} +621 -108
  75. package/dist/chunk-WTHTVKVI.cjs.map +1 -0
  76. package/dist/{createEngineGridQuery-Mt1hc33m.d.ts → createEngineGridQuery-BBkud5oE.d.ts} +61 -6
  77. package/dist/{createEngineGridQuery-Dmq3i5v3.d.cts → createEngineGridQuery-D-fgO_jg.d.cts} +61 -6
  78. package/dist/date-picker-jalali.cjs +17 -17
  79. package/dist/date-picker-jalali.d.cts +3 -3
  80. package/dist/date-picker-jalali.d.ts +3 -3
  81. package/dist/date-picker-jalali.js +1 -1
  82. package/dist/headless.cjs +102 -102
  83. package/dist/headless.d.cts +13 -9
  84. package/dist/headless.d.ts +13 -9
  85. package/dist/headless.js +4 -4
  86. package/dist/index.cjs +440 -382
  87. package/dist/index.cjs.map +1 -1
  88. package/dist/index.d.cts +34 -14
  89. package/dist/index.d.ts +34 -14
  90. package/dist/index.js +200 -143
  91. package/dist/index.js.map +1 -1
  92. package/dist/plugins/csv.cjs +3 -3
  93. package/dist/plugins/csv.d.cts +2 -2
  94. package/dist/plugins/csv.d.ts +2 -2
  95. package/dist/plugins/csv.js +2 -2
  96. package/dist/plugins/excel.cjs +11 -11
  97. package/dist/plugins/excel.d.cts +4 -4
  98. package/dist/plugins/excel.d.ts +4 -4
  99. package/dist/plugins/excel.js +3 -3
  100. package/dist/plugins/pdf/fonts/vazirmatn.cjs +6 -6
  101. package/dist/plugins/pdf/fonts/vazirmatn.d.cts +4 -4
  102. package/dist/plugins/pdf/fonts/vazirmatn.d.ts +4 -4
  103. package/dist/plugins/pdf/fonts/vazirmatn.js +3 -3
  104. package/dist/plugins/pdf.cjs +5 -5
  105. package/dist/plugins/pdf.d.cts +5 -5
  106. package/dist/plugins/pdf.d.ts +5 -5
  107. package/dist/plugins/pdf.js +2 -2
  108. package/dist/presence.d.cts +3 -3
  109. package/dist/presence.d.ts +3 -3
  110. package/dist/sync.cjs +2 -2
  111. package/dist/sync.d.cts +3 -3
  112. package/dist/sync.d.ts +3 -3
  113. package/dist/sync.js +1 -1
  114. package/package.json +3 -3
  115. package/dist/GridSyncService-KTLB4KP3.js +0 -3
  116. package/dist/GridSyncService-TAPAHABV.cjs +0 -12
  117. package/dist/applyRowVisibilityHandler-KS6TMCBN.js.map +0 -1
  118. package/dist/applyRowVisibilityHandler-LXCOGESZ.cjs.map +0 -1
  119. package/dist/callbackRemoteApi-BlXO5NJz.d.ts +0 -30
  120. package/dist/callbackRemoteApi-DgnXH-i0.d.cts +0 -30
  121. package/dist/chunk-633KP74Z.js.map +0 -1
  122. package/dist/chunk-ASPTRYRD.cjs +0 -21
  123. package/dist/chunk-ASPTRYRD.cjs.map +0 -1
  124. package/dist/chunk-BHDRUZH5.cjs +0 -33
  125. package/dist/chunk-BHDRUZH5.cjs.map +0 -1
  126. package/dist/chunk-BLYVOV3G.cjs.map +0 -1
  127. package/dist/chunk-DXRCYW42.cjs.map +0 -1
  128. package/dist/chunk-HTNJT2QU.js.map +0 -1
  129. package/dist/chunk-IIISFUW4.cjs.map +0 -1
  130. package/dist/chunk-KUBVDIF7.cjs.map +0 -1
  131. package/dist/chunk-KYAOSBQN.js +0 -31
  132. package/dist/chunk-KYAOSBQN.js.map +0 -1
  133. package/dist/chunk-PXCHPZTP.cjs.map +0 -1
  134. package/dist/chunk-QQMU44KJ.js.map +0 -1
  135. package/dist/chunk-RM6ZWNT3.js.map +0 -1
  136. package/dist/chunk-Y6W5V2CI.js +0 -19
  137. package/dist/chunk-Y6W5V2CI.js.map +0 -1
@@ -2,7 +2,7 @@ import { getLocalePack, resolveDirection } from './chunk-SZ7BLAY3.js';
2
2
  import { jalaliAdapter, pad2, gregorianDateToJalali, jalaliToGregorianDate, jalaliMonthLength } from './chunk-GQEDLUMB.js';
3
3
  import { subscribeCatalogHostEvents } from './chunk-MUQQKPWR.js';
4
4
  import { normalizeDigits } from './chunk-AU3RDJYQ.js';
5
- import { createContext, useMemo, useEffect, useContext, useState, useCallback, useRef } from 'react';
5
+ import { createContext, useContext, useMemo, useEffect, useCallback, useState, useRef } from 'react';
6
6
  import { jsx } from 'react/jsx-runtime';
7
7
 
8
8
  // infrastructure/date/gregorianAdapter.ts
@@ -322,18 +322,26 @@ function ERPTableHostProvider({
322
322
  numberingSystem,
323
323
  dateAdapter,
324
324
  remoteApi,
325
- messages,
326
- onToast,
325
+ messages: messagesProp,
326
+ onToast: onToastProp,
327
327
  theme = themeErp,
328
328
  themeToggle = true,
329
329
  themeLocked = false,
330
330
  onToggleTheme,
331
- components,
332
- filterComponents,
333
- columnMenuItems,
334
- onColumnMenuAction,
335
- useDependOn
331
+ components: componentsProp,
332
+ filterComponents: filterComponentsProp,
333
+ columnMenuItems: columnMenuItemsProp,
334
+ onColumnMenuAction: onColumnMenuActionProp,
335
+ useDependOn: useDependOnProp
336
336
  }) {
337
+ const outer = useContext(ERPTableHostContext);
338
+ const messages = messagesProp ?? outer.messages;
339
+ const onToast = onToastProp ?? outer.onToast;
340
+ const components = componentsProp ?? outer.components;
341
+ const filterComponents = filterComponentsProp ?? outer.filterComponents;
342
+ const columnMenuItems = columnMenuItemsProp ?? outer.columnMenuItems;
343
+ const onColumnMenuAction = onColumnMenuActionProp ?? outer.onColumnMenuAction;
344
+ const useDependOn = useDependOnProp ?? outer.useDependOn;
337
345
  const value = useMemo(
338
346
  () => ({
339
347
  locale,
@@ -389,10 +397,13 @@ function useThemePortalStyle(extra) {
389
397
  }
390
398
  function useTranslations() {
391
399
  const { locale, messages } = useERPTableHost();
392
- return (key, vars) => {
393
- const raw = translate(key, locale, messages);
394
- return vars ? formatMessage(raw, vars) : raw;
395
- };
400
+ return useCallback(
401
+ (key, vars) => {
402
+ const raw = translate(key, locale, messages);
403
+ return vars ? formatMessage(raw, vars) : raw;
404
+ },
405
+ [locale, messages]
406
+ );
396
407
  }
397
408
  function useLocale() {
398
409
  return useERPTableHost().locale;
@@ -505,16 +516,27 @@ function useMediaQuery(query) {
505
516
  }, [media]);
506
517
  return { match };
507
518
  }
519
+ function useLatest(value) {
520
+ const ref = useRef(value);
521
+ ref.current = value;
522
+ return ref;
523
+ }
524
+ function errorMessage(error) {
525
+ return error instanceof Error ? error.message : "Remote request failed";
526
+ }
508
527
  function useRemoteQuery(args) {
509
- const { remoteApi } = useERPTableHost();
528
+ const { remoteApi, onToast } = useERPTableHost();
529
+ const toastRef = useLatest(onToast);
510
530
  const [data, setData] = useState(null);
511
531
  const [isFetching, setIsFetching] = useState(false);
532
+ const [error, setError] = useState(null);
512
533
  const refetch = useCallback(async () => {
513
534
  if (!args.url || args.skip || !remoteApi) {
514
535
  setData(null);
515
536
  return;
516
537
  }
517
538
  setIsFetching(true);
539
+ setError(null);
518
540
  try {
519
541
  const response = await remoteApi.request({
520
542
  endpoint: args.url,
@@ -522,6 +544,10 @@ function useRemoteQuery(args) {
522
544
  method: "POST"
523
545
  });
524
546
  setData(response ?? null);
547
+ } catch (e) {
548
+ setData(null);
549
+ setError(e);
550
+ toastRef.current?.("error", errorMessage(e), e);
525
551
  } finally {
526
552
  setIsFetching(false);
527
553
  }
@@ -529,12 +555,14 @@ function useRemoteQuery(args) {
529
555
  useEffect(() => {
530
556
  void refetch();
531
557
  }, [refetch]);
532
- return { data, isFetching, refetch };
558
+ return { data, isFetching, error, refetch };
533
559
  }
534
560
  function useLazyRemote() {
535
- const { remoteApi } = useERPTableHost();
561
+ const { remoteApi, onToast } = useERPTableHost();
562
+ const toastRef = useLatest(onToast);
536
563
  const [data, setData] = useState(null);
537
564
  const [isFetching, setIsFetching] = useState(false);
565
+ const [error, setError] = useState(null);
538
566
  const trigger = useCallback(
539
567
  async (args) => {
540
568
  if (!args.url || !remoteApi) {
@@ -542,16 +570,21 @@ function useLazyRemote() {
542
570
  return;
543
571
  }
544
572
  setIsFetching(true);
573
+ setError(null);
545
574
  try {
546
575
  const response = await remoteApi.request({ endpoint: args.url, params: args.body, method: "POST" });
547
576
  setData(response ?? null);
577
+ } catch (e) {
578
+ setData(null);
579
+ setError(e);
580
+ toastRef.current?.("error", errorMessage(e), e);
548
581
  } finally {
549
582
  setIsFetching(false);
550
583
  }
551
584
  },
552
585
  [remoteApi]
553
586
  );
554
- return [trigger, { data, isFetching }];
587
+ return [trigger, { data, isFetching, error }];
555
588
  }
556
589
 
557
590
  // ui/host/toast.ts
@@ -607,6 +640,6 @@ function useGridHostEvents(input) {
607
640
  }, [input.ready, input.controller, input.eventStore, input.tableKey]);
608
641
  }
609
642
 
610
- export { AR_MESSAGES, EN_MESSAGES, ERPTableHostProvider, FA_MESSAGES, GridTheme, JALALI_WEEKDAY_LABELS_FA, addJalaliMonths, bindGridHostEvents, buildDependencyBody, buildJalaliMonthGrid, compareJalaliDay, gregorianAdapter, hasDependValue, isDateInRange, isStockDarkTheme, jalaliMonthName, resolveActiveTheme, sameJalaliDay, themeDark, themeDefault, themeErp, themeErpDark, themeToStyle, toJalaliYmd, translate, useDateAdapter, useDirection, useERPTableHost, useERPTableTheme, useGridHostEvents, useHostDependOn, useHostToast, useLazyRemote, useLocale, useMediaQuery, useNumberingSystem, useRemoteQuery, useStaticDependOn, useThemePortalStyle, useTranslations };
611
- //# sourceMappingURL=chunk-QQMU44KJ.js.map
612
- //# sourceMappingURL=chunk-QQMU44KJ.js.map
643
+ export { AR_MESSAGES, EN_MESSAGES, ERPTableHostProvider, FA_MESSAGES, GridTheme, JALALI_WEEKDAY_LABELS_FA, addJalaliMonths, bindGridHostEvents, buildDependencyBody, buildJalaliMonthGrid, compareJalaliDay, getDependFieldName, getStaticDependValue, gregorianAdapter, hasDependValue, isDateInRange, isStockDarkTheme, jalaliMonthName, resolveActiveTheme, sameJalaliDay, themeDark, themeDefault, themeErp, themeErpDark, themeToStyle, toJalaliYmd, translate, useDateAdapter, useDirection, useERPTableHost, useERPTableTheme, useGridHostEvents, useHostDependOn, useHostToast, useLazyRemote, useLocale, useMediaQuery, useNumberingSystem, useRemoteQuery, useStaticDependOn, useThemePortalStyle, useTranslations };
644
+ //# sourceMappingURL=chunk-HLOHWFOA.js.map
645
+ //# sourceMappingURL=chunk-HLOHWFOA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../infrastructure/date/gregorianAdapter.ts","../infrastructure/date/jalaliCalendarModel.ts","../ui/theme/GridTheme.ts","../ui/theme/resolveActiveTheme.ts","../ui/theme/applyCssVars.ts","../ui/host/messages.ts","../ui/host/ERPTableHost.tsx","../ui/host/dependOn.ts","../ui/host/bindGridHostEvents.ts","../ui/host/useMediaQuery.ts","../ui/host/useRemoteQuery.ts","../ui/host/toast.ts","../ui/host/useGridHostEvents.ts"],"names":["useEffect","useState","useCallback","useRef"],"mappings":"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","file":"chunk-HLOHWFOA.js","sourcesContent":["import type { DateAdapter } from '../../application/ports/DateAdapter';\r\nimport { normalizeDigits } from '../../engine/dataOps/sortModel';\r\nimport { pad2 } from './jalaliMath';\r\n\r\nconst ISO_RE = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\r\nconst SLASH_RE = /^(\\d{4})[/\\-.](\\d{1,2})[/\\-.](\\d{1,2})$/;\r\n\r\nfunction utcDay(y: number, m: number, d: number): Date {\r\n return new Date(Date.UTC(y, m - 1, d, 12, 0, 0));\r\n}\r\n\r\nfunction asUtcDay(date: Date): Date {\r\n return utcDay(date.getUTCFullYear(), date.getUTCMonth() + 1, date.getUTCDate());\r\n}\r\n\r\n/** Gregorian calendar adapter (PR-128 / D21). */\r\nexport const gregorianAdapter: DateAdapter = {\r\n id: 'gregory',\r\n\r\n parse(input: unknown): Date | null {\r\n if (input == null || input === '') return null;\r\n if (input instanceof Date && !Number.isNaN(input.getTime())) {\r\n return asUtcDay(input);\r\n }\r\n if (typeof input === 'number' && Number.isFinite(input)) {\r\n const d = new Date(input);\r\n return Number.isNaN(d.getTime()) ? null : asUtcDay(d);\r\n }\r\n const text = normalizeDigits(String(input).trim());\r\n const iso = ISO_RE.exec(text);\r\n if (iso) {\r\n return utcDay(Number(iso[1]), Number(iso[2]), Number(iso[3]));\r\n }\r\n const slash = SLASH_RE.exec(text);\r\n if (slash) {\r\n return utcDay(Number(slash[1]), Number(slash[2]), Number(slash[3]));\r\n }\r\n const fallback = new Date(text);\r\n return Number.isNaN(fallback.getTime()) ? null : asUtcDay(fallback);\r\n },\r\n\r\n format(date: Date): string {\r\n const d = asUtcDay(date);\r\n return `${d.getUTCFullYear()}-${pad2(d.getUTCMonth() + 1)}-${pad2(d.getUTCDate())}`;\r\n },\r\n\r\n addDays(date: Date, days: number): Date {\r\n const next = asUtcDay(date);\r\n next.setUTCDate(next.getUTCDate() + days);\r\n return next;\r\n },\r\n\r\n startOfMonth(date: Date): Date {\r\n const d = asUtcDay(date);\r\n return utcDay(d.getUTCFullYear(), d.getUTCMonth() + 1, 1);\r\n },\r\n\r\n compare(a: Date, b: Date): number {\r\n return asUtcDay(a).getTime() - asUtcDay(b).getTime();\r\n },\r\n};\r\n","/**\r\n * Pure Jalali month-grid helpers for the internal picker (PR-140).\r\n */\r\n\r\nimport {\r\n gregorianDateToJalali,\r\n jalaliMonthLength,\r\n jalaliToGregorianDate,\r\n} from './jalaliMath';\r\n\r\nexport type JalaliYmd = { jy: number; jm: number; jd: number };\r\n\r\nexport type CalendarCell = {\r\n ymd: JalaliYmd;\r\n date: Date;\r\n inCurrentMonth: boolean;\r\n /** 0 = Saturday … 6 = Friday (Jalali week starts Saturday). */\r\n weekday: number;\r\n};\r\n\r\nconst MONTH_NAMES_FA = [\r\n 'فروردین',\r\n 'اردیبهشت',\r\n 'خرداد',\r\n 'تیر',\r\n 'مرداد',\r\n 'شهریور',\r\n 'مهر',\r\n 'آبان',\r\n 'آذر',\r\n 'دی',\r\n 'بهمن',\r\n 'اسفند',\r\n] as const;\r\n\r\nexport const JALALI_WEEKDAY_LABELS_FA = [\r\n 'ش',\r\n 'ی',\r\n 'د',\r\n 'س',\r\n 'چ',\r\n 'پ',\r\n 'ج',\r\n] as const;\r\n\r\nexport function jalaliMonthName(jm: number): string {\r\n return MONTH_NAMES_FA[jm - 1] ?? String(jm);\r\n}\r\n\r\nexport function toJalaliYmd(date: Date): JalaliYmd {\r\n return gregorianDateToJalali(utcNoon(date));\r\n}\r\n\r\nexport function fromJalaliYmd(ymd: JalaliYmd): Date {\r\n return jalaliToGregorianDate(ymd.jy, ymd.jm, ymd.jd);\r\n}\r\n\r\nexport function sameJalaliDay(a: Date, b: Date): boolean {\r\n const x = toJalaliYmd(a);\r\n const y = toJalaliYmd(b);\r\n return x.jy === y.jy && x.jm === y.jm && x.jd === y.jd;\r\n}\r\n\r\nexport function compareJalaliDay(a: Date, b: Date): number {\r\n return utcNoon(a).getTime() - utcNoon(b).getTime();\r\n}\r\n\r\nexport function addJalaliMonths(\r\n jy: number,\r\n jm: number,\r\n delta: number,\r\n): { jy: number; jm: number } {\r\n const idx = jy * 12 + (jm - 1) + delta;\r\n return {\r\n jy: Math.floor(idx / 12),\r\n jm: (idx % 12) + 1,\r\n };\r\n}\r\n\r\n/**\r\n * 6×7 grid of days for a Jalali month. Week starts Saturday.\r\n * Leading/trailing cells may belong to adjacent months (`inCurrentMonth: false`).\r\n */\r\nexport function buildJalaliMonthGrid(jy: number, jm: number): CalendarCell[] {\r\n const first = jalaliToGregorianDate(jy, jm, 1);\r\n const jsDow = first.getUTCDay();\r\n const jalaliWeekStart = (jsDow + 1) % 7;\r\n const daysInMonth = jalaliMonthLength(jy, jm);\r\n const cells: CalendarCell[] = [];\r\n\r\n for (let i = 0; i < 42; i += 1) {\r\n const offset = i - jalaliWeekStart;\r\n let cellJy = jy;\r\n let cellJm = jm;\r\n let cellJd: number;\r\n let inCurrentMonth = true;\r\n\r\n if (offset < 0) {\r\n const prev = addJalaliMonths(jy, jm, -1);\r\n cellJy = prev.jy;\r\n cellJm = prev.jm;\r\n cellJd = jalaliMonthLength(cellJy, cellJm) + offset + 1;\r\n inCurrentMonth = false;\r\n } else if (offset >= daysInMonth) {\r\n const next = addJalaliMonths(jy, jm, 1);\r\n cellJy = next.jy;\r\n cellJm = next.jm;\r\n cellJd = offset - daysInMonth + 1;\r\n inCurrentMonth = false;\r\n } else {\r\n cellJd = offset + 1;\r\n }\r\n\r\n const date = jalaliToGregorianDate(cellJy, cellJm, cellJd);\r\n cells.push({\r\n ymd: { jy: cellJy, jm: cellJm, jd: cellJd },\r\n date,\r\n inCurrentMonth,\r\n weekday: i % 7,\r\n });\r\n }\r\n return cells;\r\n}\r\n\r\nexport type DateRangeValue = {\r\n start: Date | null;\r\n end: Date | null;\r\n};\r\n\r\nexport function isDateInRange(date: Date, range: DateRangeValue): boolean {\r\n if (!range.start) return false;\r\n if (!range.end) return sameJalaliDay(date, range.start);\r\n const t = utcNoon(date).getTime();\r\n const a = utcNoon(range.start).getTime();\r\n const b = utcNoon(range.end).getTime();\r\n return t >= Math.min(a, b) && t <= Math.max(a, b);\r\n}\r\n\r\nfunction utcNoon(date: Date): Date {\r\n return new Date(\r\n Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(), 12),\r\n );\r\n}\r\n","export type ThemeParams = {\r\n backgroundColor: string;\r\n foregroundColor: string;\r\n accentColor: string;\r\n headerBackgroundColor: string;\r\n rowStripeColor: string;\r\n rowSelectedColor: string;\r\n borderColor: string;\r\n dangerColor: string;\r\n searchMatchColor: string;\r\n fontFamily: string;\r\n rowHeight: number;\r\n cellFontSize: number;\r\n borderRadius: string;\r\n};\r\n\r\nexport type ThemeCssVars = Record<string, string>;\r\n\r\n/** `--erp-*` mirrors `--pdg-*` for one version (PR-87 / D13). */\r\nfunction aliasErpTokens(vars: ThemeCssVars): ThemeCssVars {\r\n const out: ThemeCssVars = {};\r\n for (const [key, value] of Object.entries(vars)) {\r\n if (key.startsWith('--pdg-')) {\r\n out[`--erp-${key.slice('--pdg-'.length)}`] = value;\r\n }\r\n }\r\n return out;\r\n}\r\n\r\nexport class GridTheme {\r\n constructor(\r\n readonly params: ThemeParams,\r\n readonly extraCssVars: ThemeCssVars = {},\r\n ) {}\r\n\r\n withParams(partial: Partial<ThemeParams>): GridTheme {\r\n return new GridTheme({ ...this.params, ...partial }, this.extraCssVars);\r\n }\r\n\r\n withExtraCssVars(extra: ThemeCssVars): GridTheme {\r\n return new GridTheme(this.params, { ...this.extraCssVars, ...extra });\r\n }\r\n\r\n toCssVars(): ThemeCssVars {\r\n const p = this.params;\r\n const roles: ThemeCssVars = {\r\n '--pdg-bg': p.backgroundColor,\r\n '--pdg-fg': p.foregroundColor,\r\n '--pdg-accent': p.accentColor,\r\n '--pdg-header-bg': p.headerBackgroundColor,\r\n '--pdg-row-stripe': p.rowStripeColor,\r\n '--pdg-row-selected': p.rowSelectedColor,\r\n '--pdg-border': p.borderColor,\r\n '--pdg-danger': p.dangerColor,\r\n '--pdg-search-match': p.searchMatchColor,\r\n '--pdg-font': p.fontFamily,\r\n '--pdg-row-height': `${p.rowHeight}px`,\r\n '--pdg-font-size': `${p.cellFontSize}px`,\r\n '--pdg-radius': p.borderRadius,\r\n };\r\n return {\r\n ...roles,\r\n ...aliasErpTokens(roles),\r\n ...this.extraCssVars,\r\n ...aliasErpTokens(this.extraCssVars),\r\n };\r\n }\r\n}\r\n\r\n/** Default grid chrome — same computed colors as the CSS palette aliases. */\r\nexport const themeDefault = new GridTheme({\r\n backgroundColor: '#fff',\r\n foregroundColor: '#292929',\r\n accentColor: '#0658b0',\r\n headerBackgroundColor: '#f4f4f4',\r\n rowStripeColor: '#ddecfd',\r\n rowSelectedColor: '#dbeafe',\r\n borderColor: '#ececec',\r\n dangerColor: '#dc2626',\r\n searchMatchColor: '#facc15',\r\n fontFamily: 'IRANSans, Tahoma, sans-serif',\r\n rowHeight: 40,\r\n cellFontSize: 12,\r\n borderRadius: '0.25rem',\r\n});\r\n\r\n/** @deprecated Use {@link themeDefault}. Removed in 1.0.0. */\r\nexport const themeErp = themeDefault;\r\n\r\n/** Dark chrome. Palette extras keep leftover gray utilities readable. */\r\nconst DARK_PALETTE_VARS: ThemeCssVars = {\r\n '--pdg-main-white': '#171717',\r\n '--pdg-main-black': '#f4f4f4',\r\n '--pdg-gray-3': '#262626',\r\n '--pdg-gray-5': '#404040',\r\n '--pdg-gray-6': '#525252',\r\n '--pdg-gray-7': '#a3a3a3',\r\n '--pdg-gray-8': '#d4d4d4',\r\n '--pdg-gray-85': '#d4d4d4',\r\n '--pdg-gray-9': '#e5e5e5',\r\n '--pdg-gray-10': '#f5f5f5',\r\n '--pdg-gray-11': '#fafafa',\r\n '--pdg-black-6': '#f4f4f4',\r\n '--pdg-blue-6': '#60a5fa',\r\n '--pdg-blue-11': '#1e3a5f',\r\n '--pdg-blue-100': '#1e3a8a',\r\n '--pdg-red-100': '#7f1d1d',\r\n '--pdg-red-300': '#fca5a5',\r\n '--pdg-red-600': '#f87171',\r\n '--pdg-yellow-200': '#854d0e',\r\n '--pdg-yellow-400': '#eab308',\r\n '--pdg-zinc-200': '#3f3f46',\r\n '--pdg-neutral-500': '#a3a3a3',\r\n '--pdg-gray-100': '#27272a',\r\n '--pdg-scrollbar': '#525252',\r\n '--pdg-overlay': 'rgba(0, 0, 0, 0.55)',\r\n};\r\n\r\nexport const themeDark = themeDefault\r\n .withParams({\r\n backgroundColor: '#171717',\r\n foregroundColor: '#f4f4f4',\r\n accentColor: '#60a5fa',\r\n headerBackgroundColor: '#262626',\r\n rowStripeColor: '#1e3a5f',\r\n rowSelectedColor: '#1e3a8a',\r\n borderColor: '#404040',\r\n dangerColor: '#f87171',\r\n searchMatchColor: '#eab308',\r\n })\r\n .withExtraCssVars(DARK_PALETTE_VARS);\r\n\r\n/** @deprecated Use {@link themeDark}. Removed in 1.0.0. */\r\nexport const themeErpDark = themeDark;\r\n","import {\r\n GridTheme,\r\n type ThemeParams,\r\n themeErp,\r\n themeErpDark,\r\n} from './GridTheme';\r\n\r\nexport function themeParamsEqual(a: ThemeParams, b: ThemeParams): boolean {\r\n return (\r\n a.backgroundColor === b.backgroundColor &&\r\n a.foregroundColor === b.foregroundColor &&\r\n a.accentColor === b.accentColor &&\r\n a.headerBackgroundColor === b.headerBackgroundColor &&\r\n a.rowStripeColor === b.rowStripeColor &&\r\n a.rowSelectedColor === b.rowSelectedColor &&\r\n a.borderColor === b.borderColor &&\r\n a.dangerColor === b.dangerColor &&\r\n a.searchMatchColor === b.searchMatchColor &&\r\n a.fontFamily === b.fontFamily &&\r\n a.rowHeight === b.rowHeight &&\r\n a.cellFontSize === b.cellFontSize &&\r\n a.borderRadius === b.borderRadius\r\n );\r\n}\r\n\r\nexport function isStockLightTheme(theme: GridTheme): boolean {\r\n return themeParamsEqual(theme.params, themeErp.params);\r\n}\r\n\r\nexport function isStockDarkTheme(theme: GridTheme): boolean {\r\n return themeParamsEqual(theme.params, themeErpDark.params);\r\n}\r\n\r\n/** Built-in light/dark. Any `withParams` change locks the product toggle. */\r\nexport function isStockTheme(theme: GridTheme): boolean {\r\n return isStockLightTheme(theme) || isStockDarkTheme(theme);\r\n}\r\n\r\nexport function resolveActiveTheme(input: {\r\n requested?: GridTheme;\r\n preferDark: boolean;\r\n}): { theme: GridTheme; locked: boolean } {\r\n const requested = input.requested ?? themeErp;\r\n const locked = !isStockTheme(requested);\r\n if (locked) return { theme: requested, locked: true };\r\n return {\r\n theme: input.preferDark ? themeErpDark : themeErp,\r\n locked: false,\r\n };\r\n}\r\n","import type { CSSProperties } from 'react';\r\n\r\nimport type { GridTheme, ThemeCssVars } from './GridTheme';\r\nimport { themeErp } from './GridTheme';\r\n\r\nlet lastVars: ThemeCssVars = themeErp.toCssVars();\r\n\r\nexport function rememberThemeVars(vars: ThemeCssVars): void {\r\n lastVars = vars;\r\n}\r\n\r\nexport function getRememberedThemeVars(): ThemeCssVars {\r\n return lastVars;\r\n}\r\n\r\nexport function themeToStyle(\r\n theme: GridTheme,\r\n extra?: CSSProperties,\r\n): CSSProperties {\r\n return { ...theme.toCssVars(), ...extra } as CSSProperties;\r\n}\r\n\r\n/** Copy last (or given) theme vars onto an imperative DOM node (toasts). */\r\nexport function assignThemeVars(\r\n el: HTMLElement,\r\n vars: ThemeCssVars = lastVars,\r\n): void {\r\n for (const [key, value] of Object.entries(vars)) {\r\n el.style.setProperty(key, value);\r\n }\r\n}\r\n","import {\r\n getLocalePack,\r\n type ERPTableLocale,\r\n type ERPTableMessages,\r\n} from '../locales';\r\n\r\nexport type { ERPTableLocale, ERPTableMessages } from '../locales';\r\nexport {\r\n arMessages,\r\n enMessages,\r\n faMessages,\r\n formatLocaleDate,\r\n formatLocaleNumber,\r\n getLocalePack,\r\n LOCALE_META,\r\n LOCALE_PACKS,\r\n resolveDirection,\r\n resolveLocaleMeta,\r\n} from '../locales';\r\nexport type { LocaleMeta, NumberingSystem } from '../locales';\r\n\r\n/** @deprecated Prefer `faMessages` from `persian-data-grid/locales/fa`. */\r\nexport const FA_MESSAGES: ERPTableMessages = getLocalePack('fa');\r\n/** @deprecated Prefer `enMessages` from `persian-data-grid/locales/en`. */\r\nexport const EN_MESSAGES: ERPTableMessages = getLocalePack('en');\r\n/** Arabic pack alias (PR-127). */\r\nexport const AR_MESSAGES: ERPTableMessages = getLocalePack('ar');\r\n\r\nexport function translate(\r\n key: string,\r\n locale: ERPTableLocale,\r\n overrides?: Partial<ERPTableMessages>,\r\n): string {\r\n const pack = getLocalePack(locale);\r\n return overrides?.[key] ?? pack[key] ?? key;\r\n}\r\n\r\n/** Replace `{name}` tokens in a message template (PR-125). */\r\nexport function formatMessage(\r\n template: string,\r\n vars: Record<string, string | number>,\r\n): string {\r\n return template.replace(/\\{(\\w+)\\}/g, (_, name: string) => {\r\n const value = vars[name];\r\n return value == null ? `{${name}}` : String(value);\r\n });\r\n}\r\n","\"use client\";\r\n\r\nimport React, {\r\n createContext,\r\n useCallback,\r\n useContext,\r\n useEffect,\r\n useMemo,\r\n type CSSProperties,\r\n type ReactNode,\r\n} from 'react';\r\n\r\nimport type { DateAdapter } from '../../application/ports/DateAdapter';\r\nimport type { UseDependOnHook } from './dependOn';\r\nimport type { RemoteApi } from '../../application/ports/RemoteApi';\r\nimport type { ColumnMenuItemsConfig } from '../../engine/dataOps/columnMenu';\r\nimport {\r\n gregorianAdapter,\r\n jalaliAdapter,\r\n} from '../../infrastructure/date';\r\nimport type { CellComponentMap } from '../cellRenderer/cellRegistry';\r\nimport type { ColumnMenuActionEvent } from '../desktop/ColumnMenuPopover';\r\nimport type { FilterComponentMap } from '../filters';\r\nimport {\r\n GridTheme,\r\n rememberThemeVars,\r\n themeErp,\r\n themeToStyle,\r\n} from '../theme';\r\nimport {\r\n formatMessage,\r\n resolveDirection,\r\n type ERPTableLocale,\r\n type ERPTableMessages,\r\n type NumberingSystem,\r\n translate,\r\n} from './messages';\r\n\r\nexport type ERPTableToastKind = 'success' | 'error';\r\n\r\nexport type ERPTableHostValue = {\r\n locale: ERPTableLocale;\r\n direction: 'rtl' | 'ltr';\r\n /** Intl digit system (PR-127). Default from locale meta. */\r\n numberingSystem?: NumberingSystem;\r\n /**\r\n * Calendar port (PR-128 / D21). Default: `jalaliAdapter` for `fa`,\r\n * otherwise `gregorianAdapter`.\r\n */\r\n dateAdapter?: DateAdapter;\r\n remoteApi?: RemoteApi;\r\n messages?: Partial<ERPTableMessages>;\r\n onToast?: (kind: ERPTableToastKind, message: string, detail?: unknown) => void;\r\n theme?: GridTheme;\r\n themeToggle?: boolean;\r\n themeLocked?: boolean;\r\n onToggleTheme?: () => void;\r\n components?: CellComponentMap;\r\n /** Custom column filter UIs (PR-95). Keys match `ColumnDef.filter`. */\r\n filterComponents?: FilterComponentMap;\r\n /** Column header menu items (PR-114). */\r\n columnMenuItems?: ColumnMenuItemsConfig;\r\n /** Custom column menu action handler (PR-114). */\r\n onColumnMenuAction?: (event: ColumnMenuActionEvent) => void;\r\n /**\r\n * Resolves `dependOn` values for remote lists (e.g. from the form that owns\r\n * the grid — Redux, React context, …). Default: static item values.\r\n */\r\n useDependOn?: UseDependOnHook;\r\n};\r\n\r\nfunction defaultDateAdapter(locale: ERPTableLocale): DateAdapter {\r\n return locale === 'fa' ? jalaliAdapter : gregorianAdapter;\r\n}\r\n\r\nconst ERPTableHostContext = createContext<ERPTableHostValue>({\r\n locale: 'fa',\r\n direction: 'rtl',\r\n dateAdapter: jalaliAdapter,\r\n theme: themeErp,\r\n themeToggle: true,\r\n themeLocked: false,\r\n});\r\n\r\nexport function ERPTableHostProvider({\r\n children,\r\n locale = 'fa',\r\n direction,\r\n numberingSystem,\r\n dateAdapter,\r\n remoteApi,\r\n messages: messagesProp,\r\n onToast: onToastProp,\r\n theme = themeErp,\r\n themeToggle = true,\r\n themeLocked = false,\r\n onToggleTheme,\r\n components: componentsProp,\r\n filterComponents: filterComponentsProp,\r\n columnMenuItems: columnMenuItemsProp,\r\n onColumnMenuAction: onColumnMenuActionProp,\r\n useDependOn: useDependOnProp,\r\n}: ERPTableHostValue & { children: ReactNode }) {\r\n // Host-injection fields fall back to an outer provider (the host app wraps\r\n // the grid); explicit props always win.\r\n const outer = useContext(ERPTableHostContext);\r\n const messages = messagesProp ?? outer.messages;\r\n const onToast = onToastProp ?? outer.onToast;\r\n const components = componentsProp ?? outer.components;\r\n const filterComponents = filterComponentsProp ?? outer.filterComponents;\r\n const columnMenuItems = columnMenuItemsProp ?? outer.columnMenuItems;\r\n const onColumnMenuAction = onColumnMenuActionProp ?? outer.onColumnMenuAction;\r\n const useDependOn = useDependOnProp ?? outer.useDependOn;\r\n const value = useMemo<ERPTableHostValue>(\r\n () => ({\r\n locale,\r\n direction: resolveDirection(locale, direction),\r\n numberingSystem,\r\n dateAdapter: dateAdapter ?? defaultDateAdapter(locale),\r\n remoteApi,\r\n messages,\r\n onToast,\r\n theme,\r\n themeToggle,\r\n themeLocked,\r\n onToggleTheme,\r\n components,\r\n filterComponents,\r\n columnMenuItems,\r\n onColumnMenuAction,\r\n useDependOn,\r\n }),\r\n [\r\n locale,\r\n direction,\r\n numberingSystem,\r\n dateAdapter,\r\n remoteApi,\r\n messages,\r\n onToast,\r\n theme,\r\n themeToggle,\r\n themeLocked,\r\n onToggleTheme,\r\n components,\r\n filterComponents,\r\n columnMenuItems,\r\n onColumnMenuAction,\r\n useDependOn,\r\n ],\r\n );\r\n\r\n useEffect(() => {\r\n rememberThemeVars(theme.toCssVars());\r\n }, [theme]);\r\n\r\n return (\r\n <ERPTableHostContext.Provider value={value}>\r\n {children}\r\n </ERPTableHostContext.Provider>\r\n );\r\n}\r\n\r\nexport function useERPTableHost(): ERPTableHostValue {\r\n return useContext(ERPTableHostContext);\r\n}\r\n\r\nexport function useERPTableTheme(): GridTheme {\r\n return useERPTableHost().theme ?? themeErp;\r\n}\r\n\r\n/** Merge theme CSS vars into a portal node that mounts on `document.body`. */\r\nexport function useThemePortalStyle(extra?: CSSProperties): CSSProperties {\r\n const theme = useERPTableTheme();\r\n return themeToStyle(theme, extra);\r\n}\r\n\r\n/** Stable per locale / messages — safe as an effect dependency. */\r\nexport function useTranslations() {\r\n const { locale, messages } = useERPTableHost();\r\n return useCallback(\r\n (key: string, vars?: Record<string, string | number>) => {\r\n const raw = translate(key, locale, messages);\r\n return vars ? formatMessage(raw, vars) : raw;\r\n },\r\n [locale, messages],\r\n );\r\n}\r\n\r\nexport function useLocale(): ERPTableLocale {\r\n return useERPTableHost().locale;\r\n}\r\n\r\nexport function useNumberingSystem(): NumberingSystem | undefined {\r\n return useERPTableHost().numberingSystem;\r\n}\r\n\r\nexport function useDateAdapter(): DateAdapter {\r\n return useERPTableHost().dateAdapter ?? jalaliAdapter;\r\n}\r\n\r\nexport function useDirection(): 'rtl' | 'ltr' {\r\n return useERPTableHost().direction;\r\n}\r\n","\"use client\";\r\n\r\nimport { useERPTableHost } from './ERPTableHost';\r\n\r\n/** One dependency: a named sibling field and (optionally) its current value. */\r\nexport type DependOnItem =\r\n | string\r\n | { fieldName: string; value?: unknown };\r\nexport type DependOn = DependOnItem | DependOnItem[];\r\n\r\nexport type DependValueResolver = (item: DependOnItem) => unknown;\r\n\r\nexport type UseDependOnOptions = {\r\n /**\r\n * Ask the host to resolve dependency values (e.g. from the form that owns\r\n * the grid). When false/omitted, the `value` carried by each item is used.\r\n */\r\n enabled?: boolean;\r\n /** Send `value.value` when a resolved value is an option-like object. */\r\n unwrapObjectValue?: boolean;\r\n};\r\n\r\nexport type UseDependOnResult = {\r\n /** `{ [fieldName]: value }` to merge into a remote request body. */\r\n dependencyBody: Record<string, unknown>;\r\n /** Every dependency has a value (true when there is no dependOn). */\r\n isReady: boolean;\r\n /** Stable string that changes when the dependencies change. */\r\n dependencyKey: string;\r\n};\r\n\r\n/**\r\n * Host-injectable dependency resolver. The arianERP host implements this on\r\n * top of Redux page data; the default implementation reads the static values\r\n * carried by the `dependOn` items.\r\n */\r\nexport type UseDependOnHook = (\r\n dependOn?: DependOn | null,\r\n options?: UseDependOnOptions,\r\n) => UseDependOnResult;\r\n\r\nconst toList = (dependOn?: DependOn | null): DependOnItem[] =>\r\n !dependOn ? [] : Array.isArray(dependOn) ? dependOn : [dependOn];\r\n\r\nexport const getDependFieldName = (item: DependOnItem): string =>\r\n typeof item === 'string' ? item : item.fieldName;\r\n\r\n/** The value carried by the item itself; a bare field name carries none. */\r\nexport const getStaticDependValue: DependValueResolver = (item) =>\r\n typeof item === 'object' ? item.value : undefined;\r\n\r\n/** True when every dependency resolves to a non-null value (or there are none). */\r\nexport const hasDependValue = (\r\n dependOn?: DependOn | null,\r\n resolve: DependValueResolver = getStaticDependValue,\r\n): boolean => toList(dependOn).every((item) => resolve(item) != null);\r\n\r\n/** Builds the `{ [fieldName]: value }` part of a request body. */\r\nexport const buildDependencyBody = (\r\n dependOn?: DependOn | null,\r\n resolve: DependValueResolver = getStaticDependValue,\r\n): Record<string, unknown> =>\r\n Object.fromEntries(\r\n toList(dependOn).map((item) => [getDependFieldName(item), resolve(item)]),\r\n );\r\n\r\n/** Default `UseDependOnHook`: static values carried by the items. */\r\nexport const useStaticDependOn: UseDependOnHook = (dependOn, options) => {\r\n const unwrap = (value: unknown) =>\r\n options?.unwrapObjectValue &&\r\n value !== null &&\r\n typeof value === 'object' &&\r\n !Array.isArray(value) &&\r\n 'value' in value\r\n ? (value as { value: unknown }).value\r\n : value;\r\n const resolve: DependValueResolver = (item) => unwrap(getStaticDependValue(item));\r\n return {\r\n isReady: hasDependValue(dependOn, resolve),\r\n dependencyBody: buildDependencyBody(dependOn, resolve),\r\n dependencyKey: JSON.stringify(dependOn ?? null),\r\n };\r\n};\r\n\r\n/** Resolve dependency values through the host hook, falling back to static. */\r\nexport const useHostDependOn: UseDependOnHook = (dependOn, options) => {\r\n const host = useERPTableHost();\r\n const hook = host.useDependOn ?? useStaticDependOn;\r\n return hook(dependOn, options);\r\n};\r\n","import type { EventStore } from '../../application/ports/EventStore';\r\nimport {\r\n subscribeCatalogHostEvents,\r\n type CatalogHostEventHandlers,\r\n type CellFocusedEvent,\r\n type SelectionChangedEvent,\r\n} from '../../application/events/hostGridEvents';\r\nimport type { GridApi } from '../../infrastructure/ui/createGridApi';\r\nimport type { UITableController } from '../../infrastructure/ui/UITableController';\r\n\r\nexport type GridReadyEvent<TRow = unknown> = {\r\n api: GridApi<TRow>;\r\n};\r\n\r\nexport type GridHostEventHandlers<TRow = unknown> = CatalogHostEventHandlers<TRow> & {\r\n onSelectionChanged?: (event: SelectionChangedEvent<TRow>) => void;\r\n onCellFocused?: (event: CellFocusedEvent) => void;\r\n onGridReady?: (event: GridReadyEvent<TRow>) => void;\r\n};\r\n\r\nfunction selectedKeysEqual(\r\n a: Record<number, boolean> | null | undefined,\r\n b: Record<number, boolean> | null | undefined,\r\n): boolean {\r\n const left = Object.keys(a ?? {});\r\n const right = Object.keys(b ?? {});\r\n if (left.length !== right.length) return false;\r\n return left.every((key) => {\r\n const id = Number(key);\r\n return Boolean(a?.[id]) === Boolean(b?.[id]);\r\n });\r\n}\r\n\r\nfunction activeCellEqual(\r\n a: { rowId?: number; columnId?: string } | null | undefined,\r\n b: { rowId?: number; columnId?: string } | null | undefined,\r\n): boolean {\r\n return a?.rowId === b?.rowId && a?.columnId === b?.columnId;\r\n}\r\n\r\nfunction selectedRowIds(\r\n selected: Record<number, boolean> | null | undefined,\r\n): number[] {\r\n return Object.keys(selected ?? {})\r\n .map(Number)\r\n .filter((id) => Number.isFinite(id) && Boolean(selected?.[id]));\r\n}\r\n\r\n/**\r\n * Subscribe to EVENT_CATALOG (`EventStore`) plus the existing view store\r\n * (selection / focus). One unsubscribe. Not a second event bus.\r\n */\r\nexport function bindGridHostEvents<TRow = unknown>(\r\n input: {\r\n eventStore: EventStore;\r\n controller: UITableController;\r\n tableKey: string;\r\n handlers: GridHostEventHandlers<TRow>;\r\n },\r\n): () => void {\r\n const { eventStore, controller, tableKey, handlers } = input;\r\n\r\n const unsubCatalog = subscribeCatalogHostEvents(\r\n eventStore,\r\n {\r\n tableId: tableKey,\r\n getRowData: (rowId) =>\r\n controller.getAllRows()?.find((row) => row.id.value === rowId)?.data as\r\n | TRow\r\n | undefined,\r\n getAllRowData: () =>\r\n (controller.getAllRows() ?? [])\r\n .map((row) => row.data)\r\n .filter((data): data is TRow => data !== undefined),\r\n },\r\n handlers,\r\n );\r\n\r\n const unsubSelection = controller.subscribeSelected(\r\n () => controller.getSelectedRows(),\r\n (selected) => {\r\n const ids = selectedRowIds(selected);\r\n const rows = controller.getAllRows() ?? [];\r\n const selectedRows = ids\r\n .map((id) => rows.find((row) => row.id.value === id)?.data)\r\n .filter((data): data is TRow => data !== undefined);\r\n handlers.onSelectionChanged?.({\r\n selectedRowIds: ids,\r\n selectedRows,\r\n });\r\n },\r\n selectedKeysEqual,\r\n );\r\n\r\n const unsubFocus = controller.subscribeSelected(\r\n () => controller.getActiveCell(),\r\n (cell) => {\r\n handlers.onCellFocused?.({\r\n rowId: cell?.rowId ?? null,\r\n colId: cell?.columnId ?? null,\r\n });\r\n },\r\n activeCellEqual,\r\n );\r\n\r\n return () => {\r\n unsubCatalog();\r\n unsubSelection();\r\n unsubFocus();\r\n };\r\n}\r\n","\"use client\";\r\n\r\nimport { useEffect, useState } from 'react';\r\n\r\nconst QUERIES: Record<string, string> = {\r\n XLUP: '(min-width: 1024px)',\r\n XXLUP: '(min-width: 1366px)',\r\n};\r\n\r\nexport function useMediaQuery(query: string): { match: boolean | null } {\r\n const media = QUERIES[query] ?? query;\r\n const [match, setMatch] = useState<boolean | null>(() => {\r\n if (typeof window === 'undefined') return null;\r\n return window.matchMedia(media).matches;\r\n });\r\n\r\n useEffect(() => {\r\n const mql = window.matchMedia(media);\r\n const onChange = () => setMatch(mql.matches);\r\n onChange();\r\n mql.addEventListener('change', onChange);\r\n return () => mql.removeEventListener('change', onChange);\r\n }, [media]);\r\n\r\n return { match };\r\n}\r\n","\"use client\";\r\n\r\nimport { useCallback, useEffect, useRef, useState } from 'react';\r\n\r\nimport { useERPTableHost } from './ERPTableHost';\r\n\r\n/** Latest `onToast` without making callers' callbacks/effects depend on its identity. */\r\nfunction useLatest<T>(value: T) {\r\n const ref = useRef(value);\r\n ref.current = value;\r\n return ref;\r\n}\r\n\r\nfunction errorMessage(error: unknown): string {\r\n return error instanceof Error ? error.message : 'Remote request failed';\r\n}\r\n\r\ntype UseRemoteQueryArgs = {\r\n url?: string;\r\n body?: Record<string, unknown>;\r\n skip?: boolean;\r\n noCache?: boolean;\r\n};\r\n\r\nexport function useRemoteQuery<T = unknown>(args: UseRemoteQueryArgs) {\r\n const { remoteApi, onToast } = useERPTableHost();\r\n const toastRef = useLatest(onToast);\r\n const [data, setData] = useState<{ Data?: T; TotalCount?: number; ReturnCount?: number; Result?: string } | null>(null);\r\n const [isFetching, setIsFetching] = useState(false);\r\n const [error, setError] = useState<unknown>(null);\r\n\r\n const refetch = useCallback(async () => {\r\n if (!args.url || args.skip || !remoteApi) {\r\n setData(null);\r\n return;\r\n }\r\n setIsFetching(true);\r\n setError(null);\r\n try {\r\n const response = await remoteApi.request<{\r\n Data?: T;\r\n TotalCount?: number;\r\n ReturnCount?: number;\r\n Result?: string;\r\n }>({\r\n endpoint: args.url,\r\n params: args.body,\r\n method: 'POST',\r\n });\r\n setData(response ?? null);\r\n } catch (e) {\r\n // Never let a backend failure escape from an effect as an unhandled rejection.\r\n setData(null);\r\n setError(e);\r\n toastRef.current?.('error', errorMessage(e), e);\r\n } finally {\r\n setIsFetching(false);\r\n }\r\n }, [args.url, args.skip, args.noCache, JSON.stringify(args.body ?? {}), remoteApi]);\r\n\r\n useEffect(() => {\r\n void refetch();\r\n }, [refetch]);\r\n\r\n return { data, isFetching, error, refetch };\r\n}\r\n\r\n/**\r\n * Imperative counterpart of {@link useRemoteQuery} (RTK `useGet…Mutation`\r\n * style): nothing is fetched until `trigger` is called, and body/url changes\r\n * never refetch on their own.\r\n */\r\nexport function useLazyRemote<T = unknown>() {\r\n const { remoteApi, onToast } = useERPTableHost();\r\n const toastRef = useLatest(onToast);\r\n const [data, setData] = useState<{ Data?: T; TotalCount?: number; ReturnCount?: number; Result?: string } | null>(null);\r\n const [isFetching, setIsFetching] = useState(false);\r\n const [error, setError] = useState<unknown>(null);\r\n\r\n const trigger = useCallback(\r\n async (args: { url?: string; body?: Record<string, unknown> }) => {\r\n if (!args.url || !remoteApi) {\r\n setData(null);\r\n return;\r\n }\r\n setIsFetching(true);\r\n setError(null);\r\n try {\r\n const response = await remoteApi.request<{\r\n Data?: T;\r\n TotalCount?: number;\r\n ReturnCount?: number;\r\n Result?: string;\r\n }>({ endpoint: args.url, params: args.body, method: 'POST' });\r\n setData(response ?? null);\r\n } catch (e) {\r\n // Resolves (never rejects): failures surface via `error` and `onToast`.\r\n setData(null);\r\n setError(e);\r\n toastRef.current?.('error', errorMessage(e), e);\r\n } finally {\r\n setIsFetching(false);\r\n }\r\n },\r\n [remoteApi],\r\n );\r\n\r\n return [trigger, { data, isFetching, error }] as const;\r\n}\r\n","import { assignThemeVars } from '../theme';\r\nimport { useERPTableHost } from './ERPTableHost';\r\n\r\nexport function showSuccessToast(message?: unknown, _detail?: unknown): void {\r\n const text = String(message ?? '');\r\n emitToast('success', text);\r\n}\r\n\r\nexport function showErrorToast(message?: unknown, _detail?: unknown): void {\r\n const text = String(message ?? '');\r\n emitToast('error', text);\r\n}\r\n\r\nfunction emitToast(kind: 'success' | 'error', message: string): void {\r\n if (typeof document === 'undefined') return;\r\n const existing = document.querySelector('.erp-table-toast');\r\n existing?.remove();\r\n const el = document.createElement('div');\r\n el.className = `erp-table-toast is-${kind}`;\r\n el.textContent = message;\r\n assignThemeVars(el);\r\n document.body.appendChild(el);\r\n window.setTimeout(() => el.remove(), 2800);\r\n}\r\n\r\n/** Host can wrap this if it wants toasts routed through its own UI. */\r\nexport function useHostToast() {\r\n const host = useERPTableHost();\r\n return {\r\n success: (message: string, detail?: unknown) => {\r\n if (host.onToast) host.onToast('success', message, detail);\r\n else showSuccessToast(message, detail);\r\n },\r\n error: (message: string, detail?: unknown) => {\r\n if (host.onToast) host.onToast('error', message, detail);\r\n else showErrorToast(message, detail);\r\n },\r\n };\r\n}\r\n","import { useEffect, useRef } from 'react';\r\n\r\nimport type { EventStore } from '../../application/ports/EventStore';\r\nimport type { UITableController } from '../../infrastructure/ui/UITableController';\r\nimport {\r\n bindGridHostEvents,\r\n type GridHostEventHandlers,\r\n} from './bindGridHostEvents';\r\n\r\nexport type UseGridHostEventsInput<TRow = unknown> = GridHostEventHandlers<TRow> & {\r\n ready: boolean;\r\n controller: UITableController | null;\r\n eventStore: EventStore | null;\r\n tableKey: string;\r\n};\r\n\r\n/**\r\n * ERPTable wiring for PR-85. Handlers are read from a ref so EventStore\r\n * subscribeAll is not torn down when the host passes inline lambdas.\r\n */\r\nexport function useGridHostEvents<TRow = unknown>(\r\n input: UseGridHostEventsInput<TRow>,\r\n): void {\r\n const handlersRef = useRef<GridHostEventHandlers<TRow>>(input);\r\n handlersRef.current = input;\r\n\r\n useEffect(() => {\r\n if (!input.ready || !input.controller || !input.eventStore) return;\r\n return bindGridHostEvents<TRow>({\r\n eventStore: input.eventStore,\r\n controller: input.controller,\r\n tableKey: input.tableKey,\r\n handlers: {\r\n onCellValueChanged: (event) =>\r\n handlersRef.current.onCellValueChanged?.(event),\r\n onRowValueChanged: (event) =>\r\n handlersRef.current.onRowValueChanged?.(event),\r\n onRowDataUpdated: (event) =>\r\n handlersRef.current.onRowDataUpdated?.(event),\r\n onSelectionChanged: (event) =>\r\n handlersRef.current.onSelectionChanged?.(event),\r\n onCellFocused: (event) => handlersRef.current.onCellFocused?.(event),\r\n },\r\n });\r\n }, [input.ready, input.controller, input.eventStore, input.tableKey]);\r\n}\r\n"]}
@@ -44,6 +44,7 @@ var GridSyncService = class {
44
44
  this.conflictListeners = /* @__PURE__ */ new Set();
45
45
  /** Remote events waiting on manual resolution (by conflict id). */
46
46
  this.deferredRemote = /* @__PURE__ */ new Map();
47
+ this.disposed = false;
47
48
  this.policy = options.policy ?? "lastWriteWins";
48
49
  this.cursor = options.initialCursor ?? 0;
49
50
  }
@@ -57,16 +58,29 @@ var GridSyncService = class {
57
58
  return this.openConflicts;
58
59
  }
59
60
  subscribeConflicts(listener) {
61
+ if (this.disposed) return () => void 0;
60
62
  this.conflictListeners.add(listener);
61
63
  listener(this.openConflicts);
62
64
  return () => this.conflictListeners.delete(listener);
63
65
  }
66
+ /** Drop listeners and deferred conflicts; later sync() calls are no-ops. */
67
+ dispose() {
68
+ this.disposed = true;
69
+ this.conflictListeners.clear();
70
+ this.deferredRemote.clear();
71
+ this.openConflicts = [];
72
+ }
73
+ emptyResult() {
74
+ return { pushed: 0, pulled: 0, applied: 0, conflicts: [] };
75
+ }
64
76
  async sync() {
77
+ if (this.disposed) return this.emptyResult();
65
78
  const pending = this.options.offlineStatus.getPendingChanges();
66
79
  const pushable = pending.map((p) => p.event).filter(
67
80
  (e) => Boolean(e) && e.tableId === this.options.tableId
68
81
  );
69
82
  const { acceptedIds } = await this.options.transport.push(pushable);
83
+ if (this.disposed) return this.emptyResult();
70
84
  if (acceptedIds.length > 0) {
71
85
  this.options.offlineStatus.markSynced([...acceptedIds]);
72
86
  }
@@ -86,10 +100,12 @@ var GridSyncService = class {
86
100
  localByCell.set(cellKeyId(key.rowId, key.columnId), event);
87
101
  }
88
102
  const pulled = await this.options.transport.pull(this.cursor);
103
+ if (this.disposed) return this.emptyResult();
89
104
  this.cursor = pulled.cursor;
90
105
  let applied = 0;
91
106
  const conflicts = [];
92
107
  for (const remote of pulled.events) {
108
+ if (this.disposed) return this.emptyResult();
93
109
  if (remote.tableId !== this.options.tableId) continue;
94
110
  if (!isCellChanged(remote)) {
95
111
  await this.ingestRemote(remote);
@@ -138,6 +154,7 @@ var GridSyncService = class {
138
154
  };
139
155
  }
140
156
  async resolveConflict(conflictId, choice) {
157
+ if (this.disposed) return;
141
158
  const conflict = this.openConflicts.find((c) => c.id === conflictId);
142
159
  const remote = this.deferredRemote.get(conflictId);
143
160
  if (!conflict || !remote) return;
@@ -185,5 +202,5 @@ var GridSyncService = class {
185
202
  };
186
203
 
187
204
  export { GridSyncService };
188
- //# sourceMappingURL=chunk-633KP74Z.js.map
189
- //# sourceMappingURL=chunk-633KP74Z.js.map
205
+ //# sourceMappingURL=chunk-KCNTKYUY.js.map
206
+ //# sourceMappingURL=chunk-KCNTKYUY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../application/sync/resolveCellConflicts.ts","../application/sync/GridSyncService.ts"],"names":[],"mappings":"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","file":"chunk-KCNTKYUY.js","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 private disposed = false;\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 if (this.disposed) return () => undefined;\r\n this.conflictListeners.add(listener);\r\n listener(this.openConflicts);\r\n return () => this.conflictListeners.delete(listener);\r\n }\r\n\r\n /** Drop listeners and deferred conflicts; later sync() calls are no-ops. */\r\n dispose(): void {\r\n this.disposed = true;\r\n this.conflictListeners.clear();\r\n this.deferredRemote.clear();\r\n this.openConflicts = [];\r\n }\r\n\r\n private emptyResult(): SyncResult {\r\n return { pushed: 0, pulled: 0, applied: 0, conflicts: [] };\r\n }\r\n\r\n async sync(): Promise<SyncResult> {\r\n if (this.disposed) return this.emptyResult();\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 (this.disposed) return this.emptyResult();\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 if (this.disposed) return this.emptyResult();\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 // Torn down mid-apply: stop writing into a released event store.\r\n if (this.disposed) return this.emptyResult();\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 if (this.disposed) return;\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"]}
@@ -46,6 +46,7 @@ var GridSyncService = class {
46
46
  this.conflictListeners = /* @__PURE__ */ new Set();
47
47
  /** Remote events waiting on manual resolution (by conflict id). */
48
48
  this.deferredRemote = /* @__PURE__ */ new Map();
49
+ this.disposed = false;
49
50
  this.policy = options.policy ?? "lastWriteWins";
50
51
  this.cursor = options.initialCursor ?? 0;
51
52
  }
@@ -59,16 +60,29 @@ var GridSyncService = class {
59
60
  return this.openConflicts;
60
61
  }
61
62
  subscribeConflicts(listener) {
63
+ if (this.disposed) return () => void 0;
62
64
  this.conflictListeners.add(listener);
63
65
  listener(this.openConflicts);
64
66
  return () => this.conflictListeners.delete(listener);
65
67
  }
68
+ /** Drop listeners and deferred conflicts; later sync() calls are no-ops. */
69
+ dispose() {
70
+ this.disposed = true;
71
+ this.conflictListeners.clear();
72
+ this.deferredRemote.clear();
73
+ this.openConflicts = [];
74
+ }
75
+ emptyResult() {
76
+ return { pushed: 0, pulled: 0, applied: 0, conflicts: [] };
77
+ }
66
78
  async sync() {
79
+ if (this.disposed) return this.emptyResult();
67
80
  const pending = this.options.offlineStatus.getPendingChanges();
68
81
  const pushable = pending.map((p) => p.event).filter(
69
82
  (e) => Boolean(e) && e.tableId === this.options.tableId
70
83
  );
71
84
  const { acceptedIds } = await this.options.transport.push(pushable);
85
+ if (this.disposed) return this.emptyResult();
72
86
  if (acceptedIds.length > 0) {
73
87
  this.options.offlineStatus.markSynced([...acceptedIds]);
74
88
  }
@@ -88,10 +102,12 @@ var GridSyncService = class {
88
102
  localByCell.set(cellKeyId(key.rowId, key.columnId), event);
89
103
  }
90
104
  const pulled = await this.options.transport.pull(this.cursor);
105
+ if (this.disposed) return this.emptyResult();
91
106
  this.cursor = pulled.cursor;
92
107
  let applied = 0;
93
108
  const conflicts = [];
94
109
  for (const remote of pulled.events) {
110
+ if (this.disposed) return this.emptyResult();
95
111
  if (remote.tableId !== this.options.tableId) continue;
96
112
  if (!isCellChanged(remote)) {
97
113
  await this.ingestRemote(remote);
@@ -140,6 +156,7 @@ var GridSyncService = class {
140
156
  };
141
157
  }
142
158
  async resolveConflict(conflictId, choice) {
159
+ if (this.disposed) return;
143
160
  const conflict = this.openConflicts.find((c) => c.id === conflictId);
144
161
  const remote = this.deferredRemote.get(conflictId);
145
162
  if (!conflict || !remote) return;
@@ -187,5 +204,5 @@ var GridSyncService = class {
187
204
  };
188
205
 
189
206
  exports.GridSyncService = GridSyncService;
190
- //# sourceMappingURL=chunk-BLYVOV3G.cjs.map
191
- //# sourceMappingURL=chunk-BLYVOV3G.cjs.map
207
+ //# sourceMappingURL=chunk-LY27YAXE.cjs.map
208
+ //# sourceMappingURL=chunk-LY27YAXE.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-LY27YAXE.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 private disposed = false;\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 if (this.disposed) return () => undefined;\r\n this.conflictListeners.add(listener);\r\n listener(this.openConflicts);\r\n return () => this.conflictListeners.delete(listener);\r\n }\r\n\r\n /** Drop listeners and deferred conflicts; later sync() calls are no-ops. */\r\n dispose(): void {\r\n this.disposed = true;\r\n this.conflictListeners.clear();\r\n this.deferredRemote.clear();\r\n this.openConflicts = [];\r\n }\r\n\r\n private emptyResult(): SyncResult {\r\n return { pushed: 0, pulled: 0, applied: 0, conflicts: [] };\r\n }\r\n\r\n async sync(): Promise<SyncResult> {\r\n if (this.disposed) return this.emptyResult();\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 (this.disposed) return this.emptyResult();\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 if (this.disposed) return this.emptyResult();\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 // Torn down mid-apply: stop writing into a released event store.\r\n if (this.disposed) return this.emptyResult();\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 if (this.disposed) return;\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"]}
@@ -1,6 +1,6 @@
1
- import { buildExportTable } from './chunk-LJ7LMEXO.js';
1
+ import { buildExportTable } from './chunk-7GWV5HGO.js';
2
2
  import { buildXlsxBlob, downloadBlob } from './chunk-PQY54EL5.js';
3
- import { formatExportValue } from './chunk-KYAOSBQN.js';
3
+ import { formatExportValue } from './chunk-GKE33FOJ.js';
4
4
  import { unzipSync, strFromU8 } from 'fflate';
5
5
 
6
6
  // packages/plugins/excel/src/ExcelExportPlugin.ts
@@ -775,6 +775,7 @@ async function exportActiveCollectionToExcelStreaming(controller, options) {
775
775
  // packages/plugins/excel/src/exportActiveCollectionToExcel.ts
776
776
  var hasMeaningfulValue2 = (value) => value !== void 0 && value !== null && value !== "";
777
777
  async function exportActiveCollectionToExcel(controller, options) {
778
+ await controller.flushCellEdit();
778
779
  if (controller.isPagedWindow()) {
779
780
  return exportActiveCollectionToExcelStreaming(controller, options);
780
781
  }
@@ -828,5 +829,5 @@ async function exportActiveCollectionToExcel(controller, options) {
828
829
  }
829
830
 
830
831
  export { ExcelExportPlugin, ExcelImportPlugin, applyImportedRows, exportActiveCollectionToExcel, mapImportedSheet, parseXlsxBlob };
831
- //# sourceMappingURL=chunk-EHHHC5JV.js.map
832
- //# sourceMappingURL=chunk-EHHHC5JV.js.map
832
+ //# sourceMappingURL=chunk-NB5GCGHL.js.map
833
+ //# sourceMappingURL=chunk-NB5GCGHL.js.map