@incursa/ui-kit 1.6.1 → 1.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.
- package/dist/inc-design-language.css +111 -51
- package/dist/inc-design-language.css.map +1 -1
- package/dist/inc-design-language.js +326 -1
- package/dist/inc-design-language.min.css +1 -1
- package/dist/inc-design-language.min.css.map +1 -1
- package/dist/mcp/components/buttons.json +3 -3
- package/dist/mcp/components/status.json +3 -3
- package/dist/mcp/examples/reference.json +2 -2
- package/dist/mcp/examples/states.json +2 -2
- package/dist/mcp/examples/web-components.json +2 -2
- package/dist/mcp/guides/latest.json +2 -2
- package/dist/mcp/guides/package-metadata.json +2 -2
- package/dist/mcp/guides/update.json +2 -2
- package/dist/mcp/install.json +1 -1
- package/dist/mcp/patterns/reference.json +2 -2
- package/dist/mcp/patterns/states.json +2 -2
- package/dist/mcp/patterns/web-components.json +2 -2
- package/dist/mcp/resources.json +49 -49
- package/dist/mcp/search-index.json +13 -13
- package/dist/mcp/update.json +2 -2
- package/dist/mcp/worker.mjs +282 -162
- package/dist/mcp/worker.mjs.map +2 -2
- package/dist/web-components/components/actions.js +89 -13
- package/dist/web-components/components/feedback.js +17 -4
- package/dist/web-components/index.js +92 -17
- package/package.json +1 -1
- package/src/inc-design-language.js +326 -1
- package/src/inc-design-language.scss +141 -55
- package/src/web-components/components/actions.js +89 -13
- package/src/web-components/components/feedback.js +17 -4
|
@@ -14,6 +14,12 @@
|
|
|
14
14
|
nativeDialogOpen: "[data-inc-native-dialog-open]",
|
|
15
15
|
autoRefresh: "[data-inc-auto-refresh]",
|
|
16
16
|
autoRefreshToggle: '[data-inc-action="auto-refresh-toggle"]',
|
|
17
|
+
fileExample: "[data-inc-file-example]",
|
|
18
|
+
fileDropzone: "[data-inc-file-dropzone]",
|
|
19
|
+
fileInput: "[data-inc-file-input]",
|
|
20
|
+
fileBrowse: "[data-inc-file-browse]",
|
|
21
|
+
fileList: "[data-inc-file-list]",
|
|
22
|
+
fileRemove: '[data-inc-action="file-remove"]',
|
|
17
23
|
modalToggle: '[data-inc-toggle="modal"]',
|
|
18
24
|
modalDismiss: '[data-inc-dismiss="modal"]',
|
|
19
25
|
offcanvasToggle: '[data-inc-toggle="offcanvas"]',
|
|
@@ -824,6 +830,298 @@
|
|
|
824
830
|
return parsed;
|
|
825
831
|
}
|
|
826
832
|
|
|
833
|
+
function formatFileExampleSize(bytes) {
|
|
834
|
+
if (!Number.isFinite(bytes) || bytes <= 0) {
|
|
835
|
+
return "0 B";
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
if (bytes < 1024) {
|
|
839
|
+
return `${bytes} B`;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
const units = ["KB", "MB", "GB", "TB"];
|
|
843
|
+
let value = bytes / 1024;
|
|
844
|
+
let unitIndex = 0;
|
|
845
|
+
|
|
846
|
+
while (value >= 1024 && unitIndex < (units.length - 1)) {
|
|
847
|
+
value /= 1024;
|
|
848
|
+
unitIndex += 1;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
const precision = value >= 10 ? 0 : 1;
|
|
852
|
+
return `${value.toFixed(precision)} ${units[unitIndex]}`;
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
function getFileExampleTypeLabel(file) {
|
|
856
|
+
if (!(file instanceof File)) {
|
|
857
|
+
return "File";
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
const extensionMatch = /\.([a-z0-9]+)$/i.exec(file.name || "");
|
|
861
|
+
if (extensionMatch?.[1]) {
|
|
862
|
+
return extensionMatch[1].toUpperCase();
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
if (typeof file.type === "string" && file.type.includes("/")) {
|
|
866
|
+
return file.type.split("/").at(-1)?.toUpperCase() || "File";
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
return "File";
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
function createFileExampleRow(file) {
|
|
873
|
+
const row = document.createElement("div");
|
|
874
|
+
const meta = document.createElement("div");
|
|
875
|
+
const name = document.createElement("p");
|
|
876
|
+
const detail = document.createElement("p");
|
|
877
|
+
const badge = document.createElement("span");
|
|
878
|
+
const actions = document.createElement("div");
|
|
879
|
+
const preview = document.createElement("a");
|
|
880
|
+
const remove = document.createElement("button");
|
|
881
|
+
const objectUrl = URL.createObjectURL(file);
|
|
882
|
+
|
|
883
|
+
row.className = "inc-file-row";
|
|
884
|
+
row._incFileExampleObjectUrl = objectUrl;
|
|
885
|
+
|
|
886
|
+
meta.className = "inc-file-row__meta";
|
|
887
|
+
name.className = "inc-file-row__name";
|
|
888
|
+
name.textContent = file.name || "untitled-file";
|
|
889
|
+
detail.className = "inc-file-row__detail";
|
|
890
|
+
detail.textContent = `${getFileExampleTypeLabel(file)} • ${formatFileExampleSize(file.size)} • selected just now`;
|
|
891
|
+
meta.append(name, detail);
|
|
892
|
+
|
|
893
|
+
badge.className = "inc-badge inc-badge--secondary inc-badge--pill";
|
|
894
|
+
badge.textContent = "Ready";
|
|
895
|
+
|
|
896
|
+
actions.className = "inc-file-row__actions";
|
|
897
|
+
|
|
898
|
+
preview.className = "inc-btn inc-btn--outline-secondary inc-btn--sm";
|
|
899
|
+
preview.href = objectUrl;
|
|
900
|
+
preview.target = "_blank";
|
|
901
|
+
preview.rel = "noreferrer";
|
|
902
|
+
preview.textContent = "Preview";
|
|
903
|
+
|
|
904
|
+
remove.type = "button";
|
|
905
|
+
remove.className = "inc-btn inc-btn--secondary inc-btn--sm";
|
|
906
|
+
remove.textContent = "Remove";
|
|
907
|
+
remove.setAttribute("data-inc-action", "file-remove");
|
|
908
|
+
remove.setAttribute("aria-label", `Remove ${file.name}`);
|
|
909
|
+
|
|
910
|
+
actions.append(preview, remove);
|
|
911
|
+
row.append(meta, badge, actions);
|
|
912
|
+
return row;
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
function revokeFileExampleRow(row) {
|
|
916
|
+
if (!(row instanceof HTMLElement)) {
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
|
|
920
|
+
if (typeof row._incFileExampleObjectUrl === "string" && row._incFileExampleObjectUrl) {
|
|
921
|
+
URL.revokeObjectURL(row._incFileExampleObjectUrl);
|
|
922
|
+
row._incFileExampleObjectUrl = "";
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
function updateFileExampleEmptyState(controller) {
|
|
927
|
+
const { list } = controller.parts;
|
|
928
|
+
if (!(list instanceof HTMLElement)) {
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
const rows = list.querySelectorAll(".inc-file-row");
|
|
933
|
+
let empty = list.querySelector("[data-inc-file-empty]");
|
|
934
|
+
|
|
935
|
+
if (rows.length > 0) {
|
|
936
|
+
if (empty instanceof HTMLElement) {
|
|
937
|
+
empty.hidden = true;
|
|
938
|
+
}
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
if (!(empty instanceof HTMLElement)) {
|
|
943
|
+
empty = document.createElement("p");
|
|
944
|
+
empty.className = "inc-text inc-text--small inc-text--muted";
|
|
945
|
+
empty.setAttribute("data-inc-file-empty", "");
|
|
946
|
+
empty.textContent = controller.emptyText;
|
|
947
|
+
list.append(empty);
|
|
948
|
+
}
|
|
949
|
+
|
|
950
|
+
empty.hidden = false;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
function appendFilesToExample(controller, files) {
|
|
954
|
+
const { list } = controller.parts;
|
|
955
|
+
if (!(list instanceof HTMLElement)) {
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
const fileItems = Array.from(files || []).filter((file) => file instanceof File);
|
|
960
|
+
if (!fileItems.length) {
|
|
961
|
+
return;
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
fileItems.forEach((file) => {
|
|
965
|
+
list.append(createFileExampleRow(file));
|
|
966
|
+
});
|
|
967
|
+
|
|
968
|
+
updateFileExampleEmptyState(controller);
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
function dataTransferIncludesFiles(dataTransfer) {
|
|
972
|
+
if (!dataTransfer) {
|
|
973
|
+
return false;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
if (dataTransfer.files?.length) {
|
|
977
|
+
return true;
|
|
978
|
+
}
|
|
979
|
+
|
|
980
|
+
return Array.from(dataTransfer.types || []).includes("Files");
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
function setFileDropzoneActiveState(controller, isActive) {
|
|
984
|
+
const { dropzone } = controller.parts;
|
|
985
|
+
if (!(dropzone instanceof HTMLElement)) {
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
988
|
+
|
|
989
|
+
dropzone.classList.toggle("is-drag-over", Boolean(isActive));
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
function openFileExamplePicker(controller) {
|
|
993
|
+
const { input } = controller.parts;
|
|
994
|
+
if (!(input instanceof HTMLInputElement)) {
|
|
995
|
+
return;
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
input.click();
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
function initializeFileExamples() {
|
|
1002
|
+
document.querySelectorAll(selectors.fileExample).forEach((root) => {
|
|
1003
|
+
if (!(root instanceof HTMLElement) || root._incFileExampleInitialized) {
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
const controller = {
|
|
1008
|
+
root,
|
|
1009
|
+
parts: {
|
|
1010
|
+
dropzone: root.querySelector(selectors.fileDropzone),
|
|
1011
|
+
input: root.querySelector(selectors.fileInput),
|
|
1012
|
+
browse: root.querySelector(selectors.fileBrowse),
|
|
1013
|
+
list: root.querySelector(selectors.fileList),
|
|
1014
|
+
},
|
|
1015
|
+
emptyText: root.getAttribute("data-inc-file-empty-text") || "No files selected yet.",
|
|
1016
|
+
dragDepth: 0,
|
|
1017
|
+
};
|
|
1018
|
+
|
|
1019
|
+
const { dropzone, input, browse, list } = controller.parts;
|
|
1020
|
+
if (!(dropzone instanceof HTMLElement) || !(input instanceof HTMLInputElement) || !(list instanceof HTMLElement)) {
|
|
1021
|
+
return;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
root._incFileExampleInitialized = true;
|
|
1025
|
+
root._incFileExampleController = controller;
|
|
1026
|
+
|
|
1027
|
+
dropzone.setAttribute("tabindex", dropzone.getAttribute("tabindex") || "0");
|
|
1028
|
+
dropzone.setAttribute("role", dropzone.getAttribute("role") || "button");
|
|
1029
|
+
dropzone.setAttribute("aria-label", dropzone.getAttribute("aria-label") || "Drop files here or browse for files");
|
|
1030
|
+
|
|
1031
|
+
const browseAction = (event) => {
|
|
1032
|
+
event.preventDefault();
|
|
1033
|
+
openFileExamplePicker(controller);
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
if (browse instanceof HTMLElement) {
|
|
1037
|
+
browse.addEventListener("click", browseAction);
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
dropzone.addEventListener("click", (event) => {
|
|
1041
|
+
if (event.target instanceof Element && event.target.closest("a, button, input, label")) {
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
openFileExamplePicker(controller);
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
dropzone.addEventListener("keydown", (event) => {
|
|
1049
|
+
if (event.key !== "Enter" && event.key !== " ") {
|
|
1050
|
+
return;
|
|
1051
|
+
}
|
|
1052
|
+
|
|
1053
|
+
event.preventDefault();
|
|
1054
|
+
openFileExamplePicker(controller);
|
|
1055
|
+
});
|
|
1056
|
+
|
|
1057
|
+
dropzone.addEventListener("dragenter", (event) => {
|
|
1058
|
+
if (!dataTransferIncludesFiles(event.dataTransfer)) {
|
|
1059
|
+
return;
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
event.preventDefault();
|
|
1063
|
+
controller.dragDepth += 1;
|
|
1064
|
+
setFileDropzoneActiveState(controller, true);
|
|
1065
|
+
});
|
|
1066
|
+
|
|
1067
|
+
dropzone.addEventListener("dragover", (event) => {
|
|
1068
|
+
if (!dataTransferIncludesFiles(event.dataTransfer)) {
|
|
1069
|
+
return;
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
event.preventDefault();
|
|
1073
|
+
if (event.dataTransfer) {
|
|
1074
|
+
event.dataTransfer.dropEffect = "copy";
|
|
1075
|
+
}
|
|
1076
|
+
setFileDropzoneActiveState(controller, true);
|
|
1077
|
+
});
|
|
1078
|
+
|
|
1079
|
+
dropzone.addEventListener("dragleave", (event) => {
|
|
1080
|
+
if (!dataTransferIncludesFiles(event.dataTransfer)) {
|
|
1081
|
+
return;
|
|
1082
|
+
}
|
|
1083
|
+
|
|
1084
|
+
event.preventDefault();
|
|
1085
|
+
controller.dragDepth = Math.max(0, controller.dragDepth - 1);
|
|
1086
|
+
|
|
1087
|
+
if (controller.dragDepth === 0 || !dropzone.contains(event.relatedTarget)) {
|
|
1088
|
+
setFileDropzoneActiveState(controller, false);
|
|
1089
|
+
}
|
|
1090
|
+
});
|
|
1091
|
+
|
|
1092
|
+
dropzone.addEventListener("drop", (event) => {
|
|
1093
|
+
if (!dataTransferIncludesFiles(event.dataTransfer)) {
|
|
1094
|
+
return;
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
event.preventDefault();
|
|
1098
|
+
controller.dragDepth = 0;
|
|
1099
|
+
setFileDropzoneActiveState(controller, false);
|
|
1100
|
+
appendFilesToExample(controller, event.dataTransfer?.files);
|
|
1101
|
+
});
|
|
1102
|
+
|
|
1103
|
+
input.addEventListener("change", () => {
|
|
1104
|
+
appendFilesToExample(controller, input.files);
|
|
1105
|
+
input.value = "";
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
list.addEventListener("click", (event) => {
|
|
1109
|
+
const removeButton = event.target.closest(selectors.fileRemove);
|
|
1110
|
+
if (!removeButton) {
|
|
1111
|
+
return;
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
event.preventDefault();
|
|
1115
|
+
const row = removeButton.closest(".inc-file-row");
|
|
1116
|
+
revokeFileExampleRow(row);
|
|
1117
|
+
row?.remove();
|
|
1118
|
+
updateFileExampleEmptyState(controller);
|
|
1119
|
+
});
|
|
1120
|
+
|
|
1121
|
+
updateFileExampleEmptyState(controller);
|
|
1122
|
+
});
|
|
1123
|
+
}
|
|
1124
|
+
|
|
827
1125
|
function formatAutoRefreshRemaining(totalSeconds) {
|
|
828
1126
|
if (totalSeconds < 60) {
|
|
829
1127
|
return `${totalSeconds}s`;
|
|
@@ -834,14 +1132,36 @@
|
|
|
834
1132
|
return `${minutes}m ${seconds}s`;
|
|
835
1133
|
}
|
|
836
1134
|
|
|
1135
|
+
const AUTO_REFRESH_PAUSE_ICON = `
|
|
1136
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
1137
|
+
<path d="M4 3h3v10H4zM9 3h3v10H9z"></path>
|
|
1138
|
+
</svg>`.trim();
|
|
1139
|
+
|
|
1140
|
+
const AUTO_REFRESH_PLAY_ICON = `
|
|
1141
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
|
|
1142
|
+
<path d="M4 3.5v9l8-4.5-8-4.5z"></path>
|
|
1143
|
+
</svg>`.trim();
|
|
1144
|
+
|
|
837
1145
|
function getAutoRefreshParts(root) {
|
|
1146
|
+
const toggle = root.querySelector(".inc-auto-refresh__toggle");
|
|
1147
|
+
|
|
1148
|
+
if (toggle instanceof HTMLElement) {
|
|
1149
|
+
if (!toggle.querySelector(".inc-auto-refresh__toggle-icon")) {
|
|
1150
|
+
const icon = document.createElement("span");
|
|
1151
|
+
icon.className = "inc-auto-refresh__toggle-icon";
|
|
1152
|
+
icon.setAttribute("aria-hidden", "true");
|
|
1153
|
+
toggle.prepend(icon);
|
|
1154
|
+
}
|
|
1155
|
+
}
|
|
1156
|
+
|
|
838
1157
|
return {
|
|
839
1158
|
countdown: root.querySelector(".inc-auto-refresh__countdown"),
|
|
840
1159
|
label: root.querySelector(".inc-auto-refresh__label"),
|
|
841
1160
|
value: root.querySelector(".inc-auto-refresh__value"),
|
|
842
1161
|
status: root.querySelector(".inc-auto-refresh__status"),
|
|
843
1162
|
statusText: root.querySelector(".inc-auto-refresh__status-text"),
|
|
844
|
-
toggle
|
|
1163
|
+
toggle,
|
|
1164
|
+
toggleIcon: root.querySelector(".inc-auto-refresh__toggle-icon"),
|
|
845
1165
|
toggleText: root.querySelector(".inc-auto-refresh__toggle-text"),
|
|
846
1166
|
};
|
|
847
1167
|
}
|
|
@@ -861,6 +1181,10 @@
|
|
|
861
1181
|
if (parts.toggleText) {
|
|
862
1182
|
parts.toggleText.textContent = actionLabel;
|
|
863
1183
|
}
|
|
1184
|
+
|
|
1185
|
+
if (parts.toggleIcon instanceof HTMLElement) {
|
|
1186
|
+
parts.toggleIcon.innerHTML = isPaused ? AUTO_REFRESH_PLAY_ICON : AUTO_REFRESH_PAUSE_ICON;
|
|
1187
|
+
}
|
|
864
1188
|
}
|
|
865
1189
|
|
|
866
1190
|
function renderAutoRefreshCountdown(controller, remainingSeconds) {
|
|
@@ -1524,6 +1848,7 @@
|
|
|
1524
1848
|
initializeMenus();
|
|
1525
1849
|
initializeCollapses();
|
|
1526
1850
|
initializeTabs();
|
|
1851
|
+
initializeFileExamples();
|
|
1527
1852
|
initializeAutoRefresh();
|
|
1528
1853
|
attachEventHandlers();
|
|
1529
1854
|
}
|