svelte-comp 1.3.3 → 1.3.5
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 +12 -11
- package/dist/App.svelte +540 -540
- package/dist/app.css +2 -3
- package/dist/app.d.ts +10 -0
- package/dist/lib/Accordion.svelte +14 -14
- package/dist/lib/Button.svelte +23 -8
- package/dist/lib/Card.svelte +6 -6
- package/dist/lib/Carousel.svelte +16 -16
- package/dist/lib/Carousel.svelte.d.ts +1 -1
- package/dist/lib/CheckBox.svelte +2 -2
- package/dist/lib/CodeView.svelte +6 -5
- package/dist/lib/ContextMenu.svelte +19 -13
- package/dist/lib/Dialog.svelte +3 -3
- package/dist/lib/Field.svelte +1 -1
- package/dist/lib/FilePicker.svelte +66 -11
- package/dist/lib/FilePicker.svelte.d.ts +6 -1
- package/dist/lib/Hamburger.svelte +12 -12
- package/dist/lib/Menu.svelte +18 -18
- package/dist/lib/NoticeBase.svelte +5 -5
- package/dist/lib/Select.svelte +2 -2
- package/dist/lib/Slider.svelte +1 -1
- package/dist/lib/Splitter.svelte +15 -6
- package/dist/lib/Switch.svelte +5 -4
- package/dist/lib/Tabs.svelte +6 -6
- package/dist/lib/ThemeToggle.svelte +1 -0
- package/dist/lib/TimePickerNew.svelte +634 -0
- package/dist/lib/TimePickerNew.svelte.d.ts +49 -0
- package/dist/lib/Tooltip.svelte +7 -7
- package/dist/lib/Topbar.svelte +6 -6
- package/dist/lib/__tests__/Accordion.test.d.ts +1 -0
- package/dist/lib/__tests__/Accordion.test.js +171 -0
- package/dist/lib/__tests__/Badge.test.d.ts +1 -0
- package/dist/lib/__tests__/Badge.test.js +41 -0
- package/dist/lib/__tests__/Button.test.d.ts +1 -0
- package/dist/lib/__tests__/Button.test.js +269 -0
- package/dist/lib/__tests__/Calendar.test.d.ts +1 -0
- package/dist/lib/__tests__/Calendar.test.js +171 -0
- package/dist/lib/__tests__/Card.test.d.ts +1 -0
- package/dist/lib/__tests__/Card.test.js +148 -0
- package/dist/lib/__tests__/Carousel.test.d.ts +1 -0
- package/dist/lib/__tests__/Carousel.test.js +439 -0
- package/dist/lib/__tests__/CheckBox.test.d.ts +1 -0
- package/dist/lib/__tests__/CheckBox.test.js +152 -0
- package/dist/lib/__tests__/CodeView.test.d.ts +1 -0
- package/dist/lib/__tests__/CodeView.test.js +157 -0
- package/dist/lib/__tests__/ColorPicker.test.d.ts +1 -0
- package/dist/lib/__tests__/ColorPicker.test.js +93 -0
- package/dist/lib/__tests__/ContextMenu.test.d.ts +1 -0
- package/dist/lib/__tests__/ContextMenu.test.js +67 -0
- package/dist/lib/__tests__/DatePicker.test.d.ts +1 -0
- package/dist/lib/__tests__/DatePicker.test.js +108 -0
- package/dist/lib/__tests__/Dialog.test.d.ts +1 -0
- package/dist/lib/__tests__/Dialog.test.js +183 -0
- package/dist/lib/__tests__/Field.test.d.ts +1 -0
- package/dist/lib/__tests__/Field.test.js +190 -0
- package/dist/lib/__tests__/FilePicker.test.d.ts +1 -0
- package/dist/lib/__tests__/FilePicker.test.js +179 -0
- package/dist/lib/__tests__/Form.integration.test.d.ts +1 -0
- package/dist/lib/__tests__/Form.integration.test.js +158 -0
- package/dist/lib/__tests__/Form.test.d.ts +1 -0
- package/dist/lib/__tests__/Form.test.js +463 -0
- package/dist/lib/__tests__/Hamburger.test.d.ts +1 -0
- package/dist/lib/__tests__/Hamburger.test.js +161 -0
- package/dist/lib/__tests__/InstallPWA.test.d.ts +1 -0
- package/dist/lib/__tests__/InstallPWA.test.js +15 -0
- package/dist/lib/__tests__/Menu.test.d.ts +1 -0
- package/dist/lib/__tests__/Menu.test.js +285 -0
- package/dist/lib/__tests__/NoticeBase.test.d.ts +1 -0
- package/dist/lib/__tests__/NoticeBase.test.js +60 -0
- package/dist/lib/__tests__/PaginatedCard.test.d.ts +1 -0
- package/dist/lib/__tests__/PaginatedCard.test.js +89 -0
- package/dist/lib/__tests__/Pagination.test.d.ts +1 -0
- package/dist/lib/__tests__/Pagination.test.js +168 -0
- package/dist/lib/__tests__/PrimaryColorSelect.test.d.ts +1 -0
- package/dist/lib/__tests__/PrimaryColorSelect.test.js +92 -0
- package/dist/lib/__tests__/ProgressBar.test.d.ts +1 -0
- package/dist/lib/__tests__/ProgressBar.test.js +69 -0
- package/dist/lib/__tests__/ProgressCircle.test.d.ts +1 -0
- package/dist/lib/__tests__/ProgressCircle.test.js +71 -0
- package/dist/lib/__tests__/Radio.test.d.ts +1 -0
- package/dist/lib/__tests__/Radio.test.js +127 -0
- package/dist/lib/__tests__/SearchInput.test.d.ts +1 -0
- package/dist/lib/__tests__/SearchInput.test.js +80 -0
- package/dist/lib/__tests__/Select.test.d.ts +1 -0
- package/dist/lib/__tests__/Select.test.js +408 -0
- package/dist/lib/__tests__/Slider.test.d.ts +1 -0
- package/dist/lib/__tests__/Slider.test.js +213 -0
- package/dist/lib/__tests__/Splitter.test.d.ts +1 -0
- package/dist/lib/__tests__/Splitter.test.js +87 -0
- package/dist/lib/__tests__/Switch.test.d.ts +1 -0
- package/dist/lib/__tests__/Switch.test.js +97 -0
- package/dist/lib/__tests__/Table.test.d.ts +1 -0
- package/dist/lib/__tests__/Table.test.js +349 -0
- package/dist/lib/__tests__/Tabs.test.d.ts +1 -0
- package/dist/lib/__tests__/Tabs.test.js +262 -0
- package/dist/lib/__tests__/ThemeToggle.test.d.ts +1 -0
- package/dist/lib/__tests__/ThemeToggle.test.js +84 -0
- package/dist/lib/__tests__/TimePicker.test.d.ts +1 -0
- package/dist/lib/__tests__/TimePicker.test.js +146 -0
- package/dist/lib/__tests__/TimePickerNew.test.d.ts +1 -0
- package/dist/lib/__tests__/TimePickerNew.test.js +322 -0
- package/dist/lib/__tests__/Toast.test.d.ts +1 -0
- package/dist/lib/__tests__/Toast.test.js +135 -0
- package/dist/lib/__tests__/Tooltip.test.d.ts +1 -0
- package/dist/lib/__tests__/Tooltip.test.js +171 -0
- package/dist/lib/__tests__/Topbar.test.d.ts +1 -0
- package/dist/lib/__tests__/Topbar.test.js +25 -0
- package/dist/lib/__tests__/setupLangContext.d.ts +1 -0
- package/dist/lib/__tests__/setupLangContext.js +65 -0
- package/dist/lib/__tests__/storage.test.d.ts +1 -0
- package/dist/lib/__tests__/storage.test.js +124 -0
- package/dist/lib/__tests__/utils.test.d.ts +1 -0
- package/dist/lib/__tests__/utils.test.js +11 -0
- package/dist/lib/index.d.ts +1 -0
- package/dist/lib/index.js +1 -0
- package/dist/lib/lang.d.ts +4 -0
- package/dist/lib/lang.js +4 -0
- package/dist/styles.css +2 -0
- package/dist/utils/index.js +15 -4
- package/package.json +12 -12
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
12
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
// src/__tests__/Field.test.ts
|
|
38
|
+
import { render, fireEvent } from "@testing-library/svelte";
|
|
39
|
+
import { describe, it, expect, vi } from "vitest";
|
|
40
|
+
import Field from "../Field.svelte";
|
|
41
|
+
describe("Field", function () {
|
|
42
|
+
it("renders with label and placeholder", function () {
|
|
43
|
+
var getByLabelText = render(Field, {
|
|
44
|
+
props: { label: "Email", placeholder: "user@example.com" },
|
|
45
|
+
}).getByLabelText;
|
|
46
|
+
expect(getByLabelText("Email").getAttribute("placeholder")).toBe("user@example.com");
|
|
47
|
+
});
|
|
48
|
+
it("binds value and triggers onChange", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
49
|
+
var handle, getByLabelText, input;
|
|
50
|
+
return __generator(this, function (_a) {
|
|
51
|
+
switch (_a.label) {
|
|
52
|
+
case 0:
|
|
53
|
+
handle = vi.fn();
|
|
54
|
+
getByLabelText = render(Field, {
|
|
55
|
+
props: { label: "Name", onChange: handle },
|
|
56
|
+
}).getByLabelText;
|
|
57
|
+
input = getByLabelText("Name");
|
|
58
|
+
return [4 /*yield*/, fireEvent.input(input, { target: { value: "Ada" } })];
|
|
59
|
+
case 1:
|
|
60
|
+
_a.sent();
|
|
61
|
+
expect(input.value).toBe("Ada");
|
|
62
|
+
expect(handle).toHaveBeenCalledWith("Ada");
|
|
63
|
+
return [2 /*return*/];
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}); });
|
|
67
|
+
it("renders textarea when as='textarea'", function () {
|
|
68
|
+
var container = render(Field, {
|
|
69
|
+
props: { as: "textarea", label: "Description" },
|
|
70
|
+
}).container;
|
|
71
|
+
expect(container.querySelector("textarea")).toBeTruthy();
|
|
72
|
+
});
|
|
73
|
+
it("shows clear button when clearable and has value", function () {
|
|
74
|
+
var getByTitle = render(Field, {
|
|
75
|
+
props: { label: "Search", value: "test", clearable: true },
|
|
76
|
+
}).getByTitle;
|
|
77
|
+
expect(getByTitle("Clear")).toBeTruthy();
|
|
78
|
+
});
|
|
79
|
+
it("hides clear button when clearable=false", function () {
|
|
80
|
+
var queryByTitle = render(Field, {
|
|
81
|
+
props: { label: "Search", value: "test", clearable: false },
|
|
82
|
+
}).queryByTitle;
|
|
83
|
+
expect(queryByTitle("Clear")).toBeNull();
|
|
84
|
+
});
|
|
85
|
+
it("hides clear button when value is empty", function () {
|
|
86
|
+
var queryByTitle = render(Field, {
|
|
87
|
+
props: { label: "Search", value: "", clearable: true },
|
|
88
|
+
}).queryByTitle;
|
|
89
|
+
expect(queryByTitle("Clear")).toBeNull();
|
|
90
|
+
});
|
|
91
|
+
it("clears value when clear button clicked", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
92
|
+
var handleChange, getByTitle;
|
|
93
|
+
return __generator(this, function (_a) {
|
|
94
|
+
switch (_a.label) {
|
|
95
|
+
case 0:
|
|
96
|
+
handleChange = vi.fn();
|
|
97
|
+
getByTitle = render(Field, {
|
|
98
|
+
props: {
|
|
99
|
+
label: "Search",
|
|
100
|
+
value: "test",
|
|
101
|
+
clearable: true,
|
|
102
|
+
onChange: handleChange,
|
|
103
|
+
},
|
|
104
|
+
}).getByTitle;
|
|
105
|
+
return [4 /*yield*/, fireEvent.click(getByTitle("Clear"))];
|
|
106
|
+
case 1:
|
|
107
|
+
_a.sent();
|
|
108
|
+
expect(handleChange).toHaveBeenCalledWith("");
|
|
109
|
+
return [2 /*return*/];
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
}); });
|
|
113
|
+
it("renders with leading icon", function () {
|
|
114
|
+
var container = render(Field, {
|
|
115
|
+
props: { label: "Search", leading: "🔍" },
|
|
116
|
+
}).container;
|
|
117
|
+
expect(container.querySelector(".left-2")).toBeTruthy();
|
|
118
|
+
});
|
|
119
|
+
it("renders with trailing icon", function () {
|
|
120
|
+
var container = render(Field, {
|
|
121
|
+
props: { label: "Search", trailing: "⌃" },
|
|
122
|
+
}).container;
|
|
123
|
+
expect(container.querySelector(".right-2")).toBeTruthy();
|
|
124
|
+
});
|
|
125
|
+
it("applies size classes", function () {
|
|
126
|
+
var container = render(Field, { props: { label: "Test", sz: "lg" } }).container;
|
|
127
|
+
var input = container.querySelector("input");
|
|
128
|
+
expect(input === null || input === void 0 ? void 0 : input.className).toContain("h-9");
|
|
129
|
+
});
|
|
130
|
+
it("applies variant classes", function () {
|
|
131
|
+
var container = render(Field, {
|
|
132
|
+
props: { label: "Test", variant: "filled" },
|
|
133
|
+
}).container;
|
|
134
|
+
var input = container.querySelector("input");
|
|
135
|
+
expect(input === null || input === void 0 ? void 0 : input.className).toContain("color-bg-muted");
|
|
136
|
+
});
|
|
137
|
+
it("parses number when parseNumber=true", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
138
|
+
var handleChange, getByLabelText, input;
|
|
139
|
+
return __generator(this, function (_a) {
|
|
140
|
+
switch (_a.label) {
|
|
141
|
+
case 0:
|
|
142
|
+
handleChange = vi.fn();
|
|
143
|
+
getByLabelText = render(Field, {
|
|
144
|
+
props: {
|
|
145
|
+
label: "Age",
|
|
146
|
+
type: "number",
|
|
147
|
+
parseNumber: true,
|
|
148
|
+
onChange: handleChange,
|
|
149
|
+
},
|
|
150
|
+
}).getByLabelText;
|
|
151
|
+
input = getByLabelText("Age");
|
|
152
|
+
return [4 /*yield*/, fireEvent.input(input, { target: { value: "25" } })];
|
|
153
|
+
case 1:
|
|
154
|
+
_a.sent();
|
|
155
|
+
expect(handleChange).toHaveBeenCalledWith(25);
|
|
156
|
+
return [2 /*return*/];
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
}); });
|
|
160
|
+
it("applies textarea rows prop", function () {
|
|
161
|
+
var _a;
|
|
162
|
+
var container = render(Field, {
|
|
163
|
+
props: { as: "textarea", label: "Description", rows: 5 },
|
|
164
|
+
}).container;
|
|
165
|
+
expect((_a = container.querySelector("textarea")) === null || _a === void 0 ? void 0 : _a.getAttribute("rows")).toBe("5");
|
|
166
|
+
});
|
|
167
|
+
it("applies custom class to wrapper", function () {
|
|
168
|
+
var container = render(Field, {
|
|
169
|
+
props: { label: "Test", class: "custom-field" },
|
|
170
|
+
}).container;
|
|
171
|
+
var wrapper = container.querySelector("label");
|
|
172
|
+
expect(wrapper === null || wrapper === void 0 ? void 0 : wrapper.className).toContain("custom-field");
|
|
173
|
+
});
|
|
174
|
+
it("generates unique id when not provided", function () {
|
|
175
|
+
var container = render(Field, { props: { label: "Test" } }).container;
|
|
176
|
+
var input = container.querySelector("input");
|
|
177
|
+
var label = container.querySelector("label");
|
|
178
|
+
expect(input === null || input === void 0 ? void 0 : input.id).toBeTruthy();
|
|
179
|
+
expect(label === null || label === void 0 ? void 0 : label.getAttribute("for")).toBe(input === null || input === void 0 ? void 0 : input.id);
|
|
180
|
+
});
|
|
181
|
+
it("uses provided id", function () {
|
|
182
|
+
var container = render(Field, {
|
|
183
|
+
props: { label: "Test", id: "custom-id" },
|
|
184
|
+
}).container;
|
|
185
|
+
var input = container.querySelector("input");
|
|
186
|
+
var label = container.querySelector("label");
|
|
187
|
+
expect(input === null || input === void 0 ? void 0 : input.id).toBe("custom-id");
|
|
188
|
+
expect(label === null || label === void 0 ? void 0 : label.getAttribute("for")).toBe("custom-id");
|
|
189
|
+
});
|
|
190
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "./setupLangContext";
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
12
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
// $lib/__tests__/FilePicker.test.ts
|
|
38
|
+
import "./setupLangContext";
|
|
39
|
+
import { fireEvent, render } from "@testing-library/svelte";
|
|
40
|
+
import { describe, it, expect, vi } from "vitest";
|
|
41
|
+
import FilePicker from "../FilePicker.svelte";
|
|
42
|
+
function createFile(name, type, content) {
|
|
43
|
+
if (type === void 0) { type = "text/plain"; }
|
|
44
|
+
if (content === void 0) { content = "content"; }
|
|
45
|
+
return new File([content], name, { type: type });
|
|
46
|
+
}
|
|
47
|
+
describe("FilePicker", function () {
|
|
48
|
+
var createFileList = function () {
|
|
49
|
+
var files = [];
|
|
50
|
+
for (var _i = 0; _i < arguments.length; _i++) {
|
|
51
|
+
files[_i] = arguments[_i];
|
|
52
|
+
}
|
|
53
|
+
var fileList = {
|
|
54
|
+
length: files.length,
|
|
55
|
+
item: function (index) {
|
|
56
|
+
var _a;
|
|
57
|
+
return (_a = files[index]) !== null && _a !== void 0 ? _a : null;
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
files.forEach(function (file, idx) {
|
|
61
|
+
fileList[idx] = file;
|
|
62
|
+
});
|
|
63
|
+
return fileList;
|
|
64
|
+
};
|
|
65
|
+
it("renders the default label", function () {
|
|
66
|
+
var getByText = render(FilePicker).getByText;
|
|
67
|
+
expect(getByText("Choose files")).toBeTruthy();
|
|
68
|
+
});
|
|
69
|
+
it("invokes onFilesSelected when using the hidden input", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
70
|
+
var handle, files, container, input;
|
|
71
|
+
return __generator(this, function (_a) {
|
|
72
|
+
switch (_a.label) {
|
|
73
|
+
case 0:
|
|
74
|
+
handle = vi.fn();
|
|
75
|
+
files = createFileList(createFile("example.txt"));
|
|
76
|
+
container = render(FilePicker, {
|
|
77
|
+
props: { onFilesSelected: handle },
|
|
78
|
+
}).container;
|
|
79
|
+
input = container.querySelector('input[type="file"]');
|
|
80
|
+
return [4 /*yield*/, fireEvent.change(input, { target: { files: files } })];
|
|
81
|
+
case 1:
|
|
82
|
+
_a.sent();
|
|
83
|
+
expect(handle).toHaveBeenCalledTimes(1);
|
|
84
|
+
expect(handle.mock.calls[0][0]).toHaveLength(1);
|
|
85
|
+
expect(input.value).toBe("");
|
|
86
|
+
return [2 /*return*/];
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}); });
|
|
90
|
+
it("supports drag and drop file selection", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
91
|
+
var handle, files, fakeDataTransfer, container, dropZone;
|
|
92
|
+
return __generator(this, function (_a) {
|
|
93
|
+
switch (_a.label) {
|
|
94
|
+
case 0:
|
|
95
|
+
handle = vi.fn();
|
|
96
|
+
files = createFileList(createFile("drag.txt"));
|
|
97
|
+
fakeDataTransfer = { files: files };
|
|
98
|
+
container = render(FilePicker, {
|
|
99
|
+
props: { onFilesSelected: handle },
|
|
100
|
+
}).container;
|
|
101
|
+
dropZone = container.querySelector('[role="button"]');
|
|
102
|
+
return [4 /*yield*/, fireEvent.drop(dropZone, { dataTransfer: fakeDataTransfer })];
|
|
103
|
+
case 1:
|
|
104
|
+
_a.sent();
|
|
105
|
+
expect(handle).toHaveBeenCalled();
|
|
106
|
+
return [2 /*return*/];
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
}); });
|
|
110
|
+
it("rejects dropped files that do not match accept", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
111
|
+
var handle, handleError, files, fakeDataTransfer, _a, container, getByText, dropZone;
|
|
112
|
+
return __generator(this, function (_b) {
|
|
113
|
+
switch (_b.label) {
|
|
114
|
+
case 0:
|
|
115
|
+
handle = vi.fn();
|
|
116
|
+
handleError = vi.fn();
|
|
117
|
+
files = createFileList(createFile("malware.exe", "application/x-msdownload"));
|
|
118
|
+
fakeDataTransfer = { files: files };
|
|
119
|
+
_a = render(FilePicker, {
|
|
120
|
+
props: {
|
|
121
|
+
accept: ".txt",
|
|
122
|
+
onFilesSelected: handle,
|
|
123
|
+
onError: handleError,
|
|
124
|
+
},
|
|
125
|
+
}), container = _a.container, getByText = _a.getByText;
|
|
126
|
+
dropZone = container.querySelector('[role="button"]');
|
|
127
|
+
return [4 /*yield*/, fireEvent.drop(dropZone, { dataTransfer: fakeDataTransfer })];
|
|
128
|
+
case 1:
|
|
129
|
+
_b.sent();
|
|
130
|
+
expect(handle).not.toHaveBeenCalled();
|
|
131
|
+
expect(handleError).toHaveBeenCalled();
|
|
132
|
+
expect(getByText("No files selected")).toBeTruthy();
|
|
133
|
+
return [2 /*return*/];
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
}); });
|
|
137
|
+
it("rejects files larger than maxBytes before callback", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
138
|
+
var handle, handleError, files, container, input;
|
|
139
|
+
return __generator(this, function (_a) {
|
|
140
|
+
switch (_a.label) {
|
|
141
|
+
case 0:
|
|
142
|
+
handle = vi.fn();
|
|
143
|
+
handleError = vi.fn();
|
|
144
|
+
files = createFileList(createFile("large.txt", "text/plain", "12345"));
|
|
145
|
+
container = render(FilePicker, {
|
|
146
|
+
props: {
|
|
147
|
+
maxBytes: 4,
|
|
148
|
+
onFilesSelected: handle,
|
|
149
|
+
onError: handleError,
|
|
150
|
+
},
|
|
151
|
+
}).container;
|
|
152
|
+
input = container.querySelector('input[type="file"]');
|
|
153
|
+
return [4 /*yield*/, fireEvent.change(input, { target: { files: files } })];
|
|
154
|
+
case 1:
|
|
155
|
+
_a.sent();
|
|
156
|
+
expect(handle).not.toHaveBeenCalled();
|
|
157
|
+
expect(handleError).toHaveBeenCalled();
|
|
158
|
+
return [2 /*return*/];
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
}); });
|
|
162
|
+
it("does not open picker when disabled", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
163
|
+
var container, button, input, clickSpy;
|
|
164
|
+
return __generator(this, function (_a) {
|
|
165
|
+
switch (_a.label) {
|
|
166
|
+
case 0:
|
|
167
|
+
container = render(FilePicker, { props: { disabled: true } }).container;
|
|
168
|
+
button = container.querySelector("button");
|
|
169
|
+
input = container.querySelector('input[type="file"]');
|
|
170
|
+
clickSpy = vi.spyOn(input, "click");
|
|
171
|
+
return [4 /*yield*/, fireEvent.click(button)];
|
|
172
|
+
case 1:
|
|
173
|
+
_a.sent();
|
|
174
|
+
expect(clickSpy).not.toHaveBeenCalled();
|
|
175
|
+
return [2 /*return*/];
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
}); });
|
|
179
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
11
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
12
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
13
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
14
|
+
function step(op) {
|
|
15
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
16
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
17
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
18
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
19
|
+
switch (op[0]) {
|
|
20
|
+
case 0: case 1: t = op; break;
|
|
21
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
22
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
23
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
24
|
+
default:
|
|
25
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
26
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
27
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
28
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
29
|
+
if (t[2]) _.ops.pop();
|
|
30
|
+
_.trys.pop(); continue;
|
|
31
|
+
}
|
|
32
|
+
op = body.call(thisArg, _);
|
|
33
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
34
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
// $lib/__tests__/Form.integration.test.ts
|
|
38
|
+
import { render, fireEvent } from "@testing-library/svelte";
|
|
39
|
+
import { describe, it, expect, vi } from "vitest";
|
|
40
|
+
import Form from "../Form.svelte";
|
|
41
|
+
describe("Form Integration", function () {
|
|
42
|
+
it("completes full form flow with validation and submission", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
43
|
+
var mockOnSubmit, schema, container, emailInput, passwordInput, checkbox, form;
|
|
44
|
+
return __generator(this, function (_a) {
|
|
45
|
+
switch (_a.label) {
|
|
46
|
+
case 0:
|
|
47
|
+
mockOnSubmit = vi.fn();
|
|
48
|
+
schema = [
|
|
49
|
+
{
|
|
50
|
+
name: "email",
|
|
51
|
+
type: "email",
|
|
52
|
+
label: "Email",
|
|
53
|
+
required: true,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
name: "password",
|
|
57
|
+
type: "password",
|
|
58
|
+
label: "Password",
|
|
59
|
+
required: true,
|
|
60
|
+
validators: [
|
|
61
|
+
function (v) {
|
|
62
|
+
return typeof v === "string" && v.length < 6 ? "Password too short" : null;
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "agree",
|
|
68
|
+
type: "checkbox",
|
|
69
|
+
label: "I agree to terms",
|
|
70
|
+
required: true,
|
|
71
|
+
},
|
|
72
|
+
];
|
|
73
|
+
container = render(Form, {
|
|
74
|
+
props: { schema: schema, onSubmit: mockOnSubmit },
|
|
75
|
+
}).container;
|
|
76
|
+
emailInput = container.querySelector('input[type="email"]');
|
|
77
|
+
passwordInput = container.querySelector('input[type="password"]');
|
|
78
|
+
checkbox = container.querySelector('input[type="checkbox"]');
|
|
79
|
+
return [4 /*yield*/, fireEvent.input(emailInput, {
|
|
80
|
+
target: { value: "valid@example.com" },
|
|
81
|
+
})];
|
|
82
|
+
case 1:
|
|
83
|
+
_a.sent();
|
|
84
|
+
return [4 /*yield*/, fireEvent.input(passwordInput, {
|
|
85
|
+
target: { value: "securepassword" },
|
|
86
|
+
})];
|
|
87
|
+
case 2:
|
|
88
|
+
_a.sent();
|
|
89
|
+
return [4 /*yield*/, fireEvent.click(checkbox)];
|
|
90
|
+
case 3:
|
|
91
|
+
_a.sent();
|
|
92
|
+
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 50); })];
|
|
93
|
+
case 4:
|
|
94
|
+
_a.sent();
|
|
95
|
+
form = container.querySelector("form");
|
|
96
|
+
return [4 /*yield*/, fireEvent.submit(form)];
|
|
97
|
+
case 5:
|
|
98
|
+
_a.sent();
|
|
99
|
+
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 100); })];
|
|
100
|
+
case 6:
|
|
101
|
+
_a.sent();
|
|
102
|
+
expect(mockOnSubmit).toHaveBeenCalledWith({
|
|
103
|
+
email: "valid@example.com",
|
|
104
|
+
password: "securepassword",
|
|
105
|
+
agree: true,
|
|
106
|
+
}, expect.any(Object));
|
|
107
|
+
return [2 /*return*/];
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}); });
|
|
111
|
+
it("handles dynamic field visibility correctly", function () { return __awaiter(void 0, void 0, void 0, function () {
|
|
112
|
+
var schema, _a, container, queryByText, checkbox;
|
|
113
|
+
return __generator(this, function (_b) {
|
|
114
|
+
switch (_b.label) {
|
|
115
|
+
case 0:
|
|
116
|
+
schema = [
|
|
117
|
+
{
|
|
118
|
+
name: "has_address",
|
|
119
|
+
type: "checkbox",
|
|
120
|
+
label: "Add address",
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
name: "address",
|
|
124
|
+
type: "text",
|
|
125
|
+
label: "Street Address",
|
|
126
|
+
when: function (form) { return form.has_address === true; },
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
name: "city",
|
|
130
|
+
type: "text",
|
|
131
|
+
label: "City",
|
|
132
|
+
when: function (form) { return form.has_address === true; },
|
|
133
|
+
},
|
|
134
|
+
];
|
|
135
|
+
_a = render(Form, {
|
|
136
|
+
props: { schema: schema },
|
|
137
|
+
}), container = _a.container, queryByText = _a.queryByText;
|
|
138
|
+
expect(queryByText("Street Address")).toBeNull();
|
|
139
|
+
expect(queryByText("City")).toBeNull();
|
|
140
|
+
checkbox = container.querySelector('input[type="checkbox"]');
|
|
141
|
+
return [4 /*yield*/, fireEvent.click(checkbox)];
|
|
142
|
+
case 1:
|
|
143
|
+
_b.sent();
|
|
144
|
+
expect(queryByText("Street Address")).toBeTruthy();
|
|
145
|
+
expect(queryByText("City")).toBeTruthy();
|
|
146
|
+
return [4 /*yield*/, fireEvent.click(checkbox)];
|
|
147
|
+
case 2:
|
|
148
|
+
_b.sent();
|
|
149
|
+
return [4 /*yield*/, new Promise(function (resolve) { return setTimeout(resolve, 0); })];
|
|
150
|
+
case 3:
|
|
151
|
+
_b.sent();
|
|
152
|
+
expect(queryByText("Street Address")).toBeNull();
|
|
153
|
+
expect(queryByText("City")).toBeNull();
|
|
154
|
+
return [2 /*return*/];
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}); });
|
|
158
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|