dn-react-router-toolkit 0.7.15 → 0.8.1

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 (67) hide show
  1. package/dist/api/create_api_handler.d.mts +5 -4
  2. package/dist/api/create_api_handler.d.ts +5 -4
  3. package/dist/api/create_api_handler.js +0 -1
  4. package/dist/api/create_api_handler.mjs +0 -1
  5. package/dist/api/index.d.mts +1 -0
  6. package/dist/api/index.d.ts +1 -0
  7. package/dist/api/index.js +13 -6
  8. package/dist/api/index.mjs +14 -7
  9. package/dist/api/item_api_handler.d.mts +8 -5
  10. package/dist/api/item_api_handler.d.ts +8 -5
  11. package/dist/api/item_api_handler.js +13 -5
  12. package/dist/api/item_api_handler.mjs +14 -6
  13. package/dist/crud/crud_loader.d.mts +6 -5
  14. package/dist/crud/crud_loader.d.ts +6 -5
  15. package/dist/crud/crud_loader.js +79 -38
  16. package/dist/crud/crud_loader.mjs +81 -39
  17. package/dist/crud/crud_page.d.mts +3 -2
  18. package/dist/crud/crud_page.d.ts +3 -2
  19. package/dist/crud/crud_page.js +279 -201
  20. package/dist/crud/crud_page.mjs +277 -205
  21. package/dist/crud/generate_handlers.d.mts +3 -2
  22. package/dist/crud/generate_handlers.d.ts +3 -2
  23. package/dist/crud/generate_pages.d.mts +2 -1
  24. package/dist/crud/generate_pages.d.ts +2 -1
  25. package/dist/crud/index.d.mts +5 -3
  26. package/dist/crud/index.d.ts +5 -3
  27. package/dist/crud/index.js +338 -219
  28. package/dist/crud/index.mjs +346 -232
  29. package/dist/post/index.js +71 -64
  30. package/dist/post/index.mjs +76 -74
  31. package/dist/post/post_form_page.js +71 -64
  32. package/dist/post/post_form_page.mjs +76 -74
  33. package/dist/table/index.d.mts +7 -3
  34. package/dist/table/index.d.ts +7 -3
  35. package/dist/table/index.js +233 -111
  36. package/dist/table/index.mjs +230 -116
  37. package/dist/table/item_loader.d.mts +5 -4
  38. package/dist/table/item_loader.d.ts +5 -4
  39. package/dist/table/load_table.d.mts +36 -0
  40. package/dist/table/load_table.d.ts +36 -0
  41. package/dist/table/load_table.js +87 -0
  42. package/dist/table/load_table.mjs +66 -0
  43. package/dist/table/loader.d.mts +10 -15
  44. package/dist/table/loader.d.ts +10 -15
  45. package/dist/table/loader.js +67 -31
  46. package/dist/table/loader.mjs +67 -32
  47. package/dist/table/page.d.mts +6 -16
  48. package/dist/table/page.d.ts +6 -16
  49. package/dist/table/page.js +247 -169
  50. package/dist/table/page.mjs +248 -176
  51. package/dist/table/repository.d.mts +14 -10
  52. package/dist/table/repository.d.ts +14 -10
  53. package/dist/table/repository.js +5 -1
  54. package/dist/table/repository.mjs +5 -1
  55. package/dist/table/table.d.mts +4 -1
  56. package/dist/table/table.d.ts +4 -1
  57. package/dist/table/table.js +55 -6
  58. package/dist/table/table.mjs +55 -6
  59. package/dist/table/table_form.d.mts +13 -0
  60. package/dist/table/table_form.d.ts +13 -0
  61. package/dist/table/table_form.js +345 -0
  62. package/dist/table/table_form.mjs +320 -0
  63. package/dist/table/use_table.d.mts +4 -0
  64. package/dist/table/use_table.d.ts +4 -0
  65. package/dist/table/use_table.js +34 -0
  66. package/dist/table/use_table.mjs +9 -0
  67. package/package.json +2 -2
@@ -6510,10 +6510,10 @@ var require_listCacheClear = __commonJS({
6510
6510
  var require_eq = __commonJS({
6511
6511
  "node_modules/lodash/eq.js"(exports, module) {
6512
6512
  "use strict";
6513
- function eq(value, other) {
6513
+ function eq2(value, other) {
6514
6514
  return value === other || value !== value && other !== other;
6515
6515
  }
6516
- module.exports = eq;
6516
+ module.exports = eq2;
6517
6517
  }
6518
6518
  });
6519
6519
 
@@ -6521,11 +6521,11 @@ var require_eq = __commonJS({
6521
6521
  var require_assocIndexOf = __commonJS({
6522
6522
  "node_modules/lodash/_assocIndexOf.js"(exports, module) {
6523
6523
  "use strict";
6524
- var eq = require_eq();
6524
+ var eq2 = require_eq();
6525
6525
  function assocIndexOf(array, key) {
6526
6526
  var length = array.length;
6527
6527
  while (length--) {
6528
- if (eq(array[length][0], key)) {
6528
+ if (eq2(array[length][0], key)) {
6529
6529
  return length;
6530
6530
  }
6531
6531
  }
@@ -6983,12 +6983,12 @@ var require_assignValue = __commonJS({
6983
6983
  "node_modules/lodash/_assignValue.js"(exports, module) {
6984
6984
  "use strict";
6985
6985
  var baseAssignValue = require_baseAssignValue();
6986
- var eq = require_eq();
6986
+ var eq2 = require_eq();
6987
6987
  var objectProto = Object.prototype;
6988
6988
  var hasOwnProperty = objectProto.hasOwnProperty;
6989
6989
  function assignValue(object, key, value) {
6990
6990
  var objValue = object[key];
6991
- if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || value === void 0 && !(key in object)) {
6991
+ if (!(hasOwnProperty.call(object, key) && eq2(objValue, value)) || value === void 0 && !(key in object)) {
6992
6992
  baseAssignValue(object, key, value);
6993
6993
  }
6994
6994
  }
@@ -7977,48 +7977,83 @@ function CrudForm({
7977
7977
  ] });
7978
7978
  }
7979
7979
 
7980
- // src/table/loader.tsx
7980
+ // src/table/load_table.tsx
7981
7981
  import {
7982
7982
  and,
7983
+ eq,
7983
7984
  ilike
7984
7985
  } from "drizzle-orm";
7986
+ async function loadTable({
7987
+ request,
7988
+ repository,
7989
+ options
7990
+ }) {
7991
+ const searchParams = new URL(request.url).searchParams;
7992
+ const { where, searchKey, defaultOrderBy, defaultDirection } = options;
7993
+ const query = searchParams.get("query") ?? void 0;
7994
+ const limit = Number(searchParams.get("limit") ?? "20");
7995
+ const offset = Number(searchParams.get("offset") ?? "0");
7996
+ const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
7997
+ const direction = searchParams.get("direction") ?? defaultDirection;
7998
+ const filterWhere = Object.entries(options.filters ?? {}).map(([key, value]) => {
7999
+ const param = searchParams.get(key);
8000
+ if (param) {
8001
+ return eq(
8002
+ repository.schema[key],
8003
+ decodeURIComponent(param)
8004
+ );
8005
+ }
8006
+ return void 0;
8007
+ }).filter(Boolean);
8008
+ const whereClauses = and(
8009
+ searchKey && query ? ilike(
8010
+ repository.schema[searchKey],
8011
+ `%${query}%`
8012
+ ) : void 0,
8013
+ ...filterWhere,
8014
+ ...where ?? []
8015
+ );
8016
+ const total = await repository.countTotal({ where: whereClauses });
8017
+ const items = await repository.findAll({
8018
+ orderBy,
8019
+ direction,
8020
+ limit,
8021
+ offset,
8022
+ where: whereClauses
8023
+ });
8024
+ const filters = Object.fromEntries(
8025
+ await Promise.all(
8026
+ Object.keys(options.filters ?? {}).map(async (key) => {
8027
+ const values = await repository.select(key);
8028
+ return [key, values.filter(Boolean)];
8029
+ })
8030
+ )
8031
+ );
8032
+ return {
8033
+ items,
8034
+ total,
8035
+ limit,
8036
+ offset,
8037
+ orderBy,
8038
+ direction,
8039
+ searchKey,
8040
+ filters
8041
+ };
8042
+ }
8043
+
8044
+ // src/table/loader.tsx
7985
8045
  function tableLoader({
7986
8046
  repository,
7987
- tableOptions
8047
+ options
7988
8048
  }) {
7989
8049
  return async ({ request }) => {
7990
- const searchParams = new URL(request.url).searchParams;
7991
- const { where, searchKey, defaultOrderBy, defaultDirection } = tableOptions;
7992
- const query = searchParams.get("query") ?? void 0;
7993
- const limit = Number(searchParams.get("limit") ?? "10");
7994
- const offset = Number(searchParams.get("offset") ?? "0");
7995
- const orderBy = searchParams.get("orderBy") ?? defaultOrderBy;
7996
- const direction = searchParams.get("direction") ?? defaultDirection;
7997
- const whereClauses = and(
7998
- searchKey && query ? ilike(
7999
- repository.schema[searchKey],
8000
- `%${query}%`
8001
- ) : void 0,
8002
- ...where ?? []
8003
- );
8004
- const total = await repository.countTotal({ where: whereClauses });
8005
- const items = await repository.findAll({
8006
- orderBy,
8007
- direction,
8008
- limit,
8009
- offset,
8010
- where: whereClauses
8050
+ const table = await loadTable({
8051
+ request,
8052
+ repository,
8053
+ options
8011
8054
  });
8012
8055
  return {
8013
- table: {
8014
- items,
8015
- total,
8016
- limit,
8017
- offset,
8018
- orderBy,
8019
- direction,
8020
- searchKey
8021
- }
8056
+ table
8022
8057
  };
8023
8058
  };
8024
8059
  }
@@ -8051,7 +8086,6 @@ import {
8051
8086
  import {
8052
8087
  and as and2
8053
8088
  } from "drizzle-orm";
8054
- import "react-router";
8055
8089
  import { v4 } from "uuid";
8056
8090
  function apiHandler({
8057
8091
  withAuthAction,
@@ -8139,22 +8173,30 @@ function apiHandler({
8139
8173
  }
8140
8174
 
8141
8175
  // src/api/item_api_handler.ts
8142
- import { UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
8143
- import "react-router";
8176
+ import { FORBIDDEN, NOT_FOUND, UNAUTHORIZED as UNAUTHORIZED2 } from "dn-react-toolkit/http";
8144
8177
  function itemApiHandler({
8145
8178
  withAuthAction,
8146
- repository
8179
+ repository,
8180
+ isOwnedBy,
8181
+ roles
8147
8182
  }) {
8148
8183
  const loader = async ({ request }) => {
8149
8184
  return {};
8150
8185
  };
8151
8186
  const action = withAuthAction((auth) => async ({ params, request }) => {
8152
- if (!auth || auth.role !== "admin") {
8153
- return UNAUTHORIZED2();
8187
+ if (roles && roles.length > 0 && (!auth || !roles.includes(auth.role))) {
8188
+ throw UNAUTHORIZED2();
8189
+ }
8190
+ const itemId = params.itemId;
8191
+ const existing = await repository.find(itemId);
8192
+ if (!existing) {
8193
+ throw NOT_FOUND();
8194
+ }
8195
+ if (isOwnedBy && !isOwnedBy(existing, auth)) {
8196
+ throw FORBIDDEN();
8154
8197
  }
8155
8198
  switch (request.method) {
8156
8199
  case "DELETE": {
8157
- const itemId = params.itemId;
8158
8200
  await repository.delete(itemId);
8159
8201
  return {};
8160
8202
  }
@@ -8232,96 +8274,20 @@ function crudHandler({
8232
8274
  }
8233
8275
 
8234
8276
  // src/crud/crud_page.tsx
8235
- import { useLoaderData as useLoaderData2, useLocation as useLocation3 } from "react-router";
8277
+ import { useLoaderData as useLoaderData2, useLocation as useLocation4 } from "react-router";
8236
8278
 
8237
8279
  // src/table/page.tsx
8238
- import {
8239
- Link as Link3,
8240
- useLoaderData,
8241
- useLocation as useLocation2,
8242
- useNavigate as useNavigate2,
8243
- useSearchParams as useSearchParams3
8244
- } from "react-router";
8245
- import { GoSearch } from "react-icons/go";
8280
+ import { Link as Link3, useLocation as useLocation3 } from "react-router";
8246
8281
 
8247
- // src/table/buttons.tsx
8248
- import { cn as cn2 } from "dn-react-toolkit/utils";
8249
- import { Link, useLocation, useSearchParams } from "react-router";
8250
- import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
8251
- function TablePageButtons({
8252
- MAX_PAGES_TO_SHOW,
8253
- total,
8254
- limit,
8255
- offset
8256
- }) {
8257
- const pages = Math.ceil(total / limit);
8258
- const { pathname } = useLocation();
8259
- const [searchParams] = useSearchParams();
8260
- const currentPage = Math.floor(offset / limit) + 1;
8261
- const startButton = (Math.ceil(currentPage / MAX_PAGES_TO_SHOW) - 1) * MAX_PAGES_TO_SHOW;
8262
- const endButton = Math.min(startButton + MAX_PAGES_TO_SHOW - 1, pages);
8263
- return /* @__PURE__ */ jsx7(Fragment3, { children: pages > 1 && /* @__PURE__ */ jsxs3("div", { className: "flex justify-center items-center my-8 gap-4 text-neutral-400", children: [
8264
- startButton > 1 && /* @__PURE__ */ jsx7(
8265
- Link,
8266
- {
8267
- to: (() => {
8268
- searchParams.set(
8269
- "offset",
8270
- String((startButton - 1) * limit)
8271
- );
8272
- return `${pathname}?${searchParams.toString()}`;
8273
- })(),
8274
- className: "w-10 block text-center transition-colors hover:text-primary",
8275
- children: "\uC774\uC804"
8276
- }
8277
- ),
8278
- Array.from({
8279
- length: Math.min(
8280
- MAX_PAGES_TO_SHOW,
8281
- pages - startButton
8282
- )
8283
- }).map((_, index2) => {
8284
- return /* @__PURE__ */ jsx7(
8285
- Link,
8286
- {
8287
- to: (() => {
8288
- searchParams.set(
8289
- "offset",
8290
- String((startButton + index2) * limit)
8291
- );
8292
- return `${pathname}?${searchParams.toString()}`;
8293
- })(),
8294
- className: cn2(
8295
- "w-6 block text-center transition-colors",
8296
- currentPage === startButton + index2 + 1 ? "font-bold text-primary" : "hover:text-primary"
8297
- ),
8298
- children: startButton + index2 + 1
8299
- },
8300
- index2
8301
- );
8302
- }),
8303
- endButton < pages && /* @__PURE__ */ jsx7(
8304
- Link,
8305
- {
8306
- to: (() => {
8307
- searchParams.set(
8308
- "offset",
8309
- String((endButton + 1) * limit)
8310
- );
8311
- return `${pathname}?${searchParams.toString()}`;
8312
- })(),
8313
- className: "w-10 block text-center transition-colors hover:text-primary",
8314
- children: "\uB2E4\uC74C"
8315
- }
8316
- )
8317
- ] }) });
8318
- }
8282
+ // src/table/table_form.tsx
8283
+ import { useLocation as useLocation2, useNavigate as useNavigate2, useSearchParams as useSearchParams3 } from "react-router";
8284
+ import { GoSearch } from "react-icons/go";
8319
8285
 
8320
8286
  // src/table/table.tsx
8321
- import { cn as cn3 } from "dn-react-toolkit/utils";
8287
+ import { cn as cn2 } from "dn-react-toolkit/utils";
8322
8288
  import { GoArrowDown, GoArrowUp } from "react-icons/go";
8323
- import { Link as Link2, useSearchParams as useSearchParams2 } from "react-router";
8324
- import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
8289
+ import { Link, useSearchParams } from "react-router";
8290
+ import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
8325
8291
  function Table({
8326
8292
  className = "min-w-full whitespace-nowrap",
8327
8293
  data,
@@ -8331,17 +8297,21 @@ function Table({
8331
8297
  limit,
8332
8298
  offset,
8333
8299
  orderBy,
8334
- direction
8300
+ direction,
8301
+ filters
8335
8302
  }) {
8336
8303
  const keys = Object.entries(columns).filter((entry) => entry[1]).map(([key]) => key);
8337
8304
  const sortedArray = [...data];
8338
- const [_, setSearchParams] = useSearchParams2();
8339
- return /* @__PURE__ */ jsxs4(
8305
+ const [_, setSearchParams] = useSearchParams();
8306
+ return /* @__PURE__ */ jsxs3(
8340
8307
  "table",
8341
8308
  {
8342
- className: cn3(className, "text-[15px] border-separate border-spacing-0"),
8309
+ className: cn2(
8310
+ className,
8311
+ "text-[15px] border-separate border-spacing-0"
8312
+ ),
8343
8313
  children: [
8344
- /* @__PURE__ */ jsx8("thead", { children: /* @__PURE__ */ jsx8("tr", { children: keys.map((key) => {
8314
+ /* @__PURE__ */ jsx7("thead", { children: /* @__PURE__ */ jsx7("tr", { children: keys.map((key) => {
8345
8315
  const value = columns[key];
8346
8316
  function getReactNode() {
8347
8317
  if (value && typeof value === "object" && "label" in value) {
@@ -8352,12 +8322,12 @@ function Table({
8352
8322
  function Head() {
8353
8323
  const reactNode = getReactNode();
8354
8324
  if (typeof reactNode === "string") {
8355
- return /* @__PURE__ */ jsxs4(
8325
+ return /* @__PURE__ */ jsxs3(
8356
8326
  "button",
8357
8327
  {
8358
- className: cn3(
8359
- orderBy === key ? "text-neutral-900 font-medium" : "text-neutral-500",
8360
- "px-4 h-14 flex items-center w-full"
8328
+ className: cn2(
8329
+ orderBy === key ? "text-gray-900 font-medium" : "text-gray-500 font-medium",
8330
+ "px-4 flex items-center w-full"
8361
8331
  ),
8362
8332
  onClick: () => {
8363
8333
  let newDirection = "asc";
@@ -8371,25 +8341,70 @@ function Table({
8371
8341
  },
8372
8342
  children: [
8373
8343
  reactNode,
8374
- orderBy === key && /* @__PURE__ */ jsx8("div", { className: "ml-0.5", children: direction === "asc" ? /* @__PURE__ */ jsx8(GoArrowUp, {}) : /* @__PURE__ */ jsx8(GoArrowDown, {}) })
8344
+ orderBy === key && /* @__PURE__ */ jsx7("div", { className: "ml-0.5", children: direction === "asc" ? /* @__PURE__ */ jsx7(GoArrowUp, {}) : /* @__PURE__ */ jsx7(GoArrowDown, {}) })
8375
8345
  ]
8376
8346
  }
8377
8347
  );
8378
8348
  }
8379
- return /* @__PURE__ */ jsx8(Fragment4, { children: reactNode });
8349
+ return /* @__PURE__ */ jsx7(Fragment3, { children: reactNode });
8380
8350
  }
8381
- return /* @__PURE__ */ jsx8("th", { className: cn3("border-y font-normal"), children: /* @__PURE__ */ jsx8(Head, {}) }, key);
8351
+ const filter = filters[key];
8352
+ return /* @__PURE__ */ jsxs3(
8353
+ "th",
8354
+ {
8355
+ className: cn2(
8356
+ "py-4 border-y font-normal align-top"
8357
+ ),
8358
+ children: [
8359
+ /* @__PURE__ */ jsx7(Head, {}),
8360
+ filter && /* @__PURE__ */ jsx7("div", { className: "px-3 mt-4", children: /* @__PURE__ */ jsxs3(
8361
+ "select",
8362
+ {
8363
+ className: "w-full h-10 px-1.5 border rounded-full outline-none",
8364
+ onChange: (e) => {
8365
+ const value2 = e.target.value;
8366
+ setSearchParams((prev) => {
8367
+ if (value2) {
8368
+ prev.set(
8369
+ key,
8370
+ encodeURIComponent(
8371
+ value2
8372
+ )
8373
+ );
8374
+ } else {
8375
+ prev.delete(key);
8376
+ }
8377
+ return prev;
8378
+ });
8379
+ },
8380
+ children: [
8381
+ /* @__PURE__ */ jsx7("option", { value: "", children: "\uC804\uCCB4" }),
8382
+ filter.map((option) => /* @__PURE__ */ jsx7(
8383
+ "option",
8384
+ {
8385
+ value: option,
8386
+ children: option
8387
+ },
8388
+ option
8389
+ ))
8390
+ ]
8391
+ }
8392
+ ) })
8393
+ ]
8394
+ },
8395
+ key
8396
+ );
8382
8397
  }) }) }),
8383
- /* @__PURE__ */ jsxs4("tbody", { children: [
8384
- sortedArray.length === 0 && /* @__PURE__ */ jsx8("tr", { children: /* @__PURE__ */ jsx8(
8398
+ /* @__PURE__ */ jsxs3("tbody", { children: [
8399
+ sortedArray.length === 0 && /* @__PURE__ */ jsx7("tr", { children: /* @__PURE__ */ jsx7(
8385
8400
  "td",
8386
8401
  {
8387
8402
  colSpan: keys.length,
8388
- className: "px-4 h-14 text-neutral-400 text-center",
8403
+ className: "px-4 h-20 text-gray-400 text-center",
8389
8404
  children: "\uB370\uC774\uD130\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4."
8390
8405
  }
8391
8406
  ) }),
8392
- sortedArray.map((item, i) => /* @__PURE__ */ jsx8("tr", { className: "hover:bg-gray-50 transition-colors", children: keys.map((key, i2) => {
8407
+ sortedArray.map((item, i) => /* @__PURE__ */ jsx7("tr", { className: "hover:bg-gray-50 transition-colors", children: keys.map((key, i2) => {
8393
8408
  const value = item[key];
8394
8409
  function Content() {
8395
8410
  if (key in columns) {
@@ -8397,22 +8412,22 @@ function Table({
8397
8412
  if (column && typeof column === "object" && "mapper" in column) {
8398
8413
  const mapper = column.mapper;
8399
8414
  if (mapper) {
8400
- return /* @__PURE__ */ jsx8(Fragment4, { children: mapper(item) });
8415
+ return /* @__PURE__ */ jsx7(Fragment3, { children: mapper(item) });
8401
8416
  }
8402
8417
  }
8403
8418
  }
8404
- return /* @__PURE__ */ jsx8(Fragment4, { children: String(value) });
8419
+ return /* @__PURE__ */ jsx7(Fragment3, { children: String(value) });
8405
8420
  }
8406
- const linkedContent = getLink ? /* @__PURE__ */ jsx8(
8407
- Link2,
8421
+ const linkedContent = getLink ? /* @__PURE__ */ jsx7(
8422
+ Link,
8408
8423
  {
8409
8424
  to: getLink(item),
8410
8425
  className: "block content-center px-4 w-full h-full",
8411
- children: /* @__PURE__ */ jsx8(Content, {})
8426
+ children: /* @__PURE__ */ jsx7(Content, {})
8412
8427
  }
8413
- ) : /* @__PURE__ */ jsx8(Content, {});
8414
- const cell = Mapper ? /* @__PURE__ */ jsx8(Mapper, { item, index: i2, children: linkedContent }) : linkedContent;
8415
- return /* @__PURE__ */ jsx8("td", { className: "px-0 h-14 border-b", children: cell }, key);
8428
+ ) : /* @__PURE__ */ jsx7(Content, {});
8429
+ const cell = Mapper ? /* @__PURE__ */ jsx7(Mapper, { item, index: i2, children: linkedContent }) : linkedContent;
8430
+ return /* @__PURE__ */ jsx7("td", { className: "px-0 h-14 border-b", children: cell }, key);
8416
8431
  }) }, i))
8417
8432
  ] })
8418
8433
  ]
@@ -8420,8 +8435,170 @@ function Table({
8420
8435
  );
8421
8436
  }
8422
8437
 
8423
- // src/table/page.tsx
8438
+ // src/table/use_table.tsx
8439
+ import { useLoaderData } from "react-router";
8440
+ function useTable() {
8441
+ const { table } = useLoaderData();
8442
+ return table;
8443
+ }
8444
+
8445
+ // src/table/buttons.tsx
8446
+ import { cn as cn3 } from "dn-react-toolkit/utils";
8447
+ import { Link as Link2, useLocation, useSearchParams as useSearchParams2 } from "react-router";
8448
+ import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
8449
+ function TablePageButtons({
8450
+ MAX_PAGES_TO_SHOW,
8451
+ total,
8452
+ limit,
8453
+ offset
8454
+ }) {
8455
+ const pages = Math.ceil(total / limit);
8456
+ const { pathname } = useLocation();
8457
+ const [searchParams] = useSearchParams2();
8458
+ const currentPage = Math.floor(offset / limit) + 1;
8459
+ const startButton = (Math.ceil(currentPage / MAX_PAGES_TO_SHOW) - 1) * MAX_PAGES_TO_SHOW;
8460
+ const endButton = Math.min(startButton + MAX_PAGES_TO_SHOW - 1, pages);
8461
+ return /* @__PURE__ */ jsx8(Fragment4, { children: pages > 1 && /* @__PURE__ */ jsxs4("div", { className: "flex justify-center items-center my-8 gap-4 text-neutral-400", children: [
8462
+ startButton > 1 && /* @__PURE__ */ jsx8(
8463
+ Link2,
8464
+ {
8465
+ to: (() => {
8466
+ searchParams.set(
8467
+ "offset",
8468
+ String((startButton - 1) * limit)
8469
+ );
8470
+ return `${pathname}?${searchParams.toString()}`;
8471
+ })(),
8472
+ className: "w-10 block text-center transition-colors hover:text-primary",
8473
+ children: "\uC774\uC804"
8474
+ }
8475
+ ),
8476
+ Array.from({
8477
+ length: Math.min(
8478
+ MAX_PAGES_TO_SHOW,
8479
+ pages - startButton
8480
+ )
8481
+ }).map((_, index2) => {
8482
+ return /* @__PURE__ */ jsx8(
8483
+ Link2,
8484
+ {
8485
+ to: (() => {
8486
+ searchParams.set(
8487
+ "offset",
8488
+ String((startButton + index2) * limit)
8489
+ );
8490
+ return `${pathname}?${searchParams.toString()}`;
8491
+ })(),
8492
+ className: cn3(
8493
+ "w-6 block text-center transition-colors",
8494
+ currentPage === startButton + index2 + 1 ? "font-bold text-primary" : "hover:text-primary"
8495
+ ),
8496
+ children: startButton + index2 + 1
8497
+ },
8498
+ index2
8499
+ );
8500
+ }),
8501
+ endButton < pages && /* @__PURE__ */ jsx8(
8502
+ Link2,
8503
+ {
8504
+ to: (() => {
8505
+ searchParams.set(
8506
+ "offset",
8507
+ String((endButton + 1) * limit)
8508
+ );
8509
+ return `${pathname}?${searchParams.toString()}`;
8510
+ })(),
8511
+ className: "w-10 block text-center transition-colors hover:text-primary",
8512
+ children: "\uB2E4\uC74C"
8513
+ }
8514
+ )
8515
+ ] }) });
8516
+ }
8517
+
8518
+ // src/table/table_form.tsx
8424
8519
  import { Fragment as Fragment5, jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
8520
+ function TableForm({
8521
+ columns,
8522
+ primaryKey = "id"
8523
+ }) {
8524
+ const { pathname } = useLocation2();
8525
+ const {
8526
+ items,
8527
+ total,
8528
+ limit,
8529
+ offset,
8530
+ orderBy,
8531
+ direction,
8532
+ searchKey,
8533
+ filters
8534
+ } = useTable();
8535
+ const navigate = useNavigate2();
8536
+ const search = (query) => {
8537
+ const searchParams2 = new URLSearchParams(window.location.search);
8538
+ searchParams2.set("query", query);
8539
+ searchParams2.set("offset", "0");
8540
+ navigate(`${pathname}?${searchParams2.toString()}`);
8541
+ };
8542
+ const [searchParams] = useSearchParams3();
8543
+ return /* @__PURE__ */ jsxs5(Fragment5, { children: [
8544
+ searchKey && /* @__PURE__ */ jsxs5(
8545
+ "form",
8546
+ {
8547
+ className: "h-20 px-4 flex items-center border-t",
8548
+ onSubmit: (e) => {
8549
+ e.preventDefault();
8550
+ const formData = new FormData(e.currentTarget);
8551
+ const query = formData.get("query");
8552
+ search(query);
8553
+ },
8554
+ children: [
8555
+ /* @__PURE__ */ jsx9(
8556
+ "button",
8557
+ {
8558
+ type: "submit",
8559
+ className: "w-10 h-10 flex justify-center items-center",
8560
+ children: /* @__PURE__ */ jsx9(GoSearch, { className: "text-xl mr-4" })
8561
+ }
8562
+ ),
8563
+ /* @__PURE__ */ jsx9(
8564
+ "input",
8565
+ {
8566
+ className: "outline-none h-full flex-1",
8567
+ placeholder: "\uC5EC\uAE30\uC5D0 \uAC80\uC0C9\uD558\uC138\uC694...",
8568
+ name: "query",
8569
+ defaultValue: searchParams.get("query") ?? ""
8570
+ }
8571
+ )
8572
+ ]
8573
+ }
8574
+ ),
8575
+ /* @__PURE__ */ jsx9(
8576
+ Table,
8577
+ {
8578
+ data: items,
8579
+ columns,
8580
+ getLink: primaryKey ? (item) => `${pathname}/${item[primaryKey]}` : void 0,
8581
+ limit,
8582
+ offset,
8583
+ orderBy,
8584
+ direction,
8585
+ filters
8586
+ }
8587
+ ),
8588
+ /* @__PURE__ */ jsx9(
8589
+ TablePageButtons,
8590
+ {
8591
+ total,
8592
+ limit,
8593
+ offset,
8594
+ MAX_PAGES_TO_SHOW: 10
8595
+ }
8596
+ )
8597
+ ] });
8598
+ }
8599
+
8600
+ // src/table/page.tsx
8601
+ import { Fragment as Fragment6, jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
8425
8602
  function createTablePage({
8426
8603
  name,
8427
8604
  columns,
@@ -8430,88 +8607,25 @@ function createTablePage({
8430
8607
  return function TablePage({
8431
8608
  header: Header
8432
8609
  }) {
8433
- const { pathname } = useLocation2();
8434
- const { table } = useLoaderData();
8435
- const { items, total, limit, offset, orderBy, direction, searchKey } = table;
8436
- const navigate = useNavigate2();
8437
- const search = (query) => {
8438
- const searchParams2 = new URLSearchParams(window.location.search);
8439
- searchParams2.set("query", query);
8440
- searchParams2.set("offset", "0");
8441
- navigate(`${pathname}?${searchParams2.toString()}`);
8442
- };
8443
- const [searchParams] = useSearchParams3();
8444
- return /* @__PURE__ */ jsxs5(Fragment5, { children: [
8445
- /* @__PURE__ */ jsx9(
8610
+ const { pathname } = useLocation3();
8611
+ return /* @__PURE__ */ jsxs6(Fragment6, { children: [
8612
+ /* @__PURE__ */ jsx10(
8446
8613
  Header,
8447
8614
  {
8448
8615
  title: name,
8449
- actions: /* @__PURE__ */ jsxs5(Link3, { to: `${pathname}/new`, className: "button-primary", children: [
8616
+ actions: /* @__PURE__ */ jsxs6(Link3, { to: `${pathname}/new`, className: "button-primary", children: [
8450
8617
  name,
8451
8618
  " \uCD94\uAC00"
8452
8619
  ] })
8453
8620
  }
8454
8621
  ),
8455
- /* @__PURE__ */ jsxs5("div", { className: "max-w-7xl mx-auto w-full overflow-auto", children: [
8456
- searchKey && /* @__PURE__ */ jsxs5(
8457
- "form",
8458
- {
8459
- className: "h-18 px-4 flex items-center border-t",
8460
- onSubmit: (e) => {
8461
- e.preventDefault();
8462
- const formData = new FormData(e.currentTarget);
8463
- const query = formData.get("query");
8464
- search(query);
8465
- },
8466
- children: [
8467
- /* @__PURE__ */ jsx9(
8468
- "button",
8469
- {
8470
- type: "submit",
8471
- className: "w-10 h-10 flex justify-center items-center",
8472
- children: /* @__PURE__ */ jsx9(GoSearch, { className: "text-xl mr-4" })
8473
- }
8474
- ),
8475
- /* @__PURE__ */ jsx9(
8476
- "input",
8477
- {
8478
- className: "outline-none h-full flex-1",
8479
- placeholder: "\uC5EC\uAE30\uC5D0 \uAC80\uC0C9\uD558\uC138\uC694...",
8480
- name: "query",
8481
- defaultValue: searchParams.get("query") ?? ""
8482
- }
8483
- )
8484
- ]
8485
- }
8486
- ),
8487
- /* @__PURE__ */ jsx9(
8488
- Table,
8489
- {
8490
- data: items,
8491
- columns,
8492
- getLink: primaryKey ? (item) => `${pathname}/${item[primaryKey]}` : void 0,
8493
- limit,
8494
- offset,
8495
- orderBy,
8496
- direction
8497
- }
8498
- ),
8499
- /* @__PURE__ */ jsx9(
8500
- TablePageButtons,
8501
- {
8502
- total,
8503
- limit,
8504
- offset,
8505
- MAX_PAGES_TO_SHOW: 10
8506
- }
8507
- )
8508
- ] })
8622
+ /* @__PURE__ */ jsx10("div", { className: "max-w-7xl mx-auto w-full overflow-auto", children: /* @__PURE__ */ jsx10(TableForm, { columns, primaryKey }) })
8509
8623
  ] });
8510
8624
  };
8511
8625
  }
8512
8626
 
8513
8627
  // src/crud/crud_page.tsx
8514
- import { jsx as jsx10 } from "react/jsx-runtime";
8628
+ import { jsx as jsx11 } from "react/jsx-runtime";
8515
8629
  function crudPage({
8516
8630
  name,
8517
8631
  primaryKey,
@@ -8522,16 +8636,16 @@ function crudPage({
8522
8636
  const create = (prefix2) => {
8523
8637
  return function Page() {
8524
8638
  const data = useLoaderData2();
8525
- const { pathname } = useLocation3();
8639
+ const { pathname } = useLocation4();
8526
8640
  if (pathname === prefix2) {
8527
8641
  const Component = createTablePage({
8528
8642
  ...tablePageOptions,
8529
8643
  name
8530
8644
  });
8531
- return /* @__PURE__ */ jsx10(Component, { header });
8645
+ return /* @__PURE__ */ jsx11(Component, { header });
8532
8646
  }
8533
8647
  if (pathname.startsWith(prefix2)) {
8534
- return /* @__PURE__ */ jsx10(
8648
+ return /* @__PURE__ */ jsx11(
8535
8649
  CrudFormProvider,
8536
8650
  {
8537
8651
  item: data?.item,
@@ -8539,7 +8653,7 @@ function crudPage({
8539
8653
  name,
8540
8654
  columns: formOptions.columns,
8541
8655
  primaryKey,
8542
- children: formOptions.form ? /* @__PURE__ */ jsx10(FormDelegate, { component: formOptions.form }) : /* @__PURE__ */ jsx10(CrudForm, { AdminHeader: header })
8656
+ children: formOptions.form ? /* @__PURE__ */ jsx11(FormDelegate, { component: formOptions.form }) : /* @__PURE__ */ jsx11(CrudForm, { AdminHeader: header })
8543
8657
  }
8544
8658
  );
8545
8659
  }
@@ -8554,7 +8668,7 @@ function FormDelegate({
8554
8668
  component: Component
8555
8669
  }) {
8556
8670
  const form = useFormContext();
8557
- return /* @__PURE__ */ jsx10(Component, { form });
8671
+ return /* @__PURE__ */ jsx11(Component, { form });
8558
8672
  }
8559
8673
 
8560
8674
  // src/crud/generate_handlers.ts
@@ -8570,15 +8684,15 @@ var generateHandlers = (handlers) => {
8570
8684
  };
8571
8685
 
8572
8686
  // src/crud/generate_pages.tsx
8573
- import { useLocation as useLocation4 } from "react-router";
8574
- import { jsx as jsx11 } from "react/jsx-runtime";
8687
+ import { useLocation as useLocation5 } from "react-router";
8688
+ import { jsx as jsx12 } from "react/jsx-runtime";
8575
8689
  var generatePages = (pages) => {
8576
8690
  function Page() {
8577
- const { pathname } = useLocation4();
8691
+ const { pathname } = useLocation5();
8578
8692
  for (const route2 of Object.keys(pages)) {
8579
8693
  if (pathname.startsWith(route2)) {
8580
8694
  const Page2 = pages[route2].create(route2);
8581
- return /* @__PURE__ */ jsx11(Page2, {});
8695
+ return /* @__PURE__ */ jsx12(Page2, {});
8582
8696
  }
8583
8697
  }
8584
8698
  }