@moontra/moonui 6.16.0 → 6.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +189 -108
- package/dist/index.global.js +8 -8
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +88 -26
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +88 -26
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/ui/__tests__/dark-token-contrast.test.ts +162 -0
- package/src/components/ui/__tests__/data-table-basic.test.tsx +109 -0
- package/src/components/ui/__tests__/file-upload.issue-378.test.tsx +226 -0
- package/src/components/ui/__tests__/primary-subtle-token.test.ts +95 -0
- package/src/components/ui/__tests__/progress-secondary-contrast.test.ts +231 -0
- package/src/components/ui/__tests__/progress.test.tsx +4 -1
- package/src/components/ui/__tests__/responsive-color-invariance.test.ts +92 -0
- package/src/components/ui/data-table-basic.tsx +59 -8
- package/src/components/ui/file-upload.tsx +51 -16
- package/src/components/ui/progress.tsx +14 -1
- package/src/styles/tokens.css +47 -3
- package/tailwind-preset.js +7 -0
package/dist/index.mjs
CHANGED
|
@@ -4061,23 +4061,49 @@ function DataTableBasic({
|
|
|
4061
4061
|
] }) }),
|
|
4062
4062
|
/* @__PURE__ */ jsx("div", { className: "rounded-md border", children: /* @__PURE__ */ jsxs(Table, { children: [
|
|
4063
4063
|
/* @__PURE__ */ jsx(TableHeader, { children: table.getHeaderGroups().map((headerGroup) => /* @__PURE__ */ jsx(TableRow, { children: headerGroup.headers.map((header) => {
|
|
4064
|
-
|
|
4065
|
-
|
|
4064
|
+
const canSort = enableSorting && header.column.getCanSort();
|
|
4065
|
+
const sorted = header.column.getIsSorted();
|
|
4066
|
+
const headerDef = header.column.columnDef.header;
|
|
4067
|
+
return /* @__PURE__ */ jsx(
|
|
4068
|
+
TableHead,
|
|
4066
4069
|
{
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
header.
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4079
|
-
|
|
4080
|
-
|
|
4070
|
+
"aria-sort": canSort ? sorted === "asc" ? "ascending" : sorted === "desc" ? "descending" : "none" : void 0,
|
|
4071
|
+
children: header.isPlaceholder ? null : /* @__PURE__ */ jsxs(
|
|
4072
|
+
"div",
|
|
4073
|
+
{
|
|
4074
|
+
className: cn(
|
|
4075
|
+
"flex items-center gap-2",
|
|
4076
|
+
canSort && "cursor-pointer select-none"
|
|
4077
|
+
),
|
|
4078
|
+
onClick: canSort ? header.column.getToggleSortingHandler() : void 0,
|
|
4079
|
+
children: [
|
|
4080
|
+
flexRender(
|
|
4081
|
+
header.column.columnDef.header,
|
|
4082
|
+
header.getContext()
|
|
4083
|
+
),
|
|
4084
|
+
canSort && /* #366: sıralama kontrolü yalnız fareyle çalışıyordu
|
|
4085
|
+
(dosyada `tabIndex`/`onKeyDown` grep'i 0 idi).
|
|
4086
|
+
Gerçek <button> ile Tab + Enter/Space native
|
|
4087
|
+
gelir; görünür odak focus-visible ring ile. */
|
|
4088
|
+
/* @__PURE__ */ jsx(
|
|
4089
|
+
"button",
|
|
4090
|
+
{
|
|
4091
|
+
type: "button",
|
|
4092
|
+
onClick: (event) => {
|
|
4093
|
+
event.stopPropagation();
|
|
4094
|
+
header.column.getToggleSortingHandler()?.(event);
|
|
4095
|
+
},
|
|
4096
|
+
"aria-label": `Sort by ${typeof headerDef === "string" ? headerDef : header.column.id}`,
|
|
4097
|
+
className: "ml-auto inline-flex items-center rounded-sm outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
4098
|
+
children: sorted === "desc" ? /* @__PURE__ */ jsx(ArrowDown, { className: "h-4 w-4" }) : sorted === "asc" ? /* @__PURE__ */ jsx(ArrowUp, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx(ArrowUpDown, { className: "h-4 w-4 opacity-50" })
|
|
4099
|
+
}
|
|
4100
|
+
)
|
|
4101
|
+
]
|
|
4102
|
+
}
|
|
4103
|
+
)
|
|
4104
|
+
},
|
|
4105
|
+
header.id
|
|
4106
|
+
);
|
|
4081
4107
|
}) }, headerGroup.id)) }),
|
|
4082
4108
|
/* @__PURE__ */ jsx(TableBody, { children: table.getRowModel().rows?.length ? table.getRowModel().rows.map((row) => /* @__PURE__ */ jsx(
|
|
4083
4109
|
TableRow,
|
|
@@ -4845,7 +4871,20 @@ var progressIndicatorVariants = cva(
|
|
|
4845
4871
|
variant: {
|
|
4846
4872
|
default: "bg-foreground",
|
|
4847
4873
|
primary: "bg-primary",
|
|
4848
|
-
|
|
4874
|
+
// #372: dolgu `bg-secondary` idi — track (`bg-secondary/20`) ile AYNI
|
|
4875
|
+
// yüzey token'ına basıyordu; %20 alfa track ile tam dolgu iki temada da
|
|
4876
|
+
// ~1.0 oranında kalıyor, bar görünmüyordu (light rgb(235,239,245) /
|
|
4877
|
+
// dark rgb(2,8,23)). `bg-secondary-foreground` BİLEREK seçilmedi:
|
|
4878
|
+
// light'ta --primary ile aynı hue/sat'ta yalnız ΔL=%2 (49 vs 51,
|
|
4879
|
+
// fill↔fill 1.07), dark'ta birebir --primary değeri (210 40% 98%) —
|
|
4880
|
+
// secondary varyantı primary'nin klonuna dönerdi. `--secondary-500`
|
|
4881
|
+
// (tokens.css slate skalası, RGB üçlüsü) iki temada da track'e ≥3:1
|
|
4882
|
+
// (WCAG 1.4.11) veren TEK kademe: light 4.63, dark 4.23 (gerçek kart
|
|
4883
|
+
// #111827 üstünde 3.83; 400 light'ta 2.50 ✗, 600 dark'ta 2.66 ✗).
|
|
4884
|
+
// Skala :root'ta tanımlı olduğundan tema değişiminde sabittir;
|
|
4885
|
+
// tüketici --secondary-500'ü ezerek özelleştirebilir.
|
|
4886
|
+
// Regresyon: __tests__/progress-secondary-contrast.test.ts
|
|
4887
|
+
secondary: "bg-[rgb(var(--secondary-500))]",
|
|
4849
4888
|
success: "bg-success",
|
|
4850
4889
|
warning: "bg-warning",
|
|
4851
4890
|
error: "bg-error"
|
|
@@ -4939,6 +4978,26 @@ var formatFileSize = (bytes) => {
|
|
|
4939
4978
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
4940
4979
|
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
|
|
4941
4980
|
};
|
|
4981
|
+
var matchesAcceptToken = (file, token) => {
|
|
4982
|
+
const normalized = token.trim().toLowerCase();
|
|
4983
|
+
if (!normalized)
|
|
4984
|
+
return false;
|
|
4985
|
+
if (normalized === "*" || normalized === "*/*")
|
|
4986
|
+
return true;
|
|
4987
|
+
if (normalized.startsWith(".")) {
|
|
4988
|
+
return file.name.toLowerCase().endsWith(normalized);
|
|
4989
|
+
}
|
|
4990
|
+
if (normalized.endsWith("/*")) {
|
|
4991
|
+
return file.type.toLowerCase().startsWith(normalized.slice(0, -1));
|
|
4992
|
+
}
|
|
4993
|
+
return file.type.toLowerCase() === normalized;
|
|
4994
|
+
};
|
|
4995
|
+
var isFileAccepted = (file, accept) => {
|
|
4996
|
+
const trimmed = accept.trim();
|
|
4997
|
+
if (trimmed === "" || trimmed === "*")
|
|
4998
|
+
return true;
|
|
4999
|
+
return trimmed.split(",").some((token) => matchesAcceptToken(file, token));
|
|
5000
|
+
};
|
|
4942
5001
|
var FileItem = ({
|
|
4943
5002
|
uploadedFile,
|
|
4944
5003
|
onRemove
|
|
@@ -5017,13 +5076,7 @@ var FileUpload = React12__default.forwardRef(
|
|
|
5017
5076
|
if (file.size > maxSize) {
|
|
5018
5077
|
return `File size exceeds ${formatFileSize(maxSize)}`;
|
|
5019
5078
|
}
|
|
5020
|
-
if (
|
|
5021
|
-
const cleanType = type.trim();
|
|
5022
|
-
if (cleanType.includes("*")) {
|
|
5023
|
-
return file.type.startsWith(cleanType.replace("*", ""));
|
|
5024
|
-
}
|
|
5025
|
-
return file.type === cleanType;
|
|
5026
|
-
})) {
|
|
5079
|
+
if (!isFileAccepted(file, accept)) {
|
|
5027
5080
|
return `File type not supported`;
|
|
5028
5081
|
}
|
|
5029
5082
|
return null;
|
|
@@ -5057,6 +5110,7 @@ var FileUpload = React12__default.forwardRef(
|
|
|
5057
5110
|
preview: file.type.startsWith("image/") ? URL.createObjectURL(file) : void 0
|
|
5058
5111
|
}));
|
|
5059
5112
|
setUploadedFiles((prev) => [...prev, ...newUploadedFiles]);
|
|
5113
|
+
const progressIntervals = /* @__PURE__ */ new Map();
|
|
5060
5114
|
for (const uploadedFile of newUploadedFiles) {
|
|
5061
5115
|
let progress = 0;
|
|
5062
5116
|
const interval = setInterval(() => {
|
|
@@ -5064,25 +5118,33 @@ var FileUpload = React12__default.forwardRef(
|
|
|
5064
5118
|
if (progress >= 100) {
|
|
5065
5119
|
progress = 100;
|
|
5066
5120
|
clearInterval(interval);
|
|
5121
|
+
progressIntervals.delete(uploadedFile.id);
|
|
5067
5122
|
setUploadedFiles(
|
|
5068
5123
|
(prev) => prev.map(
|
|
5069
|
-
(f) =>
|
|
5124
|
+
(f) => (
|
|
5125
|
+
// 'error'a düşmüş dosya simülasyonca geri 'success' yapılamaz —
|
|
5126
|
+
// error nihai durumdur (#378)
|
|
5127
|
+
f.id === uploadedFile.id && f.status === "uploading" ? { ...f, progress: 100, status: "success" } : f
|
|
5128
|
+
)
|
|
5070
5129
|
)
|
|
5071
5130
|
);
|
|
5072
5131
|
} else {
|
|
5073
5132
|
setUploadedFiles(
|
|
5074
5133
|
(prev) => prev.map(
|
|
5075
|
-
(f) => f.id === uploadedFile.id ? { ...f, progress } : f
|
|
5134
|
+
(f) => f.id === uploadedFile.id && f.status === "uploading" ? { ...f, progress } : f
|
|
5076
5135
|
)
|
|
5077
5136
|
);
|
|
5078
5137
|
}
|
|
5079
5138
|
}, 200);
|
|
5139
|
+
progressIntervals.set(uploadedFile.id, interval);
|
|
5080
5140
|
}
|
|
5081
5141
|
if (onUpload) {
|
|
5082
5142
|
try {
|
|
5083
5143
|
await onUpload(newUploadedFiles);
|
|
5084
5144
|
} catch (error2) {
|
|
5085
5145
|
console.error("Upload failed:", error2);
|
|
5146
|
+
progressIntervals.forEach((handle) => clearInterval(handle));
|
|
5147
|
+
progressIntervals.clear();
|
|
5086
5148
|
setUploadedFiles(
|
|
5087
5149
|
(prev) => prev.map(
|
|
5088
5150
|
(f) => newUploadedFiles.some((nf) => nf.id === f.id) ? { ...f, status: "error" } : f
|