@underverse-ui/underverse 0.2.48 → 0.2.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -49,6 +49,51 @@ Components use color variables like `primary`, `secondary`, `destructive`, etc.
49
49
 
50
50
  ---
51
51
 
52
+ ## ⚡ Performance Optimization
53
+
54
+ ### Optimize Package Imports (Next.js)
55
+
56
+ For best performance, add `optimizePackageImports` to your Next.js config:
57
+
58
+ ```js
59
+ // next.config.js
60
+ module.exports = {
61
+ experimental: {
62
+ optimizePackageImports: ["lucide-react", "@underverse-ui/underverse"],
63
+ },
64
+ };
65
+ ```
66
+
67
+ This provides:
68
+
69
+ - ✅ 15-70% faster dev boot
70
+ - ✅ 28% faster builds
71
+ - ✅ 40% faster cold starts
72
+ - ✅ Automatic tree-shaking for barrel imports
73
+
74
+ ### Dynamic Imports for Heavy Components
75
+
76
+ For pages that conditionally show DataTable or DatePicker:
77
+
78
+ ```tsx
79
+ import dynamic from "next/dynamic";
80
+
81
+ const DataTable = dynamic(() => import("@underverse-ui/underverse").then((m) => m.DataTable), { ssr: false, loading: () => <Skeleton /> });
82
+ ```
83
+
84
+ ### Web Interface Guidelines Compliant
85
+
86
+ All components follow [Vercel Web Interface Guidelines](https://github.com/vercel-labs/web-interface-guidelines):
87
+
88
+ - ✅ `focus-visible` ring (not `:focus`)
89
+ - ✅ Label `htmlFor` attribute
90
+ - ✅ ARIA attributes for accessibility
91
+ - ✅ `overscroll-behavior: contain` for modals
92
+ - ✅ Proper ellipsis (`…`) typography
93
+ - ✅ Locale-aware date formatting with `Intl.DateTimeFormat`
94
+
95
+ ---
96
+
52
97
  ## 🚀 Quick Start
53
98
 
54
99
  ### Standalone React (Vite, CRA, etc.)
package/dist/index.cjs CHANGED
@@ -259,29 +259,32 @@ var Button = (0, import_react.forwardRef)(
259
259
  const SpinnerIcon = Spinner ?? import_lucide_react.Activity;
260
260
  const [locked, setLocked] = (0, import_react.useState)(false);
261
261
  const lockTimer = (0, import_react.useRef)(null);
262
- const handleClick = (0, import_react.useCallback)(async (e) => {
263
- if (disabled || loading2) return;
264
- if (preventDoubleClick) {
265
- if (locked) return;
266
- setLocked(true);
267
- try {
268
- const result = onClick?.(e);
269
- if (result && typeof result === "object" && typeof result.then === "function") {
270
- await result;
262
+ const handleClick = (0, import_react.useCallback)(
263
+ async (e) => {
264
+ if (disabled || loading2) return;
265
+ if (preventDoubleClick) {
266
+ if (locked) return;
267
+ setLocked(true);
268
+ try {
269
+ const result = onClick?.(e);
270
+ if (result && typeof result === "object" && typeof result.then === "function") {
271
+ await result;
272
+ setLocked(false);
273
+ } else {
274
+ const ms = lockMs ?? 600;
275
+ if (lockTimer.current) clearTimeout(lockTimer.current);
276
+ lockTimer.current = setTimeout(() => setLocked(false), ms);
277
+ }
278
+ } catch (err) {
271
279
  setLocked(false);
272
- } else {
273
- const ms = lockMs ?? 600;
274
- if (lockTimer.current) clearTimeout(lockTimer.current);
275
- lockTimer.current = setTimeout(() => setLocked(false), ms);
280
+ throw err;
276
281
  }
277
- } catch (err) {
278
- setLocked(false);
279
- throw err;
282
+ } else {
283
+ onClick?.(e);
280
284
  }
281
- } else {
282
- onClick?.(e);
283
- }
284
- }, [disabled, loading2, onClick, locked, preventDoubleClick, lockMs]);
285
+ },
286
+ [disabled, loading2, onClick, locked, preventDoubleClick, lockMs]
287
+ );
285
288
  const computedDisabled = disabled || loading2 || (preventDoubleClick ? locked : false);
286
289
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
287
290
  "button",
@@ -312,15 +315,15 @@ var Button = (0, import_react.forwardRef)(
312
315
  "aria-label": rest["aria-label"] || title,
313
316
  ...rest,
314
317
  children: [
315
- !noHoverOverlay && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute inset-0 bg-linear-to-r from-primary-foreground/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-200 dark:hidden" }),
318
+ !noHoverOverlay ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "absolute inset-0 bg-linear-to-r from-primary-foreground/20 to-transparent opacity-0 group-hover:opacity-100 transition-opacity duration-200 dark:hidden" }) : null,
316
319
  loading2 ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
317
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SpinnerIcon, { className: "w-4 h-4 animate-spin" }),
318
- loadingText && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-2", "aria-live": "polite", children: loadingText }),
319
- preserveChildrenOnLoading && !loadingText && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-2 opacity-70", "aria-hidden": true, children })
320
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SpinnerIcon, { className: "w-4 h-4 animate-spin", "aria-hidden": "true" }),
321
+ loadingText ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-2", "aria-live": "polite", children: loadingText }) : null,
322
+ preserveChildrenOnLoading && !loadingText ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "ml-2 opacity-70", "aria-hidden": true, children }) : null
320
323
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
321
- Icon && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className: cn("transition-transform duration-200", iConClassName ? iConClassName : "w-5 h-5") }),
324
+ Icon ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Icon, { className: cn("transition-transform duration-200", iConClassName ? iConClassName : "w-5 h-5") }) : null,
322
325
  children,
323
- IconRight && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconRight, { className: "w-4 h-4 transition-transform duration-200" })
326
+ IconRight ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(IconRight, { className: "w-4 h-4 transition-transform duration-200" }) : null
324
327
  ] })
325
328
  ]
326
329
  }
@@ -589,7 +592,7 @@ var Card = ({
589
592
  "div",
590
593
  {
591
594
  className: cn(
592
- "rounded-lg md:rounded-xl bg-card text-card-foreground transition-all duration-300 ease-soft",
595
+ "rounded-lg md:rounded-xl bg-card text-card-foreground transition-[transform,box-shadow,border-color,background-color] duration-300 ease-soft",
593
596
  "shadow-sm md:hover:shadow-md mx-2 md:mx-0 border border-border",
594
597
  hoverable && "md:hover:-translate-y-0.5 md:hover:border-primary/15",
595
598
  clickable && "cursor-pointer active:translate-y-px md:hover:bg-accent/5",
@@ -1162,6 +1165,7 @@ var Input = (0, import_react3.forwardRef)(
1162
1165
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
1163
1166
  "label",
1164
1167
  {
1168
+ htmlFor: resolvedId,
1165
1169
  className: cn(
1166
1170
  // Label size follows input size
1167
1171
  size === "sm" ? "text-xs" : size === "lg" ? "text-base" : "text-sm",
@@ -1299,10 +1303,10 @@ var Input = (0, import_react3.forwardRef)(
1299
1303
  }
1300
1304
  )
1301
1305
  ] }),
1302
- errMsg && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { id: errorId, className: "flex items-center gap-2 text-sm text-destructive animate-in slide-in-from-top-1 duration-200", children: [
1306
+ errMsg ? /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { id: errorId, className: "flex items-center gap-2 text-sm text-destructive animate-in slide-in-from-top-1 duration-200", children: [
1303
1307
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react3.AlertCircle, { className: "w-4 h-4 shrink-0" }),
1304
1308
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: errMsg })
1305
- ] }),
1309
+ ] }) : null,
1306
1310
  (description || hint) && !errMsg && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
1307
1311
  "p",
1308
1312
  {
@@ -1320,7 +1324,7 @@ var Input = (0, import_react3.forwardRef)(
1320
1324
  );
1321
1325
  Input.displayName = "Input";
1322
1326
  var SearchInput = (0, import_react3.forwardRef)(
1323
- ({ onSearch, searchDelay = 300, placeholder = "Search...", ...props }, ref) => {
1327
+ ({ onSearch, searchDelay = 300, placeholder = "Search\u2026", ...props }, ref) => {
1324
1328
  const [searchValue, setSearchValue] = (0, import_react3.useState)(props.value || "");
1325
1329
  import_react3.default.useEffect(() => {
1326
1330
  if (!onSearch) return;
@@ -1567,7 +1571,7 @@ var Textarea = (0, import_react3.forwardRef)(
1567
1571
  onBlur: () => setIsFocused(false),
1568
1572
  className: cn(
1569
1573
  "w-full rounded-lg px-4 py-3 text-sm text-foreground transition-all duration-200",
1570
- "placeholder:text-muted-foreground focus:outline-none min-h-[80px]",
1574
+ "placeholder:text-muted-foreground focus:outline-none min-h-20",
1571
1575
  "disabled:cursor-not-allowed disabled:opacity-50",
1572
1576
  variantStyles6[variant],
1573
1577
  // DÒNG NÀY ĐÃ ĐƯỢC CẬP NHẬT:
@@ -3025,6 +3029,7 @@ var Modal = ({
3025
3029
  "div",
3026
3030
  {
3027
3031
  className: cn("fixed inset-0 z-9999 flex items-center justify-center", overlayClassName),
3032
+ style: { overscrollBehavior: "contain" },
3028
3033
  onMouseDown: handleOverlayMouseDown,
3029
3034
  onMouseUp: handleOverlayMouseUp,
3030
3035
  children: [
@@ -3067,12 +3072,13 @@ var Modal = ({
3067
3072
  "button",
3068
3073
  {
3069
3074
  onClick: onClose,
3075
+ "aria-label": "Close modal",
3070
3076
  className: cn(
3071
3077
  "rounded-sm opacity-70 ring-offset-background transition-opacity",
3072
3078
  "hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
3073
3079
  "disabled:pointer-events-none "
3074
3080
  ),
3075
- children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.X, { className: "h-4 w-4 cursor-pointer" })
3081
+ children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_lucide_react6.X, { className: "h-4 w-4 cursor-pointer", "aria-hidden": "true" })
3076
3082
  }
3077
3083
  )
3078
3084
  ] }),
@@ -3366,6 +3372,7 @@ var Tooltip = ({
3366
3372
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
3367
3373
  "div",
3368
3374
  {
3375
+ role: "tooltip",
3369
3376
  style: {
3370
3377
  position: "fixed",
3371
3378
  top: position.top,
@@ -4824,8 +4831,8 @@ var Combobox = ({
4824
4831
  options,
4825
4832
  value,
4826
4833
  onChange,
4827
- placeholder = "Select...",
4828
- searchPlaceholder = "Search...",
4834
+ placeholder = "Select\u2026",
4835
+ searchPlaceholder = "Search\u2026",
4829
4836
  emptyText = "No results found",
4830
4837
  className,
4831
4838
  disabled = false,
@@ -4987,7 +4994,7 @@ var Combobox = ({
4987
4994
  ] }),
4988
4995
  /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("div", { className: "max-h-64 overflow-y-auto overscroll-contain", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("ul", { className: "p-1 space-y-1", children: loading2 ? /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { className: "px-3 py-8 text-center", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col items-center gap-2 animate-in fade-in-0 zoom-in-95 duration-300", children: [
4989
4996
  /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react12.Loader2, { className: "h-6 w-6 animate-spin text-primary" }),
4990
- /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "text-sm text-muted-foreground", children: loadingText || "Loading..." })
4997
+ /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "text-sm text-muted-foreground", children: loadingText || "Loading\u2026" })
4991
4998
  ] }) }) : filteredOptions.length > 0 ? filteredOptions.map((item, index) => {
4992
4999
  const itemValue = getOptionValue(item);
4993
5000
  const itemLabel = getOptionLabel(item);
@@ -5025,7 +5032,7 @@ var Combobox = ({
5025
5032
  }) : /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("li", { className: "px-3 py-8 text-center text-muted-foreground text-sm", children: /* @__PURE__ */ (0, import_jsx_runtime25.jsxs)("div", { className: "flex flex-col items-center gap-2 animate-in fade-in-0 zoom-in-95 duration-300", children: [
5026
5033
  /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(import_lucide_react12.SearchX, { className: "h-8 w-8 opacity-40 text-muted-foreground" }),
5027
5034
  /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("span", { className: "text-sm", children: emptyText }),
5028
- query && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", onClick: () => setQuery(""), className: "text-xs text-primary hover:underline", children: "Clear search" })
5035
+ query && /* @__PURE__ */ (0, import_jsx_runtime25.jsx)("button", { type: "button", onClick: () => setQuery(""), className: "text-xs text-primary hover:underline", children: "Clear" })
5029
5036
  ] }) }) }) })
5030
5037
  ] })
5031
5038
  }
@@ -5044,6 +5051,7 @@ var Combobox = ({
5044
5051
  "label",
5045
5052
  {
5046
5053
  id: labelId,
5054
+ htmlFor: resolvedId,
5047
5055
  onClick: () => triggerRef.current?.focus(),
5048
5056
  className: cn(
5049
5057
  labelSize,
@@ -5745,6 +5753,7 @@ var DatePicker = ({
5745
5753
  "label",
5746
5754
  {
5747
5755
  id: labelId,
5756
+ htmlFor: resolvedId,
5748
5757
  onClick: () => triggerRef.current?.focus(),
5749
5758
  className: cn(
5750
5759
  labelSize,
@@ -12099,7 +12108,7 @@ function DataTable({
12099
12108
  const [curPage, setCurPage] = import_react32.default.useState(page);
12100
12109
  const hasMounted = import_react32.default.useRef(false);
12101
12110
  const loadedFromStorage = import_react32.default.useRef(false);
12102
- const getInitialPageSize = import_react32.default.useCallback(() => {
12111
+ const [curPageSize, setCurPageSize] = import_react32.default.useState(() => {
12103
12112
  if (typeof window === "undefined" || !storageKey) return pageSize;
12104
12113
  try {
12105
12114
  const saved = localStorage.getItem(`datatable_${storageKey}_pageSize`);
@@ -12113,8 +12122,7 @@ function DataTable({
12113
12122
  } catch {
12114
12123
  }
12115
12124
  return pageSize;
12116
- }, [storageKey, pageSize]);
12117
- const [curPageSize, setCurPageSize] = import_react32.default.useState(getInitialPageSize);
12125
+ });
12118
12126
  import_react32.default.useEffect(() => {
12119
12127
  if (typeof window === "undefined" || !storageKey) return;
12120
12128
  if (!hasMounted.current) return;
@@ -12150,7 +12158,8 @@ function DataTable({
12150
12158
  }, [debouncedFilters, sort, curPage, curPageSize]);
12151
12159
  const densityRowClass = density === "compact" ? "h-9" : density === "comfortable" ? "h-14" : "h-12";
12152
12160
  const cellPadding = density === "compact" ? "py-1.5 px-3" : density === "comfortable" ? "py-3 px-4" : "py-2.5 px-4";
12153
- const visibleColumns = columns.filter((c) => visibleCols.includes(c.key));
12161
+ const visibleColsSet = import_react32.default.useMemo(() => new Set(visibleCols), [visibleCols]);
12162
+ const visibleColumns = columns.filter((c) => visibleColsSet.has(c.key));
12154
12163
  const getRowKey = (row, idx) => {
12155
12164
  if (!rowKey) return String(idx);
12156
12165
  if (typeof rowKey === "function") return String(rowKey(row));
@@ -12302,7 +12311,7 @@ function DataTable({
12302
12311
  });
12303
12312
  },
12304
12313
  className: "text-xs text-destructive hover:underline",
12305
- children: "Clear filter"
12314
+ children: t("clearFilter")
12306
12315
  }
12307
12316
  )
12308
12317
  ] })
@@ -12453,27 +12462,42 @@ function DataTable({
12453
12462
  }
12454
12463
  )
12455
12464
  ] }),
12456
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "text-sm", children: "Loading..." })
12457
- ] }) }) }) : !displayedData || displayedData.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableCell, { colSpan: visibleColumns.length, className: "text-center py-6 text-muted-foreground", children: "No data" }) }) : displayedData.map((row, idx) => {
12465
+ /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "text-sm", children: [
12466
+ t("loading"),
12467
+ "\u2026"
12468
+ ] })
12469
+ ] }) }) }) : !displayedData || displayedData.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableRow, { children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableCell, { colSpan: visibleColumns.length, className: "text-center py-6 text-muted-foreground", children: t("noData") }) }) : displayedData.map((row, idx) => {
12458
12470
  const isLastRow = idx === displayedData.length - 1;
12459
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(TableRow, { className: cn(densityRowClass, striped && idx % 2 === 0 && "bg-muted/50"), children: visibleColumns.map((col, colIdx) => {
12460
- const value = col.dataIndex ? row[col.dataIndex] : void 0;
12461
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12462
- TableCell,
12463
- {
12464
- className: cn(
12465
- cellPadding,
12466
- col.align === "right" && "text-right",
12467
- col.align === "center" && "text-center",
12468
- columnDividers && colIdx > 0 && "border-l border-border/60",
12469
- isLastRow && col === visibleColumns[0] && "rounded-bl-md",
12470
- isLastRow && col === visibleColumns[visibleColumns.length - 1] && "rounded-br-md"
12471
- ),
12472
- children: col.render ? col.render(value, row, idx) : String(value ?? "")
12471
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12472
+ TableRow,
12473
+ {
12474
+ className: cn(densityRowClass, striped && idx % 2 === 0 && "bg-muted/50"),
12475
+ style: {
12476
+ // content-visibility: auto for rendering performance (skip off-screen rows)
12477
+ contentVisibility: "auto",
12478
+ containIntrinsicSize: density === "compact" ? "0 36px" : density === "comfortable" ? "0 56px" : "0 48px"
12473
12479
  },
12474
- col.key
12475
- );
12476
- }) }, getRowKey(row, idx));
12480
+ children: visibleColumns.map((col, colIdx) => {
12481
+ const value = col.dataIndex ? row[col.dataIndex] : void 0;
12482
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
12483
+ TableCell,
12484
+ {
12485
+ className: cn(
12486
+ cellPadding,
12487
+ col.align === "right" && "text-right",
12488
+ col.align === "center" && "text-center",
12489
+ columnDividers && colIdx > 0 && "border-l border-border/60",
12490
+ isLastRow && col === visibleColumns[0] && "rounded-bl-md",
12491
+ isLastRow && col === visibleColumns[visibleColumns.length - 1] && "rounded-br-md"
12492
+ ),
12493
+ children: col.render ? col.render(value, row, idx) : String(value ?? "")
12494
+ },
12495
+ col.key
12496
+ );
12497
+ })
12498
+ },
12499
+ getRowKey(row, idx)
12500
+ );
12477
12501
  }) })
12478
12502
  ]
12479
12503
  }
@@ -13486,7 +13510,14 @@ var en_default = {
13486
13510
  compact: "Compact",
13487
13511
  normal: "Normal",
13488
13512
  comfortable: "Comfortable",
13489
- columns: "Columns"
13513
+ columns: "Columns",
13514
+ loading: "Loading",
13515
+ noData: "No data",
13516
+ clearFilter: "Clear filter",
13517
+ headerAlign: "Header alignment",
13518
+ alignLeft: "Align left",
13519
+ alignCenter: "Align center",
13520
+ alignRight: "Align right"
13490
13521
  },
13491
13522
  ValidationInput: {
13492
13523
  required: "This field is required",
@@ -13549,7 +13580,14 @@ var vi_default = {
13549
13580
  compact: "G\u1ECDn",
13550
13581
  normal: "Th\u01B0\u1EDDng",
13551
13582
  comfortable: "Tho\u1EA3i m\xE1i",
13552
- columns: "C\u1ED9t"
13583
+ columns: "C\u1ED9t",
13584
+ loading: "\u0110ang t\u1EA3i",
13585
+ noData: "Kh\xF4ng c\xF3 d\u1EEF li\u1EC7u",
13586
+ clearFilter: "X\xF3a b\u1ED9 l\u1ECDc",
13587
+ headerAlign: "C\u0103n ch\u1EC9nh ti\xEAu \u0111\u1EC1",
13588
+ alignLeft: "C\u0103n tr\xE1i",
13589
+ alignCenter: "C\u0103n gi\u1EEFa",
13590
+ alignRight: "C\u0103n ph\u1EA3i"
13553
13591
  },
13554
13592
  ValidationInput: {
13555
13593
  required: "Tr\u01B0\u1EDDng n\xE0y l\xE0 b\u1EAFt bu\u1ED9c",
@@ -13612,7 +13650,14 @@ var ko_default = {
13612
13650
  compact: "\uCEF4\uD329\uD2B8",
13613
13651
  normal: "\uBCF4\uD1B5",
13614
13652
  comfortable: "\uC5EC\uC720",
13615
- columns: "\uC5F4"
13653
+ columns: "\uC5F4",
13654
+ loading: "\uB85C\uB529 \uC911",
13655
+ noData: "\uB370\uC774\uD130 \uC5C6\uC74C",
13656
+ clearFilter: "\uD544\uD130 \uC9C0\uC6B0\uAE30",
13657
+ headerAlign: "\uD5E4\uB354 \uC815\uB82C",
13658
+ alignLeft: "\uC67C\uCABD \uC815\uB82C",
13659
+ alignCenter: "\uAC00\uC6B4\uB370 \uC815\uB82C",
13660
+ alignRight: "\uC624\uB978\uCABD \uC815\uB82C"
13616
13661
  },
13617
13662
  ValidationInput: {
13618
13663
  required: "\uD544\uC218 \uC785\uB825 \uD56D\uBAA9\uC785\uB2C8\uB2E4",
@@ -13675,7 +13720,14 @@ var ja_default = {
13675
13720
  compact: "\u30B3\u30F3\u30D1\u30AF\u30C8",
13676
13721
  normal: "\u901A\u5E38",
13677
13722
  comfortable: "\u3086\u3063\u305F\u308A",
13678
- columns: "\u5217"
13723
+ columns: "\u5217",
13724
+ loading: "\u8AAD\u307F\u8FBC\u307F\u4E2D",
13725
+ noData: "\u30C7\u30FC\u30BF\u304C\u3042\u308A\u307E\u305B\u3093",
13726
+ clearFilter: "\u30D5\u30A3\u30EB\u30BF\u30FC\u3092\u30AF\u30EA\u30A2",
13727
+ headerAlign: "\u30D8\u30C3\u30C0\u30FC\u914D\u7F6E",
13728
+ alignLeft: "\u5DE6\u63C3\u3048",
13729
+ alignCenter: "\u4E2D\u592E\u63C3\u3048",
13730
+ alignRight: "\u53F3\u63C3\u3048"
13679
13731
  },
13680
13732
  ValidationInput: {
13681
13733
  required: "\u3053\u306E\u9805\u76EE\u306F\u5FC5\u9808\u3067\u3059",