@searchcraft/javascript-sdk 0.12.0 → 0.12.2
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 +1 -1
- package/dist/components/index.d.ts +22 -0
- package/dist/components/index.js +136 -17
- package/dist/components/index.js.map +1 -1
- package/dist/components/{p-b7e99386.js → p-870f81fd.js} +38 -6
- package/dist/components/p-870f81fd.js.map +1 -0
- package/dist/components/{p-0c495408.js → p-e8d97093.js} +110 -37
- package/dist/components/p-e8d97093.js.map +1 -0
- package/dist/components/searchcraft-facet-list.js +1 -1
- package/dist/components/searchcraft-filter-panel.js +3 -3
- package/dist/components/searchcraft-filter-panel.js.map +1 -1
- package/dist/components/searchcraft-input-form.js +1 -1
- package/dist/components/searchcraft-pagination.js +8 -2
- package/dist/components/searchcraft-pagination.js.map +1 -1
- package/dist/components/searchcraft-popover-form.js +1 -1
- package/dist/components/searchcraft-results-info.js +9 -1
- package/dist/components/searchcraft-results-info.js.map +1 -1
- package/dist/components/searchcraft-search-results-per-page.js +8 -2
- package/dist/components/searchcraft-search-results-per-page.js.map +1 -1
- package/dist/hydrate/index.js +229 -105
- package/dist/hydrate/index.mjs +229 -105
- package/dist/types/classes/SearchcraftCore.d.ts +1 -1
- package/dist/types/components/searchcraft-facet-list/searchcraft-facet-list.d.ts +5 -1
- package/dist/types/components/searchcraft-filter-panel/searchcraft-filter-panel.d.ts +1 -1
- package/dist/types/components/searchcraft-input-form/searchcraft-input-form.d.ts +5 -0
- package/dist/types/components/searchcraft-pagination/searchcraft-pagination.d.ts +1 -0
- package/dist/types/components/searchcraft-results-info/searchcraft-results-info.d.ts +1 -0
- package/dist/types/components/searchcraft-search-results-per-page/searchcraft-search-results-per-page.d.ts +1 -0
- package/dist/types/components.d.ts +16 -0
- package/dist/types/store/SearchcraftStore.types.d.ts +6 -1
- package/dist/types/types/sdk-types/searchcraft-filter-panel.types.d.ts +1 -0
- package/dist/types/utils/facets.d.ts +5 -1
- package/package.json +4 -3
- package/dist/components/p-0c495408.js.map +0 -1
- package/dist/components/p-b7e99386.js.map +0 -1
package/dist/hydrate/index.mjs
CHANGED
|
@@ -2555,6 +2555,65 @@ class SearchcraftErrorMessage {
|
|
|
2555
2555
|
}; }
|
|
2556
2556
|
}
|
|
2557
2557
|
|
|
2558
|
+
/**
|
|
2559
|
+
* This is the default instance id for searchcraft core instances.
|
|
2560
|
+
* When no id is specified in a component's props, use this one.
|
|
2561
|
+
*/
|
|
2562
|
+
const DEFAULT_CORE_INSTANCE_ID = 'searchcraft';
|
|
2563
|
+
/**
|
|
2564
|
+
* CoreInstanceRegistry
|
|
2565
|
+
*
|
|
2566
|
+
* This class is responsible for managing all of the instances of SearchcraftCore on a page.
|
|
2567
|
+
* It provides a means for consuming components to use the instance of SearchcraftCore that
|
|
2568
|
+
* they need to use when that instance of core gets added to the Registry.
|
|
2569
|
+
*/
|
|
2570
|
+
class CoreInstanceRegistry {
|
|
2571
|
+
coreInstances = {};
|
|
2572
|
+
subscriptions = {};
|
|
2573
|
+
/**
|
|
2574
|
+
* Adds a SearchcraftCore instance to the Registry.
|
|
2575
|
+
*
|
|
2576
|
+
* When the instance is added, iterates through the onAvailable callbacks
|
|
2577
|
+
* that have been subscribed via useCoreInstance.
|
|
2578
|
+
*
|
|
2579
|
+
* @param coreInstance The SearchcraftCore instance to add to the registry
|
|
2580
|
+
* @param searchcraftId The unique identifier for this SearchcraftCore instance.
|
|
2581
|
+
*/
|
|
2582
|
+
addCoreInstance(coreInstance, searchcraftId) {
|
|
2583
|
+
const id = searchcraftId || DEFAULT_CORE_INSTANCE_ID;
|
|
2584
|
+
this.coreInstances[id] = coreInstance;
|
|
2585
|
+
for (const callback of this.subscriptions[id] || []) {
|
|
2586
|
+
callback(coreInstance);
|
|
2587
|
+
}
|
|
2588
|
+
}
|
|
2589
|
+
/**
|
|
2590
|
+
* Use the specified instance of SearchcraftCore. When the instance becomes available,
|
|
2591
|
+
* the onAvailable callback will be called.
|
|
2592
|
+
*
|
|
2593
|
+
* @param searchcraftId The SearchcraftCore instance to use.
|
|
2594
|
+
* @param onAvailable The callback that gets called when the core instance becomes available.
|
|
2595
|
+
*/
|
|
2596
|
+
useCoreInstance(searchcraftId, onAvailable) {
|
|
2597
|
+
const id = searchcraftId || DEFAULT_CORE_INSTANCE_ID;
|
|
2598
|
+
// If the core instance already is available, call the onAvailable callback immediately.
|
|
2599
|
+
if (this.coreInstances[id]) {
|
|
2600
|
+
onAvailable(this.coreInstances[id]);
|
|
2601
|
+
return () => { };
|
|
2602
|
+
}
|
|
2603
|
+
// Add the callback to the collection of callbacks for this searchcraft instance.
|
|
2604
|
+
if (!this.subscriptions[id]) {
|
|
2605
|
+
this.subscriptions[id] = [];
|
|
2606
|
+
}
|
|
2607
|
+
this.subscriptions[id].push(onAvailable);
|
|
2608
|
+
return () => {
|
|
2609
|
+
if (this.subscriptions[id]) {
|
|
2610
|
+
this.subscriptions[id] = this.subscriptions[id].filter((cb) => cb !== onAvailable);
|
|
2611
|
+
}
|
|
2612
|
+
};
|
|
2613
|
+
}
|
|
2614
|
+
}
|
|
2615
|
+
const registry = new CoreInstanceRegistry();
|
|
2616
|
+
|
|
2558
2617
|
/**
|
|
2559
2618
|
* Helper function for getting a Node (FacetWithChildrenObject)
|
|
2560
2619
|
* at a given path. Traverses the node tree to get the node.
|
|
@@ -2629,8 +2688,12 @@ const mergeFacetTrees = (currentTree, incomingTree) => {
|
|
|
2629
2688
|
* It uses the `path` of each Facet to build the tree.
|
|
2630
2689
|
*
|
|
2631
2690
|
* @param facetWithChildArray
|
|
2691
|
+
* @param exclude - Optional array of facet values or paths to exclude from the tree.
|
|
2692
|
+
* - Values starting with "/" are treated as full paths and exclude the path and all children
|
|
2693
|
+
* (e.g., "/news" excludes "/news", "/news/local", "/news/national", etc.)
|
|
2694
|
+
* - Values without "/" are treated as segment names (e.g., "local" excludes all paths containing "local")
|
|
2632
2695
|
*/
|
|
2633
|
-
const facetWithChildrenArrayToCompleteFacetTree = (rootArray) => {
|
|
2696
|
+
const facetWithChildrenArrayToCompleteFacetTree = (rootArray, exclude) => {
|
|
2634
2697
|
// 1) Start with an empty tree at root "/"
|
|
2635
2698
|
const tree = {
|
|
2636
2699
|
path: '/',
|
|
@@ -2653,6 +2716,29 @@ const facetWithChildrenArrayToCompleteFacetTree = (rootArray) => {
|
|
|
2653
2716
|
// 3) Insert each flat node into our tree, creating missing ancestors
|
|
2654
2717
|
for (const { path, count } of allFacets) {
|
|
2655
2718
|
const segments = path.split('/').filter(Boolean); // "/sports/outdoors" -> ["sports","outdoors"]
|
|
2719
|
+
// Skip this facet if it matches any excluded value
|
|
2720
|
+
if (exclude && exclude.length > 0) {
|
|
2721
|
+
let shouldExclude = false;
|
|
2722
|
+
for (const excludeValue of exclude) {
|
|
2723
|
+
if (excludeValue.startsWith('/')) {
|
|
2724
|
+
// Full path exclusion: prefix match (excludes the path and all children)
|
|
2725
|
+
if (path === excludeValue || path.startsWith(`${excludeValue}/`)) {
|
|
2726
|
+
shouldExclude = true;
|
|
2727
|
+
break;
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
else {
|
|
2731
|
+
// Segment exclusion: check if any segment matches
|
|
2732
|
+
if (segments.includes(excludeValue)) {
|
|
2733
|
+
shouldExclude = true;
|
|
2734
|
+
break;
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
if (shouldExclude) {
|
|
2739
|
+
continue;
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2656
2742
|
let cursor = tree; // start at the root
|
|
2657
2743
|
for (const segment of segments) {
|
|
2658
2744
|
// Build the full path of this level
|
|
@@ -4215,65 +4301,6 @@ const html = (strings, ...values) => {
|
|
|
4215
4301
|
return result || '';
|
|
4216
4302
|
};
|
|
4217
4303
|
|
|
4218
|
-
/**
|
|
4219
|
-
* This is the default instance id for searchcraft core instances.
|
|
4220
|
-
* When no id is specified in a component's props, use this one.
|
|
4221
|
-
*/
|
|
4222
|
-
const DEFAULT_CORE_INSTANCE_ID = 'searchcraft';
|
|
4223
|
-
/**
|
|
4224
|
-
* CoreInstanceRegistry
|
|
4225
|
-
*
|
|
4226
|
-
* This class is responsible for managing all of the instances of SearchcraftCore on a page.
|
|
4227
|
-
* It provides a means for consuming components to use the instance of SearchcraftCore that
|
|
4228
|
-
* they need to use when that instance of core gets added to the Registry.
|
|
4229
|
-
*/
|
|
4230
|
-
class CoreInstanceRegistry {
|
|
4231
|
-
coreInstances = {};
|
|
4232
|
-
subscriptions = {};
|
|
4233
|
-
/**
|
|
4234
|
-
* Adds a SearchcraftCore instance to the Registry.
|
|
4235
|
-
*
|
|
4236
|
-
* When the instance is added, iterates through the onAvailable callbacks
|
|
4237
|
-
* that have been subscribed via useCoreInstance.
|
|
4238
|
-
*
|
|
4239
|
-
* @param coreInstance The SearchcraftCore instance to add to the registry
|
|
4240
|
-
* @param searchcraftId The unique identifier for this SearchcraftCore instance.
|
|
4241
|
-
*/
|
|
4242
|
-
addCoreInstance(coreInstance, searchcraftId) {
|
|
4243
|
-
const id = searchcraftId || DEFAULT_CORE_INSTANCE_ID;
|
|
4244
|
-
this.coreInstances[id] = coreInstance;
|
|
4245
|
-
for (const callback of this.subscriptions[id] || []) {
|
|
4246
|
-
callback(coreInstance);
|
|
4247
|
-
}
|
|
4248
|
-
}
|
|
4249
|
-
/**
|
|
4250
|
-
* Use the specified instance of SearchcraftCore. When the instance becomes available,
|
|
4251
|
-
* the onAvailable callback will be called.
|
|
4252
|
-
*
|
|
4253
|
-
* @param searchcraftId The SearchcraftCore instance to use.
|
|
4254
|
-
* @param onAvailable The callback that gets called when the core instance becomes available.
|
|
4255
|
-
*/
|
|
4256
|
-
useCoreInstance(searchcraftId, onAvailable) {
|
|
4257
|
-
const id = searchcraftId || DEFAULT_CORE_INSTANCE_ID;
|
|
4258
|
-
// If the core instance already is available, call the onAvailable callback immediately.
|
|
4259
|
-
if (this.coreInstances[id]) {
|
|
4260
|
-
onAvailable(this.coreInstances[id]);
|
|
4261
|
-
return () => { };
|
|
4262
|
-
}
|
|
4263
|
-
// Add the callback to the collection of callbacks for this searchcraft instance.
|
|
4264
|
-
if (!this.subscriptions[id]) {
|
|
4265
|
-
this.subscriptions[id] = [];
|
|
4266
|
-
}
|
|
4267
|
-
this.subscriptions[id].push(onAvailable);
|
|
4268
|
-
return () => {
|
|
4269
|
-
if (this.subscriptions[id]) {
|
|
4270
|
-
this.subscriptions[id] = this.subscriptions[id].filter((cb) => cb !== onAvailable);
|
|
4271
|
-
}
|
|
4272
|
-
};
|
|
4273
|
-
}
|
|
4274
|
-
}
|
|
4275
|
-
const registry = new CoreInstanceRegistry();
|
|
4276
|
-
|
|
4277
4304
|
/**
|
|
4278
4305
|
* This web component is designed to display facets in a search interface, allowing users to refine their search results by applying filters based on various attributes.
|
|
4279
4306
|
* It is consumed within the `searchcraft-filter-panel`.
|
|
@@ -4308,6 +4335,10 @@ class SearchcraftFacetList {
|
|
|
4308
4335
|
* The name of the field where facets are applied.
|
|
4309
4336
|
*/
|
|
4310
4337
|
fieldName = '';
|
|
4338
|
+
/**
|
|
4339
|
+
* Array of facet values to exclude from rendering.
|
|
4340
|
+
*/
|
|
4341
|
+
exclude;
|
|
4311
4342
|
/**
|
|
4312
4343
|
* Emitted when the facets are updated.
|
|
4313
4344
|
*/
|
|
@@ -4362,7 +4393,7 @@ class SearchcraftFacetList {
|
|
|
4362
4393
|
path: '/',
|
|
4363
4394
|
count: 0,
|
|
4364
4395
|
children: incomingFacetsWithChildrenArray || [],
|
|
4365
|
-
});
|
|
4396
|
+
}, this.exclude);
|
|
4366
4397
|
// Determine what action to take to accumulate items into the `facetTreeCollectedFromSearchResponse`.
|
|
4367
4398
|
// This facet tree gets accumulated in different ways depending on what action type occured.
|
|
4368
4399
|
switch (actionType) {
|
|
@@ -4386,7 +4417,7 @@ class SearchcraftFacetList {
|
|
|
4386
4417
|
path: '/',
|
|
4387
4418
|
count: 0,
|
|
4388
4419
|
children: supplementalFacetsWithChildrenArray || [],
|
|
4389
|
-
});
|
|
4420
|
+
}, this.exclude);
|
|
4390
4421
|
this.facetTreeCollectedFromSearchResponse = mergeFacetTrees(supplementalFacetTree, incomingFacetTree);
|
|
4391
4422
|
}
|
|
4392
4423
|
else {
|
|
@@ -4428,7 +4459,7 @@ class SearchcraftFacetList {
|
|
|
4428
4459
|
}
|
|
4429
4460
|
}
|
|
4430
4461
|
this.facetTreeFromFacetPathsNotInSearchResponse =
|
|
4431
|
-
facetWithChildrenArrayToCompleteFacetTree(collectedFacetArray);
|
|
4462
|
+
facetWithChildrenArrayToCompleteFacetTree(collectedFacetArray, this.exclude);
|
|
4432
4463
|
// Merges facetTreeCollectedFromSearchResponse with selectedFacetPathsNotInCurrentFacetTree.
|
|
4433
4464
|
// This results in a single, final facet tree that gets rendered in as Checkboxes
|
|
4434
4465
|
this.renderedFacetTree = deepMergeWithSpread(this.facetTreeFromFacetPathsNotInSearchResponse, this.facetTreeCollectedFromSearchResponse);
|
|
@@ -4436,45 +4467,86 @@ class SearchcraftFacetList {
|
|
|
4436
4467
|
handleStateUpdate(_state) {
|
|
4437
4468
|
const state = { ..._state };
|
|
4438
4469
|
// Determine what action to take based on the current State
|
|
4439
|
-
if (
|
|
4470
|
+
// Check if this is an initialQuery case (string requestProperties with empty searchTerm)
|
|
4471
|
+
const isInitialQuery = typeof state.searchClientRequestProperties === 'string' &&
|
|
4472
|
+
state.searchTerm.trim() === '';
|
|
4473
|
+
if (state.searchTerm.trim() === '' && !isInitialQuery) {
|
|
4440
4474
|
this.handleIncomingSearchResponse(state, 'SEARCH_TERM_EMPTY');
|
|
4441
4475
|
this.lastSearchTerm = '';
|
|
4442
4476
|
}
|
|
4443
4477
|
else if (this.lastTimeTaken !== state.searchResponseTimeTaken &&
|
|
4444
|
-
state.searchClientRequestProperties
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
if (this.
|
|
4450
|
-
|
|
4478
|
+
state.searchClientRequestProperties) {
|
|
4479
|
+
// Handle both object and string requestProperties (string is used for initialQuery)
|
|
4480
|
+
if (typeof state.searchClientRequestProperties === 'object') {
|
|
4481
|
+
const requestProperties = state.searchClientRequestProperties;
|
|
4482
|
+
let actionType = 'UNKNOWN';
|
|
4483
|
+
if (this.lastSearchTerm !== requestProperties.searchTerm) {
|
|
4484
|
+
if (this.areAnyFacetPathsSelected) {
|
|
4485
|
+
actionType = 'NEW_SEARCH_TERM_WHILE_FACETS_ACTIVE';
|
|
4486
|
+
}
|
|
4487
|
+
else {
|
|
4488
|
+
actionType = 'NEW_SEARCH_TERM';
|
|
4489
|
+
}
|
|
4451
4490
|
}
|
|
4452
|
-
else
|
|
4453
|
-
|
|
4491
|
+
else if (this.lastRangeValues !==
|
|
4492
|
+
JSON.stringify(requestProperties.rangeValueForIndexFields)) {
|
|
4493
|
+
actionType = 'RANGE_VALUE_UPDATE';
|
|
4454
4494
|
}
|
|
4495
|
+
else if (this.lastFacetValues !==
|
|
4496
|
+
JSON.stringify(requestProperties.facetPathsForIndexFields)) {
|
|
4497
|
+
actionType = 'FACET_UPDATE';
|
|
4498
|
+
}
|
|
4499
|
+
else if (this.lastSortType !== requestProperties.order_by) {
|
|
4500
|
+
actionType = 'SORT_ORDER_UPDATE';
|
|
4501
|
+
}
|
|
4502
|
+
else if (this.lastSearchMode !== requestProperties.mode) {
|
|
4503
|
+
actionType = 'EXACT_MATCH_UPDATE';
|
|
4504
|
+
}
|
|
4505
|
+
this.lastRangeValues = JSON.stringify(requestProperties.rangeValueForIndexFields);
|
|
4506
|
+
this.lastFacetValues = JSON.stringify(requestProperties.facetPathsForIndexFields);
|
|
4507
|
+
this.lastSortType = requestProperties.order_by;
|
|
4508
|
+
this.lastSearchMode = requestProperties.mode;
|
|
4509
|
+
this.lastSearchTerm = requestProperties.searchTerm;
|
|
4510
|
+
this.lastTimeTaken = state.searchResponseTimeTaken;
|
|
4511
|
+
// Handle the incoming response, using the action we have determined.
|
|
4512
|
+
this.handleIncomingSearchResponse(state, actionType);
|
|
4455
4513
|
}
|
|
4456
|
-
else if (
|
|
4457
|
-
|
|
4458
|
-
|
|
4459
|
-
|
|
4460
|
-
|
|
4461
|
-
JSON.
|
|
4462
|
-
|
|
4463
|
-
|
|
4464
|
-
|
|
4465
|
-
|
|
4466
|
-
|
|
4467
|
-
|
|
4468
|
-
|
|
4514
|
+
else if (typeof state.searchClientRequestProperties === 'string') {
|
|
4515
|
+
// Handle initialQuery case where requestProperties is a string
|
|
4516
|
+
// For initialQuery, searchTerm will be empty but we still want to show facets
|
|
4517
|
+
let actionType = 'NEW_SEARCH_TERM';
|
|
4518
|
+
// Parse the request to get facet and range filters from the query array
|
|
4519
|
+
const requestObj = JSON.parse(state.searchClientRequestProperties);
|
|
4520
|
+
const queryArray = Array.isArray(requestObj.query)
|
|
4521
|
+
? requestObj.query
|
|
4522
|
+
: [requestObj.query];
|
|
4523
|
+
// Extract filter queries (those with occur: 'must')
|
|
4524
|
+
const filterQueries = queryArray.filter((q) => q.occur === 'must');
|
|
4525
|
+
const currentFilters = JSON.stringify(filterQueries);
|
|
4526
|
+
// Determine the action type based on what changed
|
|
4527
|
+
if (this.lastFacetValues !== undefined && this.lastFacetValues !== currentFilters) {
|
|
4528
|
+
// Filters have changed (not initial load)
|
|
4529
|
+
actionType = 'FACET_UPDATE';
|
|
4530
|
+
}
|
|
4531
|
+
else if (state.searchTerm.trim() === '' && this.lastSearchTerm === '') {
|
|
4532
|
+
// Initial load or no changes with empty search term
|
|
4533
|
+
actionType = 'NEW_SEARCH_TERM';
|
|
4534
|
+
}
|
|
4535
|
+
else if (this.lastSearchTerm !== state.searchTerm) {
|
|
4536
|
+
// User has typed a new search term after initialQuery
|
|
4537
|
+
if (this.areAnyFacetPathsSelected) {
|
|
4538
|
+
actionType = 'NEW_SEARCH_TERM_WHILE_FACETS_ACTIVE';
|
|
4539
|
+
}
|
|
4540
|
+
else {
|
|
4541
|
+
actionType = 'NEW_SEARCH_TERM';
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
this.lastFacetValues = currentFilters;
|
|
4545
|
+
this.lastSearchTerm = state.searchTerm;
|
|
4546
|
+
this.lastTimeTaken = state.searchResponseTimeTaken;
|
|
4547
|
+
// Handle the incoming response, using the action we have determined.
|
|
4548
|
+
this.handleIncomingSearchResponse(state, actionType);
|
|
4469
4549
|
}
|
|
4470
|
-
this.lastRangeValues = JSON.stringify(requestProperties.rangeValueForIndexFields);
|
|
4471
|
-
this.lastFacetValues = JSON.stringify(requestProperties.facetPathsForIndexFields);
|
|
4472
|
-
this.lastSortType = requestProperties.order_by;
|
|
4473
|
-
this.lastSearchMode = requestProperties.mode;
|
|
4474
|
-
this.lastSearchTerm = requestProperties.searchTerm;
|
|
4475
|
-
this.lastTimeTaken = state.searchResponseTimeTaken;
|
|
4476
|
-
// Handle the incoming response, using the action we have determined.
|
|
4477
|
-
this.handleIncomingSearchResponse(state, actionType);
|
|
4478
4550
|
}
|
|
4479
4551
|
}
|
|
4480
4552
|
onCoreAvailable(core) {
|
|
@@ -4569,6 +4641,7 @@ class SearchcraftFacetList {
|
|
|
4569
4641
|
"$members$": {
|
|
4570
4642
|
"searchcraftId": [1, "searchcraft-id"],
|
|
4571
4643
|
"fieldName": [1, "field-name"],
|
|
4644
|
+
"exclude": [16],
|
|
4572
4645
|
"selectedPaths": [32],
|
|
4573
4646
|
"facetTreeCollectedFromSearchResponse": [32],
|
|
4574
4647
|
"renderedFacetTree": [32]
|
|
@@ -4714,7 +4787,7 @@ class SearchcraftFilterPanel {
|
|
|
4714
4787
|
* Iterate through `items` and render them based on `type`
|
|
4715
4788
|
*/
|
|
4716
4789
|
render() {
|
|
4717
|
-
return (hAsync("div", { key: '
|
|
4790
|
+
return (hAsync("div", { key: 'ee8974e38b296a1ba27111bc2a4244d8915f5839', class: 'searchcraft-filter-panel' }, this.items.map((filterItem) => {
|
|
4718
4791
|
switch (filterItem.type) {
|
|
4719
4792
|
case 'dateRange': {
|
|
4720
4793
|
const item = filterItem;
|
|
@@ -4734,7 +4807,7 @@ class SearchcraftFilterPanel {
|
|
|
4734
4807
|
case 'facets': {
|
|
4735
4808
|
const item = filterItem;
|
|
4736
4809
|
// return "filters-list"
|
|
4737
|
-
return (hAsync("div", { class: 'searchcraft-filter-panel-section' }, hAsync("p", { class: 'searchcraft-filter-panel-label' }, filterItem.label), hAsync("searchcraft-facet-list", { fieldName: item.fieldName, onFacetSelectionUpdated: (event) => {
|
|
4810
|
+
return (hAsync("div", { class: 'searchcraft-filter-panel-section' }, hAsync("p", { class: 'searchcraft-filter-panel-label' }, filterItem.label), hAsync("searchcraft-facet-list", { fieldName: item.fieldName, exclude: item.options.exclude, onFacetSelectionUpdated: (event) => {
|
|
4738
4811
|
this.handleFacetSelectionUpdated(item.fieldName, event.detail.paths);
|
|
4739
4812
|
} })));
|
|
4740
4813
|
}
|
|
@@ -4833,6 +4906,10 @@ class SearchcraftInputForm {
|
|
|
4833
4906
|
* 'hide-on-text-entered' - Only hide the placeholder when the input form has text entered into it.
|
|
4834
4907
|
*/
|
|
4835
4908
|
placeholderBehavior;
|
|
4909
|
+
/**
|
|
4910
|
+
* The value to display in the input field.
|
|
4911
|
+
*/
|
|
4912
|
+
value;
|
|
4836
4913
|
/**
|
|
4837
4914
|
* When the input becomes focused.
|
|
4838
4915
|
*/
|
|
@@ -4853,18 +4930,41 @@ class SearchcraftInputForm {
|
|
|
4853
4930
|
cleanupCore;
|
|
4854
4931
|
init() {
|
|
4855
4932
|
if (this.core) {
|
|
4933
|
+
// Initialize inputValue from prop if provided
|
|
4934
|
+
if (this.value !== undefined && this.value.trim().length > 0) {
|
|
4935
|
+
this.inputValue = this.value;
|
|
4936
|
+
this.core.store.getState().setSearchTerm(this.value);
|
|
4937
|
+
// Trigger search if autoSearch is enabled
|
|
4938
|
+
if (this.autoSearch) {
|
|
4939
|
+
this.core.store.getState().search();
|
|
4940
|
+
}
|
|
4941
|
+
}
|
|
4856
4942
|
this.inputInit?.emit();
|
|
4857
4943
|
}
|
|
4858
4944
|
}
|
|
4859
4945
|
onCoreChange() {
|
|
4860
4946
|
this.init();
|
|
4861
4947
|
}
|
|
4948
|
+
onValueChange(newValue) {
|
|
4949
|
+
if (newValue !== undefined && newValue !== this.inputValue) {
|
|
4950
|
+
this.inputValue = newValue;
|
|
4951
|
+
this.core?.store.getState().setSearchTerm(newValue);
|
|
4952
|
+
// Trigger search if autoSearch is enabled and value is not empty
|
|
4953
|
+
if (this.autoSearch && newValue.trim().length > 0) {
|
|
4954
|
+
this.core?.store.getState().search();
|
|
4955
|
+
}
|
|
4956
|
+
}
|
|
4957
|
+
}
|
|
4862
4958
|
onCoreAvailable(core) {
|
|
4863
4959
|
this.core = core;
|
|
4864
4960
|
this.init();
|
|
4865
4961
|
this.unsubscribe = core.store.subscribe((state) => {
|
|
4866
4962
|
this.searchTerm = state.searchTerm;
|
|
4867
|
-
|
|
4963
|
+
// Only update inputValue from store if value prop is not set
|
|
4964
|
+
// OR if the store was cleared (empty string)
|
|
4965
|
+
if (this.value === undefined || state.searchTerm === '') {
|
|
4966
|
+
this.inputValue = state.searchTerm;
|
|
4967
|
+
}
|
|
4868
4968
|
});
|
|
4869
4969
|
}
|
|
4870
4970
|
connectedCallback() {
|
|
@@ -4893,6 +4993,8 @@ class SearchcraftInputForm {
|
|
|
4893
4993
|
}
|
|
4894
4994
|
};
|
|
4895
4995
|
handleClearInput = () => {
|
|
4996
|
+
// Clear the input value even if controlled by prop
|
|
4997
|
+
this.inputValue = '';
|
|
4896
4998
|
this.core?.store.getState().resetSearchValues();
|
|
4897
4999
|
this.error = false;
|
|
4898
5000
|
};
|
|
@@ -4911,14 +5013,15 @@ class SearchcraftInputForm {
|
|
|
4911
5013
|
const inputGridStyles = {
|
|
4912
5014
|
gap: shouldHaveVerticalGap ? '4px 8px' : '0px 8px',
|
|
4913
5015
|
};
|
|
4914
|
-
return (hAsync("form", { key: '
|
|
5016
|
+
return (hAsync("form", { key: 'd214ace44e9209154d215e803de088aefa58a285', class: 'searchcraft-input-form', onSubmit: this.handleFormSubmit }, hAsync("div", { key: '5699f5dca28caf5e9584401f1883d2e08d26e3ec', class: inputGridClassNames, style: inputGridStyles }, hAsync("div", { key: 'ef792a946414a680e9c99c145246d00b9b8f2ffb', class: 'searchcraft-input-form-button' }, hAsync("searchcraft-button", { key: 'ba5a8cb98889bb486781af4915a21c94a0b1498a', onButtonClick: this.handleFormSubmit, label: this.buttonLabel })), this.inputLabel && (hAsync("div", { key: 'a9e770ef967f7ab1c6ddf8f87f23cea509894536', class: 'searchcraft-input-form-label' }, hAsync("searchcraft-input-label", { key: '93b29e630e71a3c7724921aa9586aab76e592f4f', label: this.inputLabel }))), this.error && (hAsync("div", { key: '641ef4f468d527c24a1635d49dcbbba03030686f', class: 'searchcraft-input-form-error-message' }, hAsync("searchcraft-error-message", { key: '2d839d17b702fe1b41d7e49aacfc52fb53315766' }, "Something went wrong."))), hAsync("div", { key: 'af0c73478de21447c992bd0037ba007d54f53a86', class: 'searchcraft-input-form-input-wrapper' }, hAsync("input", { key: '3de1be1aa71c143b58cd6080d422410bd400e4e5', autoComplete: 'off', class: classNames('searchcraft-input-form-input', {
|
|
4915
5017
|
'searchcraft-placeholder-hide-on-focus': this.placeholderBehavior === 'hide-on-focus',
|
|
4916
5018
|
}), onFocus: () => this.inputFocus?.emit(), onBlur: () => this.inputBlur?.emit(), onInput: (event) => {
|
|
4917
5019
|
this.handleInput(event);
|
|
4918
|
-
}, placeholder: this.placeholderValue, type: 'text', value: this.inputValue }), hAsync("div", { key: '
|
|
5020
|
+
}, placeholder: this.placeholderValue, type: 'text', value: this.inputValue }), hAsync("div", { key: 'fe9043c046e3b1b91129299f0860919ba8a8416b', class: 'searchcraft-input-form-input-icon' }, hAsync("svg", { key: '31ae1553cd214d5e2f97c9e3699862dff51a0916', class: 'searchcraft-input-form-input-search-icon', viewBox: '0 0 20 20', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', "aria-labelledby": 'searchcraft-title' }, hAsync("title", { key: '9db677da65283ff15b0d4e79b5d9daf89637b33f' }, "Search icon"), hAsync("path", { key: '2a002eae6ed3725a432e7c3e4649c0bd2ffff7a0', d: 'M17.5 17.5L13.875 13.875M15.8333 9.16667C15.8333 12.8486 12.8486 15.8333 9.16667 15.8333C5.48477 15.8333 2.5 12.8486 2.5 9.16667C2.5 5.48477 5.48477 2.5 9.16667 2.5C12.8486 2.5 15.8333 5.48477 15.8333 9.16667Z', stroke: 'currentColor', "stroke-width": '1.5', "stroke-linecap": 'round', "stroke-linejoin": 'round' }))), isShowingClearButton && (hAsync("button", { key: 'b7e92b22c3234eb31d85b0aa98d7c682b2fc0021', type: 'button', class: 'searchcraft-input-form-clear-button', onClick: this.handleClearInput }, hAsync("svg", { key: 'bfbeb742f197da0cac6dd5df2627db9df5349207', class: 'searchcraft-input-form-clear-icon', viewBox: '0 0 22 22', fill: 'none', xmlns: 'http://www.w3.org/2000/svg', "aria-labelledby": 'icon-title' }, hAsync("title", { key: 'c62b9d237b3762609fed72e0520322fb5eabe979' }, "Clear icon"), hAsync("path", { key: '198a13760ce8b076ef8e791dec933b210ff3017a', d: 'M14 8L8 14M8 8L14 14M21 11C21 16.5228 16.5228 21 11 21C5.47715 21 1 16.5228 1 11C1 5.47715 5.47715 1 11 1C16.5228 1 21 5.47715 21 11Z', stroke: 'currentColor', "stroke-width": '1.5', "stroke-linecap": 'round', "stroke-linejoin": 'round' }))))))));
|
|
4919
5021
|
}
|
|
4920
5022
|
static get watchers() { return {
|
|
4921
|
-
"core": ["onCoreChange"]
|
|
5023
|
+
"core": ["onCoreChange"],
|
|
5024
|
+
"value": ["onValueChange"]
|
|
4922
5025
|
}; }
|
|
4923
5026
|
static get cmpMeta() { return {
|
|
4924
5027
|
"$flags$": 0,
|
|
@@ -4931,6 +5034,7 @@ class SearchcraftInputForm {
|
|
|
4931
5034
|
"inputLabel": [1, "input-label"],
|
|
4932
5035
|
"placeholderValue": [1, "placeholder-value"],
|
|
4933
5036
|
"placeholderBehavior": [1, "placeholder-behavior"],
|
|
5037
|
+
"value": [1],
|
|
4934
5038
|
"inputValue": [32],
|
|
4935
5039
|
"searchTerm": [32],
|
|
4936
5040
|
"error": [32]
|
|
@@ -5042,6 +5146,7 @@ class SearchcraftPagination {
|
|
|
5042
5146
|
searchResultsPerPage;
|
|
5043
5147
|
searchResultsPage;
|
|
5044
5148
|
searchResultsCount;
|
|
5149
|
+
searchClientRequestProperties;
|
|
5045
5150
|
// local vars
|
|
5046
5151
|
searchResultsPagesCount = 1;
|
|
5047
5152
|
searchResultsRangeMin = 1;
|
|
@@ -5057,6 +5162,7 @@ class SearchcraftPagination {
|
|
|
5057
5162
|
this.searchResultsPerPage = state.searchResultsPerPage;
|
|
5058
5163
|
this.searchResultsPage = state.searchResultsPage;
|
|
5059
5164
|
this.searchResultsCount = state.searchResultsCount;
|
|
5165
|
+
this.searchClientRequestProperties = state.searchClientRequestProperties;
|
|
5060
5166
|
// local vars
|
|
5061
5167
|
this.searchResultsPagesCount = Math.ceil(this.searchResultsCount / this.searchResultsPerPage);
|
|
5062
5168
|
this.searchResultsRangeMin =
|
|
@@ -5116,8 +5222,11 @@ class SearchcraftPagination {
|
|
|
5116
5222
|
return (hAsync("li", null, hAsync("span", { class: 'searchcraft-pagination-item searchcraft-pagination-item-active' }, this.searchResultsPage)));
|
|
5117
5223
|
}
|
|
5118
5224
|
render() {
|
|
5119
|
-
//
|
|
5120
|
-
|
|
5225
|
+
// Check if this is an initialQuery case (string requestProperties with empty searchTerm)
|
|
5226
|
+
const isInitialQuery = typeof this.searchClientRequestProperties === 'string' &&
|
|
5227
|
+
this.searchTerm.trim() === '';
|
|
5228
|
+
// early return if there isn't a searchTerm (unless it's initialQuery) or there is 1 or fewer pages of results
|
|
5229
|
+
if ((!this.searchTerm && !isInitialQuery) || this.searchResultsPagesCount <= 1) {
|
|
5121
5230
|
return;
|
|
5122
5231
|
}
|
|
5123
5232
|
return (hAsync("div", { class: 'searchcraft-pagination' }, hAsync("div", { class: 'searchcraft-pagination-control' }, hAsync("searchcraft-button", { disabled: this.searchResultsPage === 1, hierarchy: 'tertiary', onButtonClick: () => this.handleGoToPage(Math.max(1, this.searchResultsPage - 1)), label: 'Previous', iconPosition: 'left', icon: hAsync("svg", { class: 'searchcraft-button-icon', width: '20', height: '20', viewBox: '0 0 20 20', fill: 'none', xmlns: 'http://www.w3.org/2000/svg' }, hAsync("title", null, "Previous page icon"), hAsync("path", { d: 'M12.5 15L7.5 10L12.5 5', stroke: 'currentColor', "stroke-width": '1.5', "stroke-linecap": 'round', "stroke-linejoin": 'round' })), iconOnly: true })), hAsync("ul", { class: 'searchcraft-pagination-list' }, this.renderOddPaginationItem(1), this.renderEvenPaginationItem(2), this.renderMiddlePaginationItem(), this.renderEvenPaginationItem(this.searchResultsPagesCount > 4
|
|
@@ -5135,6 +5244,7 @@ class SearchcraftPagination {
|
|
|
5135
5244
|
"searchResultsPerPage": [32],
|
|
5136
5245
|
"searchResultsPage": [32],
|
|
5137
5246
|
"searchResultsCount": [32],
|
|
5247
|
+
"searchClientRequestProperties": [32],
|
|
5138
5248
|
"searchResultsPagesCount": [32],
|
|
5139
5249
|
"searchResultsRangeMin": [32],
|
|
5140
5250
|
"searchResultsRangeMax": [32],
|
|
@@ -6158,6 +6268,7 @@ class SearchcraftResultsInfo {
|
|
|
6158
6268
|
searchResultsPage;
|
|
6159
6269
|
searchResultsPerPage;
|
|
6160
6270
|
searchResultsCount;
|
|
6271
|
+
searchClientRequestProperties;
|
|
6161
6272
|
// local vars
|
|
6162
6273
|
count = 0;
|
|
6163
6274
|
range = [0, 0];
|
|
@@ -6171,6 +6282,7 @@ class SearchcraftResultsInfo {
|
|
|
6171
6282
|
this.searchResultsPage = state.searchResultsPage;
|
|
6172
6283
|
this.searchResultsPerPage = state.searchResultsPerPage;
|
|
6173
6284
|
this.searchResultsCount = state.searchResultsCount;
|
|
6285
|
+
this.searchClientRequestProperties = state.searchClientRequestProperties;
|
|
6174
6286
|
// local vars
|
|
6175
6287
|
this.count = this.searchResultsCount;
|
|
6176
6288
|
this.range[0] =
|
|
@@ -6193,7 +6305,12 @@ class SearchcraftResultsInfo {
|
|
|
6193
6305
|
this.cleanupCore?.();
|
|
6194
6306
|
}
|
|
6195
6307
|
render() {
|
|
6196
|
-
if
|
|
6308
|
+
// Check if this is an initialQuery case (string requestProperties with empty searchTerm)
|
|
6309
|
+
const isInitialQuery = typeof this.searchClientRequestProperties === 'string' &&
|
|
6310
|
+
this.searchTerm.trim() === '';
|
|
6311
|
+
// Only hide if there's no search term AND no initialQuery AND no results
|
|
6312
|
+
if ((!this.searchTerm && !isInitialQuery) ||
|
|
6313
|
+
this.searchResultsCount === 0) {
|
|
6197
6314
|
return null;
|
|
6198
6315
|
}
|
|
6199
6316
|
return (hAsync("p", { class: 'searchcraft-results-info' }, typeof this.template !== 'undefined'
|
|
@@ -6214,6 +6331,7 @@ class SearchcraftResultsInfo {
|
|
|
6214
6331
|
"searchResultsPage": [32],
|
|
6215
6332
|
"searchResultsPerPage": [32],
|
|
6216
6333
|
"searchResultsCount": [32],
|
|
6334
|
+
"searchClientRequestProperties": [32],
|
|
6217
6335
|
"count": [32],
|
|
6218
6336
|
"range": [32],
|
|
6219
6337
|
"responseTime": [32]
|
|
@@ -6588,6 +6706,7 @@ class SearchcraftSearchResultsPerPage {
|
|
|
6588
6706
|
searchResultsPerPage;
|
|
6589
6707
|
searchResultsCount;
|
|
6590
6708
|
searchResultsPagesCount;
|
|
6709
|
+
searchClientRequestProperties;
|
|
6591
6710
|
// local vars
|
|
6592
6711
|
initialSearchResultsPerPage;
|
|
6593
6712
|
// store functions
|
|
@@ -6602,6 +6721,7 @@ class SearchcraftSearchResultsPerPage {
|
|
|
6602
6721
|
this.searchResultsPerPage = state.searchResultsPerPage;
|
|
6603
6722
|
this.searchResultsPage = state.searchResultsPage;
|
|
6604
6723
|
this.searchResultsCount = state.searchResultsCount;
|
|
6724
|
+
this.searchClientRequestProperties = state.searchClientRequestProperties;
|
|
6605
6725
|
// local vars
|
|
6606
6726
|
this.searchResultsPagesCount = Math.ceil(this.searchResultsCount / this.searchResultsPerPage);
|
|
6607
6727
|
// store functions
|
|
@@ -6619,8 +6739,11 @@ class SearchcraftSearchResultsPerPage {
|
|
|
6619
6739
|
this.cleanupCore?.();
|
|
6620
6740
|
}
|
|
6621
6741
|
render() {
|
|
6622
|
-
//
|
|
6623
|
-
|
|
6742
|
+
// Check if this is an initialQuery case (string requestProperties with empty searchTerm)
|
|
6743
|
+
const isInitialQuery = typeof this.searchClientRequestProperties === 'string' &&
|
|
6744
|
+
this.searchTerm.trim() === '';
|
|
6745
|
+
// early return if there isn't a searchTerm (unless it's initialQuery) or there is 1 or fewer pages of results
|
|
6746
|
+
if ((!this.searchTerm && !isInitialQuery) || this.searchResultsPagesCount <= 1) {
|
|
6624
6747
|
return;
|
|
6625
6748
|
}
|
|
6626
6749
|
return (hAsync("div", { class: 'searchcraft-search-results-per-page' }, hAsync("div", { class: 'searchcraft-search-results-per-page-select' }, hAsync("label", { class: 'searchcraft-search-results-per-page-select-label', htmlFor: 'searchcraft-search-results-per-page-select-input' }, "Results Per Page"), hAsync("div", { class: 'searchcraft-search-results-per-page-select-input' }, hAsync("searchcraft-select", { inputId: 'searchcraft-search-results-per-page-select-input', name: 'results-per-page', options: [...Array(5)].map((_, index) => {
|
|
@@ -6646,6 +6769,7 @@ class SearchcraftSearchResultsPerPage {
|
|
|
6646
6769
|
"searchResultsPerPage": [32],
|
|
6647
6770
|
"searchResultsCount": [32],
|
|
6648
6771
|
"searchResultsPagesCount": [32],
|
|
6772
|
+
"searchClientRequestProperties": [32],
|
|
6649
6773
|
"initialSearchResultsPerPage": [32],
|
|
6650
6774
|
"setSearchResultsPerPage": [32],
|
|
6651
6775
|
"setSearchResultsPage": [32]
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type AdClient, MeasureClient, SearchClient } from "../clients/index";
|
|
2
|
-
import type { AdClientResponseItem, SearchcraftConfig, SearchcraftSDKInfo,
|
|
2
|
+
import type { AdClientResponseItem, SearchClientRequestProperties, SearchcraftConfig, SearchcraftSDKInfo, SubscriptionEventCallback, SubscriptionEventMap, SubscriptionEventName, UnsubscribeFunction } from "../types/index";
|
|
3
3
|
import { type SearchcraftStore } from "../store/index";
|
|
4
4
|
/**
|
|
5
5
|
* Javascript Class providing the functionality to interact with the Searchcraft BE
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type EventEmitter } from '../../stencil-public-runtime';
|
|
2
2
|
import type { FacetWithChildrenObject } from "../../types/index";
|
|
3
|
-
import type { SearchcraftState } from "../../store/index";
|
|
4
3
|
import type { SearchcraftCore } from "../../classes/index";
|
|
4
|
+
import type { SearchcraftState } from "../../store/index";
|
|
5
5
|
type HandlerActionType = 'SEARCH_TERM_EMPTY' | 'NEW_SEARCH_TERM' | 'NEW_SEARCH_TERM_WHILE_FACETS_ACTIVE' | 'RANGE_VALUE_UPDATE' | 'EXACT_MATCH_UPDATE' | 'SORT_ORDER_UPDATE' | 'FACET_UPDATE' | 'UNKNOWN';
|
|
6
6
|
/**
|
|
7
7
|
* This web component is designed to display facets in a search interface, allowing users to refine their search results by applying filters based on various attributes.
|
|
@@ -33,6 +33,10 @@ export declare class SearchcraftFacetList {
|
|
|
33
33
|
* The name of the field where facets are applied.
|
|
34
34
|
*/
|
|
35
35
|
fieldName: string;
|
|
36
|
+
/**
|
|
37
|
+
* Array of facet values to exclude from rendering.
|
|
38
|
+
*/
|
|
39
|
+
exclude?: string[];
|
|
36
40
|
/**
|
|
37
41
|
* Emitted when the facets are updated.
|
|
38
42
|
*/
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SearchcraftCore } from "../../classes/index";
|
|
2
|
-
import type {
|
|
2
|
+
import type { DateRangeFilterItem, FilterItem } from "../../types/index";
|
|
3
3
|
/**
|
|
4
4
|
* This web component represents a series of filters that allows users to refine and control their search queries by applying various filter criteria.
|
|
5
5
|
*
|
|
@@ -60,6 +60,10 @@ export declare class SearchcraftInputForm {
|
|
|
60
60
|
* 'hide-on-text-entered' - Only hide the placeholder when the input form has text entered into it.
|
|
61
61
|
*/
|
|
62
62
|
placeholderBehavior?: 'hide-on-focus' | 'hide-on-text-entered';
|
|
63
|
+
/**
|
|
64
|
+
* The value to display in the input field.
|
|
65
|
+
*/
|
|
66
|
+
value?: string;
|
|
63
67
|
/**
|
|
64
68
|
* When the input becomes focused.
|
|
65
69
|
*/
|
|
@@ -80,6 +84,7 @@ export declare class SearchcraftInputForm {
|
|
|
80
84
|
private cleanupCore?;
|
|
81
85
|
init(): void;
|
|
82
86
|
onCoreChange(): void;
|
|
87
|
+
onValueChange(newValue: string | undefined): void;
|
|
83
88
|
onCoreAvailable(core: SearchcraftCore): void;
|
|
84
89
|
connectedCallback(): void;
|
|
85
90
|
disconnectedCallback(): void;
|
|
@@ -36,6 +36,7 @@ export declare class SearchcraftPagination {
|
|
|
36
36
|
searchResultsPerPage: any;
|
|
37
37
|
searchResultsPage: any;
|
|
38
38
|
searchResultsCount: any;
|
|
39
|
+
searchClientRequestProperties: any;
|
|
39
40
|
searchResultsPagesCount: number;
|
|
40
41
|
searchResultsRangeMin: number;
|
|
41
42
|
searchResultsRangeMax: number;
|
|
@@ -43,6 +43,7 @@ export declare class SearchcraftSearchResultsPerPage {
|
|
|
43
43
|
searchResultsPerPage: any;
|
|
44
44
|
searchResultsCount: any;
|
|
45
45
|
searchResultsPagesCount: any;
|
|
46
|
+
searchClientRequestProperties: any;
|
|
46
47
|
initialSearchResultsPerPage: any;
|
|
47
48
|
setSearchResultsPerPage: (perPage: number) => void;
|
|
48
49
|
setSearchResultsPage: (page: number) => void;
|