najm-kit 2.2.2 → 2.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2875,6 +2875,8 @@ interface TableState {
2875
2875
  isRefreshing: boolean;
2876
2876
  dynamicHeight: boolean;
2877
2877
  CardComponent: ComponentType<any> | null;
2878
+ /** Placeholder shaped like `CardComponent`; see `renderCardSkeleton`. */
2879
+ CardSkeletonComponent: ComponentType<any> | null;
2878
2880
  className: string;
2879
2881
  classNames: NTableClassNames;
2880
2882
  bordered?: boolean;
@@ -3014,6 +3016,7 @@ declare const createTableStore: (seed?: Partial<TableState>) => {
3014
3016
  isRefreshing: () => boolean;
3015
3017
  dynamicHeight: () => boolean;
3016
3018
  CardComponent: () => ComponentType<any>;
3019
+ CardSkeletonComponent: () => ComponentType<any>;
3017
3020
  className: () => string;
3018
3021
  classNames: () => NTableClassNames;
3019
3022
  bordered?: () => boolean;
@@ -3199,6 +3202,32 @@ interface NTableProps<T = any, M extends ViewMode = ViewMode> {
3199
3202
  'data-row'?: string;
3200
3203
  'data-row-id'?: string;
3201
3204
  }>;
3205
+ /**
3206
+ * A placeholder shaped like `renderCard`.
3207
+ *
3208
+ * The card page size is measured from whatever is on screen, and during a
3209
+ * first load that is the skeleton. The built-in placeholder is an avatar row,
3210
+ * so a consumer whose cards are a different height — a media card, say — gets
3211
+ * a page size measured against a card it does not use, and the grid re-lays
3212
+ * out once real cards arrive. Supplying a placeholder with the real card's
3213
+ * geometry makes the first measurement the correct one.
3214
+ */
3215
+ renderCardSkeleton?: ComponentType<Record<string, never>>;
3216
+ /**
3217
+ * Emit both skeleton shapes and let a media query choose between them.
3218
+ *
3219
+ * A view mode derived from the viewport is unknowable on the server, so the
3220
+ * server renders the card shape and the client corrects it after hydration —
3221
+ * on a desktop table page that is a visible card skeleton followed by a table
3222
+ * skeleton. No client-side detection can fix it, because the first paint is
3223
+ * whatever the server sent. Rendering both and hiding one in CSS puts the
3224
+ * right shape in that first paint. The skeleton is `aria-hidden` decoration,
3225
+ * so the duplicate costs nothing to assistive technology.
3226
+ *
3227
+ * The breakpoint is `lg` (1024px), matching the point at which a table
3228
+ * becomes usable.
3229
+ */
3230
+ responsiveSkeleton?: boolean;
3202
3231
  renderToolbar?: (state: NTableState) => React__default.ReactNode;
3203
3232
  renderEmpty?: () => React__default.ReactNode;
3204
3233
  renderError?: (error: any) => React__default.ReactNode;
@@ -3435,6 +3464,7 @@ declare const TableStoreContext: React$1.Context<{
3435
3464
  isRefreshing: () => boolean;
3436
3465
  dynamicHeight: () => boolean;
3437
3466
  CardComponent: () => React$1.ComponentType<any>;
3467
+ CardSkeletonComponent: () => React$1.ComponentType<any>;
3438
3468
  className: () => string;
3439
3469
  classNames: () => NTableClassNames;
3440
3470
  bordered?: () => boolean;
@@ -3567,6 +3597,7 @@ declare function useStoreSync(props: any): {
3567
3597
  isRefreshing: () => boolean;
3568
3598
  dynamicHeight: () => boolean;
3569
3599
  CardComponent: () => React__default.ComponentType<any>;
3600
+ CardSkeletonComponent: () => React__default.ComponentType<any>;
3570
3601
  className: () => string;
3571
3602
  classNames: () => NTableClassNames;
3572
3603
  bordered?: () => boolean;
package/dist/index.mjs CHANGED
@@ -12183,6 +12183,7 @@ var createTableStore = (seed) => {
12183
12183
  getRowId: null,
12184
12184
  renderToolbar: null,
12185
12185
  CardComponent: null,
12186
+ CardSkeletonComponent: null,
12186
12187
  className: "",
12187
12188
  classNames: {},
12188
12189
  bordered: void 0,
@@ -12492,9 +12493,11 @@ function useDynamicPageSize(containerRef, effectiveViewMode) {
12492
12493
  const bodyEl = container2.querySelector("[data-ntable-body]");
12493
12494
  const tableHeaderEl = container2.querySelector("[data-ntable-table-header]");
12494
12495
  const loadingHeaderEl = container2.querySelector("[data-ntable-loading-header]");
12495
- const cardsGridEl = container2.querySelector(
12496
- "[data-ntable-loading-cards-grid], [data-ntable-cards-grid]"
12497
- );
12496
+ const cardsGridEl = Array.from(
12497
+ container2.querySelectorAll(
12498
+ "[data-ntable-loading-cards-grid], [data-ntable-cards-grid]"
12499
+ )
12500
+ ).find((el) => el.clientHeight > 0 || el.clientWidth > 0) ?? null;
12498
12501
  let bodyHeight = bodyEl?.clientHeight ?? 0;
12499
12502
  const bodyWidth = bodyEl?.clientWidth ?? container2.clientWidth ?? 0;
12500
12503
  if (!bodyHeight) {
@@ -12726,11 +12729,12 @@ function useTable(effectiveViewModeOverride) {
12726
12729
  if (dynamicPageSizeTarget === storePagination.pageSize) return;
12727
12730
  const reported = reportedGeometryRef.current;
12728
12731
  if (reported?.key === geometryKey && reported.count >= MAX_PAGE_SIZE_REPORTS_PER_GEOMETRY) return;
12732
+ const delay = reported ? DYNAMIC_PAGE_SIZE_DEBOUNCE_MS : 0;
12729
12733
  const timer = setTimeout(() => {
12730
12734
  const current = reportedGeometryRef.current;
12731
12735
  reportedGeometryRef.current = current?.key === geometryKey ? { key: geometryKey, count: current.count + 1 } : { key: geometryKey, count: 1 };
12732
12736
  setPagination({ pageIndex: storePagination.pageIndex, pageSize: dynamicPageSizeTarget });
12733
- }, DYNAMIC_PAGE_SIZE_DEBOUNCE_MS);
12737
+ }, delay);
12734
12738
  return () => clearTimeout(timer);
12735
12739
  }, [
12736
12740
  manualPagination,
@@ -13207,6 +13211,7 @@ function NDataCardShell({ row, onClick, onContextMenu, actions, children, classN
13207
13211
  );
13208
13212
  }
13209
13213
  var DEFAULT_ROWS2 = 6;
13214
+ var UNMEASURED_DYNAMIC_ROWS = 32;
13210
13215
  var DEFAULT_CARD_COUNT = 48;
13211
13216
  function NTableCardSkeleton({ surface }) {
13212
13217
  return /* @__PURE__ */ jsx(
@@ -13353,7 +13358,7 @@ function NTableLoadingSkeleton({ rows }) {
13353
13358
  const userGetRowCanExpand = useTableStore.use.getRowCanExpand();
13354
13359
  const hasExpansion = Boolean(renderSubRow || userGetRowCanExpand);
13355
13360
  const loadingText = useTableStore.use.loadingText();
13356
- const rowCount = rows ?? (dynamicHeight && bodyHeight > 0 ? skeletonRowCount : DEFAULT_ROWS2);
13361
+ const rowCount = rows ?? (dynamicHeight ? bodyHeight > 0 ? skeletonRowCount : UNMEASURED_DYNAMIC_ROWS : DEFAULT_ROWS2);
13357
13362
  const renderHeaderLabel = (header) => typeof header === "string" ? header : null;
13358
13363
  return /* @__PURE__ */ jsxs("div", { className: "flex min-h-0 flex-1 flex-col gap-2", children: [
13359
13364
  /* @__PURE__ */ jsx(NTableHeaderSkeleton, {}),
@@ -13423,6 +13428,7 @@ function NTableCardsLoadingSkeleton({ rows }) {
13423
13428
  const cardRowHeight = useTableStore.use.cardRowHeight();
13424
13429
  const cardGap = useTableStore.use.cardGap();
13425
13430
  const loadingText = useTableStore.use.loadingText();
13431
+ const CardSkeletonComponent = useTableStore.use.CardSkeletonComponent();
13426
13432
  const cardCount = rows ?? (dynamicHeight && bodyHeight > 0 ? calculateCardSkeletonCount({
13427
13433
  bodyHeight,
13428
13434
  columnCount: cardColumnCount,
@@ -13451,7 +13457,7 @@ function NTableCardsLoadingSkeleton({ rows }) {
13451
13457
  "data-ntable-loading-card-count": cardCount,
13452
13458
  "aria-hidden": "true",
13453
13459
  className: cn(containerClass),
13454
- children: Array.from({ length: cardCount }).map((_, index) => /* @__PURE__ */ jsx(NTableCardSkeleton, { surface }, index))
13460
+ children: Array.from({ length: cardCount }).map((_, index) => CardSkeletonComponent ? /* @__PURE__ */ jsx("div", { "data-ntable-loading-card": true, children: /* @__PURE__ */ jsx(CardSkeletonComponent, {}) }, index) : /* @__PURE__ */ jsx(NTableCardSkeleton, { surface }, index))
13455
13461
  }
13456
13462
  )
13457
13463
  ]
@@ -13561,6 +13567,7 @@ function NTableCards({ effectiveMode }) {
13561
13567
  const showCheckbox = useTableStore.use.showCheckbox();
13562
13568
  const selectedRowId = useTableStore.use.selectedRowId();
13563
13569
  const CardComponent = useTableStore.use.CardComponent();
13570
+ const CardSkeletonComponent = useTableStore.use.CardSkeletonComponent();
13564
13571
  const storeIsCardView = useTableStore.use.isCardView();
13565
13572
  useTableStore.use.isLoading();
13566
13573
  const error = useTableStore.use.error();
@@ -13702,7 +13709,7 @@ function NTableCards({ effectiveMode }) {
13702
13709
  row.id
13703
13710
  );
13704
13711
  }),
13705
- continuation.pending ? Array.from({ length: Math.max(1, cardColumnCount || 1) }).map((_, index) => /* @__PURE__ */ jsx(NTableCardSkeleton, { surface }, `ntable-continuation-skeleton-${index}`)) : null
13712
+ continuation.pending ? Array.from({ length: Math.max(1, cardColumnCount || 1) }).map((_, index) => CardSkeletonComponent ? /* @__PURE__ */ jsx(CardSkeletonComponent, {}, `ntable-continuation-skeleton-${index}`) : /* @__PURE__ */ jsx(NTableCardSkeleton, { surface }, `ntable-continuation-skeleton-${index}`)) : null
13706
13713
  ] }),
13707
13714
  continuation.error ? /* @__PURE__ */ jsxs(
13708
13715
  "div",
@@ -14316,7 +14323,10 @@ function TableLayout(props) {
14316
14323
  "aria-busy": isRefreshing ? "true" : void 0,
14317
14324
  className: "flex min-h-0 flex-1 flex-col gap-2 overflow-hidden",
14318
14325
  children: isCustomMode ? customRenderer ? customRenderer() : null : /* @__PURE__ */ jsxs(Fragment, { children: [
14319
- isLoading && !isRefreshing && (props.renderLoading ? /* @__PURE__ */ jsx(TableStateSlot, { children: props.renderLoading() }) : effectiveMode === "table" ? /* @__PURE__ */ jsx(NTableLoadingSkeleton, {}) : effectiveMode === "cards" ? /* @__PURE__ */ jsx(NTableCardsLoadingSkeleton, {}) : /* @__PURE__ */ jsx(NTableLoadingSkeleton, {})),
14326
+ isLoading && !isRefreshing && (props.renderLoading ? /* @__PURE__ */ jsx(TableStateSlot, { children: props.renderLoading() }) : props.responsiveSkeleton ? /* @__PURE__ */ jsxs(Fragment, { children: [
14327
+ /* @__PURE__ */ jsx("div", { "data-ntable-skeleton-variant": "table", className: "hidden min-h-0 flex-1 flex-col lg:flex", children: /* @__PURE__ */ jsx(NTableLoadingSkeleton, {}) }),
14328
+ /* @__PURE__ */ jsx("div", { "data-ntable-skeleton-variant": "cards", className: "flex min-h-0 flex-1 flex-col lg:hidden", children: /* @__PURE__ */ jsx(NTableCardsLoadingSkeleton, {}) })
14329
+ ] }) : effectiveMode === "table" ? /* @__PURE__ */ jsx(NTableLoadingSkeleton, {}) : effectiveMode === "cards" ? /* @__PURE__ */ jsx(NTableCardsLoadingSkeleton, {}) : /* @__PURE__ */ jsx(NTableLoadingSkeleton, {})),
14320
14330
  error && !isLoading && /* @__PURE__ */ jsx(TableStateSlot, { children: props.renderError ? props.renderError(error) : /* @__PURE__ */ jsx(NErrorState, { message: typeof error === "string" ? error : "An error occurred" }) }),
14321
14331
  showFilteredEmpty && /* @__PURE__ */ jsx(TableStateSlot, { children: props.renderFilteredEmpty ? props.renderFilteredEmpty() : renderFilteredEmpty ? renderFilteredEmpty() : props.renderEmpty ? props.renderEmpty() : /* @__PURE__ */ jsx(DefaultTableFilteredEmptyState, {}) }),
14322
14332
  showEmpty && /* @__PURE__ */ jsx(TableStateSlot, { children: props.renderEmpty ? props.renderEmpty() : /* @__PURE__ */ jsx(DefaultTableEmptyState, { title: noDataText }) }),
@@ -14420,6 +14430,7 @@ function NTable(props) {
14420
14430
  mode,
14421
14431
  onModeChange: props.onModeChange,
14422
14432
  CardComponent: props.renderCard ?? null,
14433
+ CardSkeletonComponent: props.renderCardSkeleton ?? null,
14423
14434
  className: props.className ?? "",
14424
14435
  classNames: props.classNames ?? {},
14425
14436
  bordered: props.bordered ?? (recipeBordered ? true : void 0),
@@ -14501,6 +14512,7 @@ function NTable(props) {
14501
14512
  renderFilteredEmpty: props.renderFilteredEmpty,
14502
14513
  renderError: props.renderError,
14503
14514
  renderLoading: props.renderLoading,
14515
+ responsiveSkeleton: props.responsiveSkeleton,
14504
14516
  contextMenuClose: ctx.close,
14505
14517
  contextMenuOpen: ctx.isOpen
14506
14518
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "najm-kit",
3
- "version": "2.2.2",
3
+ "version": "2.2.4",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "description": "Reusable React UI component package for Najm framework",