@bitforgehq/ui 0.4.0 → 0.5.0-next.4

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 (87) hide show
  1. package/CHANGELOG.md +350 -0
  2. package/README.md +12 -12
  3. package/ai/MANIFEST.index.json +74 -2
  4. package/ai/MANIFEST.json +3507 -1763
  5. package/ai/REFERENCE.index.json +189 -0
  6. package/ai/REFERENCE.json +1617 -139
  7. package/ai/UI_GUIDE.md +70 -20
  8. package/ai/components/app-frame.md +1 -1
  9. package/ai/components/badge.md +41 -1
  10. package/ai/components/chat-composer.md +357 -0
  11. package/ai/components/chat-message.md +251 -0
  12. package/ai/components/chat-thread.md +521 -0
  13. package/ai/components/checkbox.md +7 -0
  14. package/ai/components/combobox.md +12 -0
  15. package/ai/components/date-input.md +9 -0
  16. package/ai/components/datetime-input.md +2 -0
  17. package/ai/components/field.md +10 -0
  18. package/ai/components/file-input.md +498 -0
  19. package/ai/components/header.md +1 -1
  20. package/ai/components/image-input.md +368 -0
  21. package/ai/components/image-tile.md +452 -0
  22. package/ai/components/image-viewer.md +309 -0
  23. package/ai/components/media-card.md +478 -0
  24. package/ai/components/menu-button.md +67 -9
  25. package/ai/components/menu.md +10 -0
  26. package/ai/components/multi-combobox.md +7 -0
  27. package/ai/components/nav-group.md +10 -3
  28. package/ai/components/nav-item.md +11 -2
  29. package/ai/components/number-input.md +2 -7
  30. package/ai/components/pagination.md +59 -11
  31. package/ai/components/popover.md +13 -0
  32. package/ai/components/radio-group.md +6 -0
  33. package/ai/components/segmented.md +14 -2
  34. package/ai/components/select.md +100 -42
  35. package/ai/components/sidebar-toggle.md +16 -9
  36. package/ai/components/sidebar.md +41 -13
  37. package/ai/components/tab-group.md +18 -2
  38. package/ai/components/table.md +17 -2
  39. package/ai/components/theme-menu-button.md +1 -0
  40. package/ai/components/time-input.md +2 -0
  41. package/ai/components/toolbar.md +7 -18
  42. package/ai/reference/bf-chat-composer-harness.md +64 -0
  43. package/ai/reference/bf-chat-message-role.md +27 -0
  44. package/ai/reference/bf-chat-message-status.md +28 -0
  45. package/ai/reference/bf-fade-in-directive.md +18 -0
  46. package/ai/reference/bf-file-input-harness.md +67 -0
  47. package/ai/reference/bf-file-input-variant.md +27 -0
  48. package/ai/reference/bf-image-input-harness.md +67 -0
  49. package/ai/reference/bf-image-input-shape.md +27 -0
  50. package/ai/reference/bf-image-tile-aspect.md +28 -0
  51. package/ai/reference/bf-image-tile-caption-placement.md +27 -0
  52. package/ai/reference/bf-image-tile-harness.md +70 -0
  53. package/ai/reference/bf-image-viewer-actions-context.md +29 -0
  54. package/ai/reference/bf-image-viewer-harness.md +87 -0
  55. package/ai/reference/bf-image-viewer-image.md +25 -0
  56. package/ai/reference/bf-image-viewer-options.md +33 -0
  57. package/ai/reference/bf-image-viewer-origin.md +23 -0
  58. package/ai/reference/bf-image-viewer-ref.md +55 -0
  59. package/ai/reference/bf-image-viewer-service.md +32 -0
  60. package/ai/reference/bf-labels.md +107 -75
  61. package/ai/reference/bf-media-card-aspect.md +28 -0
  62. package/ai/reference/bf-media-card-harness.md +66 -0
  63. package/ai/reference/bf-motion-list-directive.md +22 -0
  64. package/ai/reference/bf-pagination-position-label.md +22 -0
  65. package/ai/reference/bf-prose-directive.md +16 -0
  66. package/ai/reference/bf-rejected-file-reason.md +28 -0
  67. package/ai/reference/bf-rejected-file.md +28 -0
  68. package/ai/reference/bf-select-harness.md +14 -5
  69. package/ai/reference/bf-select-option.md +2 -0
  70. package/ai/reference/bf-size.md +3 -0
  71. package/ai/reference/bf_table_sort_select.md +23 -0
  72. package/ai/reference/provide-bf-labels.md +11 -3
  73. package/ai/reference/provide-bf-select.md +20 -0
  74. package/bin/bf-ui.js +1 -0
  75. package/fesm2022/bitforgehq-ui-overlay.mjs +2660 -594
  76. package/fesm2022/bitforgehq-ui-overlay.mjs.map +1 -1
  77. package/fesm2022/bitforgehq-ui-testing.mjs +414 -10
  78. package/fesm2022/bitforgehq-ui-testing.mjs.map +1 -1
  79. package/fesm2022/bitforgehq-ui.mjs +8056 -3993
  80. package/fesm2022/bitforgehq-ui.mjs.map +1 -1
  81. package/llms-full.txt +4923 -132
  82. package/llms.txt +36 -1
  83. package/package.json +1 -1
  84. package/theme.css +60 -0
  85. package/types/bitforgehq-ui-overlay.d.ts +695 -7
  86. package/types/bitforgehq-ui-testing.d.ts +517 -6
  87. package/types/bitforgehq-ui.d.ts +1699 -181
@@ -110,29 +110,44 @@ function provideBfTesting(options = {}) {
110
110
  return makeEnvironmentProviders([...providers, ɵprovideBfDocumentReset()]);
111
111
  }
112
112
  var BfSelectHarness = class BfSelectHarness extends ComponentHarness {
113
- static hostSelector = "bf-select";
114
- select = this.locatorFor("select");
113
+ static hostSelector = "bf-select, [data-bf-select]";
114
+ nativeSelect = this.locatorForOptional("select");
115
+ combobox = this.locatorForOptional("[role=\"combobox\"]");
115
116
  label = this.locatorForOptional("label");
116
117
  error = this.locatorForOptional("p[id$=\"-error\"]");
117
118
  help = this.locatorForOptional("p[id$=\"-help\"]");
118
119
  nativeOptions = this.locatorForAll("option");
120
+ styledOptions = this.locatorForAll("[data-bf-select-options] > span");
119
121
  static with(filters = {}) {
120
122
  return new HarnessPredicate(BfSelectHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label));
121
123
  }
122
124
  async getLabel() {
123
125
  const label = await this.label();
124
126
  if (label) return (await label.text({ exclude: "[aria-hidden=\"true\"]" })).trim();
125
- return await (await this.select()).getAttribute("aria-label") ?? "";
127
+ return await (await this.control()).getAttribute("aria-label") ?? "";
128
+ }
129
+ async isOpen() {
130
+ if (await this.nativeSelect()) return false;
131
+ return await (await this.control()).getAttribute("aria-expanded") === "true";
126
132
  }
127
133
  async getValueLabel() {
134
+ if (!await this.nativeSelect()) {
135
+ const field = await this.control();
136
+ return await field.getAttribute("data-placeholder") !== null ? "" : (await field.text()).trim();
137
+ }
128
138
  for (const option of await this.options()) if (option.choice && await option.element.getProperty("selected")) return option.label;
129
139
  return "";
130
140
  }
131
141
  async getOptionLabels() {
142
+ if (!await this.nativeSelect()) return (await this.styledChoices()).map((option) => option.label);
132
143
  return (await this.options()).filter((option) => option.choice).map((option) => option.label);
133
144
  }
134
145
  async selectOption(label) {
135
146
  if (await this.isDisabled()) throw new Error(`BfSelectHarness: the select is disabled, so "${label}" cannot be chosen`);
147
+ if (!await this.nativeSelect()) {
148
+ await this.selectStyled(label);
149
+ return;
150
+ }
136
151
  const options = await this.options();
137
152
  const option = options.find((o) => o.choice && o.label === label);
138
153
  if (!option) {
@@ -140,18 +155,20 @@ var BfSelectHarness = class BfSelectHarness extends ComponentHarness {
140
155
  throw new Error(`BfSelectHarness: no option "${label}" (options: ${known.join(", ")})`);
141
156
  }
142
157
  if (await option.element.getProperty("disabled")) throw new Error(`BfSelectHarness: the option "${label}" is disabled`);
143
- const select = await this.select();
158
+ const select = await this.control();
144
159
  await select.setInputValue(await option.element.getProperty("value"));
145
160
  await select.dispatchEvent("change");
146
161
  }
147
162
  async isDisabled() {
148
- return (await this.select()).getProperty("disabled");
163
+ if (!await this.nativeSelect()) return await (await this.control()).getAttribute("aria-disabled") === "true";
164
+ return (await this.control()).getProperty("disabled");
149
165
  }
150
166
  async isReadonly() {
151
- return await (await this.select()).getAttribute("aria-readonly") === "true";
167
+ return await (await this.control()).getAttribute("aria-readonly") === "true";
152
168
  }
153
169
  async isRequired() {
154
- return (await this.select()).getProperty("required");
170
+ if (!await this.nativeSelect()) return await (await this.control()).getAttribute("aria-required") === "true";
171
+ return (await this.control()).getProperty("required");
155
172
  }
156
173
  async getErrorText() {
157
174
  return (await (await this.error())?.text())?.trim() ?? "";
@@ -160,10 +177,61 @@ var BfSelectHarness = class BfSelectHarness extends ComponentHarness {
160
177
  return (await (await this.help())?.text())?.trim() ?? "";
161
178
  }
162
179
  async focus() {
163
- await (await this.select()).focus();
180
+ await (await this.control()).focus();
164
181
  }
165
182
  async blur() {
166
- await (await this.select()).blur();
183
+ await (await this.control()).blur();
184
+ }
185
+ async control() {
186
+ const native = await this.nativeSelect();
187
+ if (native) return native;
188
+ const field = await this.combobox();
189
+ if (!field) throw new Error("BfSelectHarness: found neither a native select nor a combobox field");
190
+ return field;
191
+ }
192
+ async open() {
193
+ if (!await this.isOpen()) await (await this.control()).click();
194
+ }
195
+ async close() {
196
+ if (await this.isOpen()) await (await this.control()).sendKeys(TestKey.ESCAPE);
197
+ }
198
+ async listOptions() {
199
+ const id = await (await this.control()).getAttribute("aria-controls");
200
+ if (!id) return [];
201
+ const root = this.documentRootLocatorFactory();
202
+ const [elements, labels] = await Promise.all([root.locatorForAll(`[id="${id}"] [role="option"]`)(), root.locatorForAll(`[id="${id}"] [role="option"] [data-label]`)()]);
203
+ return Promise.all(elements.map(async (element, i) => ({
204
+ element,
205
+ label: (await (labels[i] ?? element).text()).trim()
206
+ })));
207
+ }
208
+ async styledChoices() {
209
+ return Promise.all((await this.styledOptions()).map(async (element) => {
210
+ const [label, disabled] = await Promise.all([element.text(), element.getAttribute("data-disabled")]);
211
+ return {
212
+ label: label.trim(),
213
+ disabled: disabled !== null
214
+ };
215
+ }));
216
+ }
217
+ async selectStyled(label) {
218
+ const choices = await this.styledChoices();
219
+ const choice = choices.find((o) => o.label === label);
220
+ if (!choice) {
221
+ const known = choices.map((o) => o.label);
222
+ throw new Error(`BfSelectHarness: no option "${label}" (options: ${known.join(", ")})`);
223
+ }
224
+ if (choice.disabled) throw new Error(`BfSelectHarness: the option "${label}" is disabled`);
225
+ if (await this.isReadonly()) return;
226
+ await this.open();
227
+ const option = (await this.listOptions()).find((o) => o.label === label);
228
+ if (!option) {
229
+ await this.close();
230
+ throw new Error(`BfSelectHarness: the open list has no option "${label}"`);
231
+ }
232
+ await option.element.click();
233
+ await new Promise((resolve) => setTimeout(resolve));
234
+ await this.forceStabilize();
167
235
  }
168
236
  async options() {
169
237
  return Promise.all((await this.nativeOptions()).map(async (element, index) => {
@@ -1083,6 +1151,342 @@ var BfToggleHarness = class BfToggleHarness extends ComponentHarness {
1083
1151
  return (await (await this.error())?.text())?.trim() ?? "";
1084
1152
  }
1085
1153
  };
1086
- export { BfCalendarHarness, BfChartHarness, BfComboboxHarness, BfDateInputHarness, BfDateTimeInputHarness, BfDesktopToastHarness, BfDialogHarness, BfMenuButtonHarness, BfMenuHarness, BfMenuItemHarness, BfPaginationHarness, BfPopoverHarness, BfRadioGroupHarness, BfSegmentedHarness, BfSelectHarness, BfSidePanelHarness, BfSidebarToggleHarness, BfTabGroupHarness, BfTableHarness, BfTimeInputHarness, BfToggleHarness, BfTooltipHarness, installBfJsdomShims, provideBfTesting };
1154
+ var BfFileInputHarness = class BfFileInputHarness extends ComponentHarness {
1155
+ static hostSelector = "bf-file-input";
1156
+ label = this.locatorForOptional("label");
1157
+ error = this.locatorForOptional("p[id$=\"-error\"]");
1158
+ box = this.locatorForOptional("[data-box]");
1159
+ pick = this.locatorForOptional("[data-pick]");
1160
+ ariaLabelText = this.locatorForOptional("[data-aria-label]");
1161
+ dropzone = this.locatorForOptional("[data-dropzone]");
1162
+ nativeInput = this.locatorFor("input[type=\"file\"]");
1163
+ names = this.locatorForAll("[data-file] [data-name]");
1164
+ removeButtons = this.locatorForAll("[data-file] button");
1165
+ rejectedNames = this.locatorForAll("[data-rejected] [data-rejected-name]");
1166
+ rejectedMessages = this.locatorForAll("[data-rejected] [data-rejected-message]");
1167
+ static with(filters = {}) {
1168
+ return new HarnessPredicate(BfFileInputHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label));
1169
+ }
1170
+ async getLabel() {
1171
+ const label = await this.label();
1172
+ if (label) return (await label.text({ exclude: "[aria-hidden=\"true\"]" })).trim();
1173
+ return (await (await this.ariaLabelText())?.text())?.trim() ?? "";
1174
+ }
1175
+ async getErrorText() {
1176
+ return (await (await this.error())?.text())?.trim() ?? "";
1177
+ }
1178
+ async getVariant() {
1179
+ return await this.dropzone() !== null || await this.box() === null ? "dropzone" : "field";
1180
+ }
1181
+ async isDisabled() {
1182
+ return (await this.nativeInput()).getProperty("disabled");
1183
+ }
1184
+ async isReadonly() {
1185
+ return await this.pick() === null;
1186
+ }
1187
+ async addFiles(files) {
1188
+ const target = await this.box();
1189
+ if (!target || await this.isDisabled() || await this.isReadonly()) return;
1190
+ const data = { dataTransfer: { files } };
1191
+ await target.dispatchEvent("drop", data);
1192
+ }
1193
+ async getFileNames() {
1194
+ return Promise.all((await this.names()).map(async (name) => (await name.text()).trim()));
1195
+ }
1196
+ async getRejected() {
1197
+ const [names, messages] = await Promise.all([this.rejectedNames(), this.rejectedMessages()]);
1198
+ return Promise.all(names.map(async (name, index) => ({
1199
+ name: (await name.text()).trim(),
1200
+ message: (await messages[index]?.text() ?? "").trim()
1201
+ })));
1202
+ }
1203
+ async removeFile(name) {
1204
+ const index = (await this.getFileNames()).indexOf(name);
1205
+ if (index < 0) throw new Error(`BfFileInputHarness: no chosen file is named "${name}"`);
1206
+ const button = (await this.removeButtons())[index];
1207
+ if (!button) throw new Error(`BfFileInputHarness: "${name}" cannot be removed from this field`);
1208
+ await button.click();
1209
+ }
1210
+ };
1211
+ var BfImageInputHarness = class BfImageInputHarness extends ComponentHarness {
1212
+ static hostSelector = "bf-image-input";
1213
+ label = this.locatorForOptional("label");
1214
+ error = this.locatorForOptional("p[id$=\"-error\"]");
1215
+ tile = this.locatorFor("[data-tile]");
1216
+ preview = this.locatorForOptional("[data-tile] img");
1217
+ removeButton = this.locatorForOptional("[data-remove]");
1218
+ rejection = this.locatorForOptional("[data-rejection]");
1219
+ nativeInput = this.locatorFor("input[type=\"file\"]");
1220
+ static with(filters = {}) {
1221
+ return new HarnessPredicate(BfImageInputHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label));
1222
+ }
1223
+ async getLabel() {
1224
+ const label = await this.label();
1225
+ if (label) return (await label.text({ exclude: "[aria-hidden=\"true\"]" })).trim();
1226
+ return await (await this.tile()).getAttribute("aria-label") ?? "";
1227
+ }
1228
+ async getErrorText() {
1229
+ return (await (await this.error())?.text())?.trim() ?? "";
1230
+ }
1231
+ async isDisabled() {
1232
+ return (await this.nativeInput()).getProperty("disabled");
1233
+ }
1234
+ async isReadonly() {
1235
+ return await (await this.tile()).getProperty("tagName") !== "BUTTON";
1236
+ }
1237
+ async hasPreview() {
1238
+ return await this.preview() !== null;
1239
+ }
1240
+ async getPreviewSrc() {
1241
+ return (await this.preview())?.getAttribute("src") ?? null;
1242
+ }
1243
+ async addFile(file) {
1244
+ if (await this.isDisabled() || await this.isReadonly()) return;
1245
+ const data = { dataTransfer: { files: [file] } };
1246
+ await (await this.tile()).dispatchEvent("drop", data);
1247
+ }
1248
+ async remove() {
1249
+ const button = await this.removeButton();
1250
+ if (!button) throw new Error("BfImageInputHarness: there is no Remove button, so nothing can be removed");
1251
+ await button.click();
1252
+ }
1253
+ async getRejectedMessage() {
1254
+ return (await (await this.rejection())?.text())?.trim() ?? "";
1255
+ }
1256
+ };
1257
+ var BfMediaCardHarness = class BfMediaCardHarness extends ComponentHarness {
1258
+ static hostSelector = "bf-media-card";
1259
+ media = this.locatorFor("[data-media]");
1260
+ image = this.locatorForOptional("[data-media] img");
1261
+ heading = this.locatorForOptional("[data-body] h1, [data-body] h2, [data-body] h3, [data-body] h4, [data-body] h5, [data-body] h6");
1262
+ loadingLabel = this.locatorForOptional("[data-loading-label]");
1263
+ failedLabel = this.locatorForOptional("[data-failed-label]");
1264
+ selectButton = this.locatorForOptional("button[data-select]");
1265
+ static with(filters = {}) {
1266
+ return new HarnessPredicate(BfMediaCardHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getTitle(), label));
1267
+ }
1268
+ async getTitle() {
1269
+ return (await (await this.heading())?.text())?.trim() ?? "";
1270
+ }
1271
+ async getState() {
1272
+ const state = await (await this.media()).getAttribute("data-state");
1273
+ return state === "loading" || state === "loaded" || state === "failed" ? state : "empty";
1274
+ }
1275
+ async getSrc() {
1276
+ return await (await this.image())?.getAttribute("src") ?? "";
1277
+ }
1278
+ async getAlt() {
1279
+ return await (await this.image())?.getAttribute("alt") ?? "";
1280
+ }
1281
+ async getLoadingLabel() {
1282
+ return (await (await this.loadingLabel())?.text())?.trim() ?? "";
1283
+ }
1284
+ async getFailedMessage() {
1285
+ return (await (await this.failedLabel())?.text())?.trim() ?? "";
1286
+ }
1287
+ async loadImage() {
1288
+ await (await this.requireImage()).dispatchEvent("load");
1289
+ }
1290
+ async failImage() {
1291
+ await (await this.requireImage()).dispatchEvent("error");
1292
+ }
1293
+ async isSelectable() {
1294
+ return await this.selectButton() !== null;
1295
+ }
1296
+ async isSelected() {
1297
+ return await (await this.selectButton())?.getAttribute("aria-pressed") === "true";
1298
+ }
1299
+ async toggleSelected() {
1300
+ const button = await this.selectButton();
1301
+ if (!button) throw new Error("BfMediaCardHarness: the card is not selectable");
1302
+ await button.click();
1303
+ }
1304
+ async requireImage() {
1305
+ const image = await this.image();
1306
+ if (!image) throw new Error("BfMediaCardHarness: the card shows no image (no src, or it failed)");
1307
+ return image;
1308
+ }
1309
+ };
1310
+ var BfImageTileHarness = class BfImageTileHarness extends ComponentHarness {
1311
+ static hostSelector = "bf-image-tile";
1312
+ tile = this.locatorFor("bf-image-tile > div");
1313
+ media = this.locatorFor("[data-media]");
1314
+ image = this.locatorForOptional("[data-media] img");
1315
+ title = this.locatorFor("[data-title]");
1316
+ meta = this.locatorFor("[data-meta]");
1317
+ placeholder = this.locatorForOptional("[data-placeholder]");
1318
+ failed = this.locatorForOptional("[data-failed]");
1319
+ action = this.locatorForOptional("[data-title] [data-bf-action]");
1320
+ static with(filters = {}) {
1321
+ return new HarnessPredicate(BfImageTileHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getTitle(), label));
1322
+ }
1323
+ async getTitle() {
1324
+ return (await (await this.title()).text()).trim();
1325
+ }
1326
+ async getMeta() {
1327
+ return (await (await this.meta()).text()).trim();
1328
+ }
1329
+ async getState() {
1330
+ const state = await (await this.media()).getAttribute("data-state");
1331
+ return state === "loading" || state === "loaded" || state === "failed" ? state : "empty";
1332
+ }
1333
+ async getSrc() {
1334
+ return await (await this.image())?.getAttribute("src") ?? "";
1335
+ }
1336
+ async getAlt() {
1337
+ return await (await this.image())?.getAttribute("alt") ?? "";
1338
+ }
1339
+ async getPlaceholderText() {
1340
+ return (await (await this.placeholder())?.text())?.trim() ?? "";
1341
+ }
1342
+ async getFailedMessage() {
1343
+ return (await (await this.failed())?.text())?.trim() ?? "";
1344
+ }
1345
+ async isSelected() {
1346
+ return await (await this.tile()).getAttribute("data-selected") !== null;
1347
+ }
1348
+ async isClickable() {
1349
+ return await this.action() !== null;
1350
+ }
1351
+ async click() {
1352
+ const action = await this.action();
1353
+ if (!action) throw new Error("BfImageTileHarness: the tile has no bfAction link or button");
1354
+ await action.click();
1355
+ }
1356
+ async loadImage() {
1357
+ await (await this.requireImage()).dispatchEvent("load");
1358
+ }
1359
+ async failImage() {
1360
+ await (await this.requireImage()).dispatchEvent("error");
1361
+ }
1362
+ async requireImage() {
1363
+ const image = await this.image();
1364
+ if (!image) throw new Error("BfImageTileHarness: the tile shows no picture (no src, or it failed)");
1365
+ return image;
1366
+ }
1367
+ };
1368
+ var BfImageViewerHarness = class BfImageViewerHarness extends ComponentHarness {
1369
+ static hostSelector = "bf-image-viewer";
1370
+ image = this.locatorForOptional("img[data-image]");
1371
+ frame = this.locatorFor("[data-frame]");
1372
+ caption = this.locatorForOptional("[data-caption]");
1373
+ counter = this.locatorFor("[data-counter]");
1374
+ closeButton = this.locatorFor("[data-close] button");
1375
+ nextButton = this.locatorForOptional("[data-next] button");
1376
+ previousButton = this.locatorForOptional("[data-previous] button");
1377
+ static with(filters = {}) {
1378
+ return new HarnessPredicate(BfImageViewerHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label));
1379
+ }
1380
+ async getLabel() {
1381
+ return await (await this.host()).getAttribute("data-label") ?? "";
1382
+ }
1383
+ async getIndex() {
1384
+ return Number(await (await this.host()).getAttribute("data-index"));
1385
+ }
1386
+ async getCount() {
1387
+ return Number(await (await this.host()).getAttribute("data-count"));
1388
+ }
1389
+ async getCounterText() {
1390
+ return await this.getCount() < 2 ? "" : (await (await this.counter()).text()).trim();
1391
+ }
1392
+ async getSrc() {
1393
+ return await (await this.image())?.getAttribute("src") ?? "";
1394
+ }
1395
+ async getAlt() {
1396
+ return await (await this.image())?.getAttribute("alt") ?? "";
1397
+ }
1398
+ async getCaption() {
1399
+ return (await (await this.caption())?.text())?.trim() ?? "";
1400
+ }
1401
+ async isLoaded() {
1402
+ return await (await this.frame()).getAttribute("data-status") === "loaded";
1403
+ }
1404
+ async hasFailed() {
1405
+ return await (await this.frame()).getAttribute("data-status") === "error";
1406
+ }
1407
+ async loadImage() {
1408
+ await (await this.requireImage()).dispatchEvent("load");
1409
+ }
1410
+ async failImage() {
1411
+ await (await this.requireImage()).dispatchEvent("error");
1412
+ }
1413
+ async next() {
1414
+ const button = await this.nextButton();
1415
+ if (!button) throw new Error("BfImageViewerHarness: a viewer of one image has no next button");
1416
+ await button.click();
1417
+ }
1418
+ async previous() {
1419
+ const button = await this.previousButton();
1420
+ if (!button) throw new Error("BfImageViewerHarness: a viewer of one image has no previous button");
1421
+ await button.click();
1422
+ }
1423
+ async pressKey(key) {
1424
+ const keys = {
1425
+ ArrowLeft: TestKey.LEFT_ARROW,
1426
+ ArrowRight: TestKey.RIGHT_ARROW,
1427
+ Home: TestKey.HOME,
1428
+ End: TestKey.END,
1429
+ Escape: TestKey.ESCAPE
1430
+ };
1431
+ await (await this.closeButton()).sendKeys(keys[key]);
1432
+ }
1433
+ async close() {
1434
+ await (await this.closeButton()).click();
1435
+ }
1436
+ async requireImage() {
1437
+ const image = await this.image();
1438
+ if (!image) throw new Error("BfImageViewerHarness: the viewer shows no image (it failed to load)");
1439
+ return image;
1440
+ }
1441
+ };
1442
+ var BfChatComposerHarness = class BfChatComposerHarness extends ComponentHarness {
1443
+ static hostSelector = "bf-chat-composer";
1444
+ textarea = this.locatorFor("textarea");
1445
+ label = this.locatorForOptional("label");
1446
+ button = this.locatorFor("button[data-action]");
1447
+ static with(filters = {}) {
1448
+ return new HarnessPredicate(BfChatComposerHarness, filters).addOption("label", filters.label, async (harness, label) => HarnessPredicate.stringMatches(harness.getLabel(), label));
1449
+ }
1450
+ async getLabel() {
1451
+ const label = await this.label();
1452
+ return (label ? (await label.text()).trim() : "") || (await (await this.textarea()).getAttribute("aria-label") ?? "");
1453
+ }
1454
+ async getValue() {
1455
+ return (await this.textarea()).getProperty("value");
1456
+ }
1457
+ async setValue(text) {
1458
+ const textarea = await this.textarea();
1459
+ await textarea.clear();
1460
+ if (text) {
1461
+ await textarea.setInputValue(text);
1462
+ await textarea.dispatchEvent("input");
1463
+ }
1464
+ }
1465
+ async send() {
1466
+ if (await this.isRunning() || !await this.canAct()) return;
1467
+ await (await this.button()).click();
1468
+ }
1469
+ async pressEnter() {
1470
+ await (await this.textarea()).sendKeys(TestKey.ENTER);
1471
+ }
1472
+ async stop() {
1473
+ if (!await this.isRunning() || !await this.canAct()) return;
1474
+ await (await this.button()).click();
1475
+ }
1476
+ async isRunning() {
1477
+ return await (await this.button()).getAttribute("data-mode") === "stop";
1478
+ }
1479
+ async isDisabled() {
1480
+ return (await this.textarea()).getProperty("disabled");
1481
+ }
1482
+ async canAct() {
1483
+ const button = await this.button();
1484
+ return !await button.getProperty("disabled") && await button.getAttribute("aria-disabled") !== "true";
1485
+ }
1486
+ async getButtonLabel() {
1487
+ return (await (await this.button()).text()).trim();
1488
+ }
1489
+ };
1490
+ export { BfCalendarHarness, BfChartHarness, BfChatComposerHarness, BfComboboxHarness, BfDateInputHarness, BfDateTimeInputHarness, BfDesktopToastHarness, BfDialogHarness, BfFileInputHarness, BfImageInputHarness, BfImageTileHarness, BfImageViewerHarness, BfMediaCardHarness, BfMenuButtonHarness, BfMenuHarness, BfMenuItemHarness, BfPaginationHarness, BfPopoverHarness, BfRadioGroupHarness, BfSegmentedHarness, BfSelectHarness, BfSidePanelHarness, BfSidebarToggleHarness, BfTabGroupHarness, BfTableHarness, BfTimeInputHarness, BfToggleHarness, BfTooltipHarness, installBfJsdomShims, provideBfTesting };
1087
1491
 
1088
1492
  //# sourceMappingURL=bitforgehq-ui-testing.mjs.map