@phatvu/web-component-poc 1.0.6 → 1.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/fast-button_6.cjs.entry.js +578 -0
- package/dist/cjs/{fast-button_4.cjs.entry.js → fast-carousel.cjs.entry.js} +1 -231
- package/dist/cjs/{index-B2BTpdbN.js → index-227GpI8K.js} +66 -2
- package/dist/cjs/job-card.cjs.entry.js +1 -1
- package/dist/cjs/loader.cjs.js +2 -2
- package/dist/cjs/web-component-poc.cjs.js +2 -2
- package/dist/collection/collection-manifest.json +4 -1
- package/dist/collection/components/button/button.css +14 -14
- package/dist/collection/components/button/button.js +12 -24
- package/dist/collection/components/fast-form/fast-form.css +5 -0
- package/dist/collection/components/fast-form/fast-form.js +99 -0
- package/dist/collection/components/fast-input/fast-input.css +45 -0
- package/dist/collection/components/fast-input/fast-input.js +359 -0
- package/dist/collection/components/jobs-list-only/jobs-list-only.js +180 -3
- package/dist/collection/components/jobs-list-reactive/jobs-list-reactive.css +8 -0
- package/dist/collection/components/jobs-list-reactive/jobs-list-reactive.js +203 -0
- package/dist/components/fast-button.js +1 -1
- package/dist/components/fast-carousel.js +1 -1
- package/dist/components/fast-form.d.ts +11 -0
- package/dist/components/fast-form.js +1 -0
- package/dist/components/fast-input.d.ts +11 -0
- package/dist/components/fast-input.js +1 -0
- package/dist/components/index.js +1 -1
- package/dist/components/job-card.js +1 -1
- package/dist/components/jobs-item.js +1 -1
- package/dist/components/jobs-list-only.js +1 -1
- package/dist/components/jobs-list-reactive.d.ts +11 -0
- package/dist/components/jobs-list-reactive.js +1 -0
- package/dist/components/p-Bb27ylcX.js +1 -0
- package/dist/components/{p-ClQDwJJB.js → p-CzgtwPsc.js} +1 -1
- package/dist/esm/fast-button_6.entry.js +571 -0
- package/dist/esm/{fast-button_4.entry.js → fast-carousel.entry.js} +2 -229
- package/dist/esm/{index-Dk5CvWmb.js → index-BqjrT3zA.js} +66 -2
- package/dist/esm/job-card.entry.js +1 -1
- package/dist/esm/loader.js +3 -3
- package/dist/esm/web-component-poc.js +3 -3
- package/dist/types/components/button/button.d.ts +1 -13
- package/dist/types/components/fast-form/fast-form.d.ts +10 -0
- package/dist/types/components/fast-input/fast-input.d.ts +35 -0
- package/dist/types/components/jobs-list-only/jobs-list-only.d.ts +22 -0
- package/dist/types/components/jobs-list-reactive/jobs-list-reactive.d.ts +26 -0
- package/dist/types/components.d.ts +256 -11
- package/dist/web-component-poc/{p-52c85341.entry.js → p-14247159.entry.js} +1 -1
- package/dist/web-component-poc/p-309a490b.entry.js +1 -0
- package/dist/web-component-poc/p-7ea9a87f.entry.js +1 -0
- package/dist/web-component-poc/{p-Dk5CvWmb.js → p-BqjrT3zA.js} +2 -2
- package/dist/web-component-poc/web-component-poc.esm.js +1 -1
- package/hydrate/index.js +457 -27
- package/hydrate/index.mjs +457 -27
- package/package.json +7 -3
- package/dist/components/p-UM9TUfe3.js +0 -1
- package/dist/web-component-poc/p-96761988.entry.js +0 -1
package/hydrate/index.js
CHANGED
|
@@ -132,7 +132,7 @@ function hydrateFactory($stencilWindow, $stencilHydrateOpts, $stencilHydrateResu
|
|
|
132
132
|
|
|
133
133
|
|
|
134
134
|
const NAMESPACE = 'web-component-poc';
|
|
135
|
-
const BUILD = /* web-component-poc */ { hotModuleReplacement: false, hydratedSelectorName: "hydrated",
|
|
135
|
+
const BUILD = /* web-component-poc */ { hotModuleReplacement: false, hydratedSelectorName: "hydrated", propChangeCallback: false, shadowDom: false, slotRelocation: true, state: true, updatable: true};
|
|
136
136
|
|
|
137
137
|
/*
|
|
138
138
|
Stencil Hydrate Platform v4.43.2 | MIT Licensed | https://stenciljs.com
|
|
@@ -2099,6 +2099,13 @@ var dispatchHooks = (hostRef, isInitialLoad) => {
|
|
|
2099
2099
|
hostRef.$deferredConnectedCallback$ = false;
|
|
2100
2100
|
safeCall(instance, "connectedCallback", void 0, elm);
|
|
2101
2101
|
}
|
|
2102
|
+
{
|
|
2103
|
+
hostRef.$flags$ |= 256 /* isListenReady */;
|
|
2104
|
+
if (hostRef.$queuedListeners$) {
|
|
2105
|
+
hostRef.$queuedListeners$.map(([methodName, event]) => safeCall(instance, methodName, event, elm));
|
|
2106
|
+
hostRef.$queuedListeners$ = void 0;
|
|
2107
|
+
}
|
|
2108
|
+
}
|
|
2102
2109
|
if (hostRef.$fetchedCbList$.length) {
|
|
2103
2110
|
hostRef.$fetchedCbList$.forEach((cb) => cb(elm));
|
|
2104
2111
|
}
|
|
@@ -2478,6 +2485,7 @@ var connectedCallback = (elm) => {
|
|
|
2478
2485
|
initializeComponent(elm, hostRef, cmpMeta);
|
|
2479
2486
|
}
|
|
2480
2487
|
} else {
|
|
2488
|
+
addHostEventListeners(elm, hostRef, cmpMeta.$listeners$);
|
|
2481
2489
|
if (hostRef == null ? void 0 : hostRef.$lazyInstance$) {
|
|
2482
2490
|
fireConnectedCallback(hostRef.$lazyInstance$, elm);
|
|
2483
2491
|
} else if (hostRef == null ? void 0 : hostRef.$onReadyPromise$) {
|
|
@@ -2497,6 +2505,32 @@ var setContentReference = (elm) => {
|
|
|
2497
2505
|
contentRefElm["s-cn"] = true;
|
|
2498
2506
|
insertBefore(elm, contentRefElm, elm.firstChild);
|
|
2499
2507
|
};
|
|
2508
|
+
var addHostEventListeners = (elm, hostRef, listeners, attachParentListeners) => {
|
|
2509
|
+
if (listeners && win.document) {
|
|
2510
|
+
listeners.map(([flags, name, method]) => {
|
|
2511
|
+
const target = elm;
|
|
2512
|
+
const handler = hostListenerProxy(hostRef, method);
|
|
2513
|
+
const opts = hostListenerOpts(flags);
|
|
2514
|
+
plt.ael(target, name, handler, opts);
|
|
2515
|
+
(hostRef.$rmListeners$ = hostRef.$rmListeners$ || []).push(() => plt.rel(target, name, handler, opts));
|
|
2516
|
+
});
|
|
2517
|
+
}
|
|
2518
|
+
};
|
|
2519
|
+
var hostListenerProxy = (hostRef, methodName) => (ev) => {
|
|
2520
|
+
var _a;
|
|
2521
|
+
try {
|
|
2522
|
+
{
|
|
2523
|
+
if (hostRef.$flags$ & 256 /* isListenReady */) {
|
|
2524
|
+
(_a = hostRef.$lazyInstance$) == null ? void 0 : _a[methodName](ev);
|
|
2525
|
+
} else {
|
|
2526
|
+
(hostRef.$queuedListeners$ = hostRef.$queuedListeners$ || []).push([methodName, ev]);
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
} catch (e) {
|
|
2530
|
+
consoleError(e, hostRef.$hostElement$);
|
|
2531
|
+
}
|
|
2532
|
+
};
|
|
2533
|
+
var hostListenerOpts = (flags) => (flags & 2 /* Capture */) !== 0;
|
|
2500
2534
|
function transformTag(tag) {
|
|
2501
2535
|
return tag;
|
|
2502
2536
|
}
|
|
@@ -4277,6 +4311,7 @@ async function hydrateComponent(win2, results, tagName, elm, waitingElements) {
|
|
|
4277
4311
|
if (!hostRef) {
|
|
4278
4312
|
return;
|
|
4279
4313
|
}
|
|
4314
|
+
addHostEventListeners(this, hostRef, cmpMeta.$listeners$);
|
|
4280
4315
|
try {
|
|
4281
4316
|
connectedCallback(elm);
|
|
4282
4317
|
await elm.componentOnReady();
|
|
@@ -4507,7 +4542,7 @@ var registerInstance = (lazyInstance, hostRef) => {
|
|
|
4507
4542
|
if (!hostRef) return void 0;
|
|
4508
4543
|
lazyInstance.__stencil__getHostRef = () => hostRef;
|
|
4509
4544
|
hostRef.$lazyInstance$ = lazyInstance;
|
|
4510
|
-
if (hostRef.$cmpMeta$.$flags$ & 512 /* hasModernPropertyDecls */ && (BUILD.
|
|
4545
|
+
if (hostRef.$cmpMeta$.$flags$ & 512 /* hasModernPropertyDecls */ && (BUILD.state)) {
|
|
4511
4546
|
reWireGetterSetter(lazyInstance, hostRef);
|
|
4512
4547
|
}
|
|
4513
4548
|
return hostRef;
|
|
@@ -6454,28 +6489,16 @@ class AppCarousel {
|
|
|
6454
6489
|
}; }
|
|
6455
6490
|
}
|
|
6456
6491
|
|
|
6457
|
-
const buttonCss = () => `:host{display:inline-block}.
|
|
6492
|
+
const buttonCss = () => `:host{display:inline-block}.fast-button{display:inline-flex;align-items:center;justify-content:center;padding:0.5rem 1rem;font-family:inherit;font-size:0.875rem;font-weight:500;line-height:1.25;border:none;border-radius:0.375rem;cursor:pointer;transition:background-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease}.fast-button:focus{outline:2px solid var(--custom-button-focus-ring, #2563eb);outline-offset:2px}.fast-button:focus:not(:focus-visible){outline:none}.fast-button--primary{background-color:var(--custom-button-primary-bg, #2563eb);color:var(--custom-button-primary-color, #fff)}.fast-button--primary:hover:not(.fast-button--disabled){background-color:var(--custom-button-primary-hover-bg, #1d4ed8)}.fast-button--primary:active:not(.fast-button--disabled){background-color:var(--custom-button-primary-active-bg, #1e40af)}.fast-button--secondary{background-color:var(--custom-button-secondary-bg, #e5e7eb);color:var(--custom-button-secondary-color, #1f2937)}.fast-button--secondary:hover:not(.fast-button--disabled){background-color:var(--custom-button-secondary-hover-bg, #d1d5db)}.fast-button--secondary:active:not(.fast-button--disabled){background-color:var(--custom-button-secondary-active-bg, #9ca3af)}.fast-button--text{background-color:transparent;color:var(--custom-button-text-color, #2563eb)}.fast-button--text:hover:not(.fast-button--disabled){background-color:var(--custom-button-text-hover-bg, rgba(37, 99, 235, 0.08))}.fast-button--text:active:not(.fast-button--disabled){background-color:var(--custom-button-text-active-bg, rgba(37, 99, 235, 0.12))}.fast-button--disabled,.fast-button:disabled{opacity:0.6;cursor:not-allowed}`;
|
|
6458
6493
|
|
|
6459
|
-
class
|
|
6494
|
+
class FastButton {
|
|
6460
6495
|
constructor(hostRef) {
|
|
6461
6496
|
registerInstance(this, hostRef);
|
|
6462
6497
|
this.buttonClick = createEvent(this, "buttonClick");
|
|
6463
6498
|
}
|
|
6464
|
-
/**
|
|
6465
|
-
* Visual variant of the button.
|
|
6466
|
-
*/
|
|
6467
6499
|
variant = 'primary';
|
|
6468
|
-
|
|
6469
|
-
* Native button type (button or submit).
|
|
6470
|
-
*/
|
|
6471
|
-
type = 'button';
|
|
6472
|
-
/**
|
|
6473
|
-
* When true, the button is disabled and does not emit events.
|
|
6474
|
-
*/
|
|
6500
|
+
type = 'submit';
|
|
6475
6501
|
disabled = false;
|
|
6476
|
-
/**
|
|
6477
|
-
* Emitted when the button is clicked (not emitted when disabled).
|
|
6478
|
-
*/
|
|
6479
6502
|
buttonClick;
|
|
6480
6503
|
handleClick = (e) => {
|
|
6481
6504
|
if (this.disabled) {
|
|
@@ -6486,11 +6509,11 @@ class CustomButton {
|
|
|
6486
6509
|
this.buttonClick.emit(e);
|
|
6487
6510
|
};
|
|
6488
6511
|
render() {
|
|
6489
|
-
return (hAsync("button", { key: '
|
|
6490
|
-
'
|
|
6491
|
-
[`
|
|
6492
|
-
'
|
|
6493
|
-
}, disabled: this.disabled, onClick: this.handleClick }, hAsync("slot", { key: '
|
|
6512
|
+
return (hAsync("button", { key: 'b8e811748ade97c941bdf197a311d69d2801a120', type: this.type, class: {
|
|
6513
|
+
'fast-button': true,
|
|
6514
|
+
[`fast-button--${this.variant}`]: true,
|
|
6515
|
+
'fast-button--disabled': this.disabled,
|
|
6516
|
+
}, disabled: this.disabled, onClick: this.handleClick }, hAsync("slot", { key: 'a6b987059cc33799abd580ea11f0fe644a3973bf' })));
|
|
6494
6517
|
}
|
|
6495
6518
|
static get style() { return buttonCss(); }
|
|
6496
6519
|
static get cmpMeta() { return {
|
|
@@ -6507,6 +6530,213 @@ class CustomButton {
|
|
|
6507
6530
|
}; }
|
|
6508
6531
|
}
|
|
6509
6532
|
|
|
6533
|
+
const fastFormCss = () => `.fast-form{display:flex;gap:0.5rem;align-items:flex-start}`;
|
|
6534
|
+
|
|
6535
|
+
class FastForm {
|
|
6536
|
+
constructor(hostRef) {
|
|
6537
|
+
registerInstance(this, hostRef);
|
|
6538
|
+
this.searchExecuted = createEvent(this, "searchExecuted");
|
|
6539
|
+
}
|
|
6540
|
+
get el() { return getElement(this); }
|
|
6541
|
+
searchExecuted;
|
|
6542
|
+
handleInputSubmit() {
|
|
6543
|
+
this.submit();
|
|
6544
|
+
}
|
|
6545
|
+
async submit() {
|
|
6546
|
+
const inputs = this.el.querySelectorAll('fast-input');
|
|
6547
|
+
const params = {};
|
|
6548
|
+
for (const input of Array.from(inputs)) {
|
|
6549
|
+
const paramName = await input.getParamName();
|
|
6550
|
+
const value = await input.getValue();
|
|
6551
|
+
if (value) {
|
|
6552
|
+
params[paramName] = value;
|
|
6553
|
+
}
|
|
6554
|
+
}
|
|
6555
|
+
this.updateUrlParams(params);
|
|
6556
|
+
document.dispatchEvent(new CustomEvent('search-executed', {
|
|
6557
|
+
detail: params,
|
|
6558
|
+
bubbles: true,
|
|
6559
|
+
composed: true,
|
|
6560
|
+
}));
|
|
6561
|
+
this.searchExecuted.emit(params);
|
|
6562
|
+
}
|
|
6563
|
+
updateUrlParams(params) {
|
|
6564
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
6565
|
+
// Get all param names from inputs and clear them first
|
|
6566
|
+
const inputs = this.el.querySelectorAll('fast-input');
|
|
6567
|
+
for (const input of Array.from(inputs)) {
|
|
6568
|
+
const paramName = input.paramName;
|
|
6569
|
+
if (paramName) {
|
|
6570
|
+
urlParams.delete(paramName);
|
|
6571
|
+
}
|
|
6572
|
+
}
|
|
6573
|
+
// Set new values
|
|
6574
|
+
for (const [key, value] of Object.entries(params)) {
|
|
6575
|
+
if (value) {
|
|
6576
|
+
urlParams.set(key, value);
|
|
6577
|
+
}
|
|
6578
|
+
}
|
|
6579
|
+
const qs = urlParams.toString();
|
|
6580
|
+
const newUrl = qs
|
|
6581
|
+
? `${window.location.pathname}?${qs}`
|
|
6582
|
+
: window.location.pathname;
|
|
6583
|
+
history.pushState({}, '', newUrl);
|
|
6584
|
+
}
|
|
6585
|
+
handleFormSubmit = (e) => {
|
|
6586
|
+
e.preventDefault();
|
|
6587
|
+
this.submit();
|
|
6588
|
+
};
|
|
6589
|
+
render() {
|
|
6590
|
+
return (hAsync("form", { key: '50436bb904e8b175ae0c23158812a4e4756544c0', class: "fast-form", onSubmit: this.handleFormSubmit }, hAsync("slot", { key: '2f76c4c42c15ebf389d6e0fdbcb9a2098bf1156a' })));
|
|
6591
|
+
}
|
|
6592
|
+
static get style() { return fastFormCss(); }
|
|
6593
|
+
static get cmpMeta() { return {
|
|
6594
|
+
"$flags$": 260,
|
|
6595
|
+
"$tagName$": "fast-form",
|
|
6596
|
+
"$members$": undefined,
|
|
6597
|
+
"$listeners$": [[0, "inputSubmit", "handleInputSubmit"]],
|
|
6598
|
+
"$lazyBundleId$": "-",
|
|
6599
|
+
"$attrsToReflect$": []
|
|
6600
|
+
}; }
|
|
6601
|
+
}
|
|
6602
|
+
|
|
6603
|
+
const fastInputCss = () => `.fast-input{position:relative;display:inline-block}.fast-input__field{padding:0.5rem 0.75rem;font-size:1rem;border:1px solid #ccc;border-radius:4px;width:100%;box-sizing:border-box}.fast-input__dropdown{position:absolute;top:100%;left:0;right:0;margin:0;padding:0;list-style:none;background:#fff;border:1px solid #ccc;border-top:none;border-radius:0 0 4px 4px;z-index:100;max-height:200px;overflow-y:auto}.fast-input__dropdown-item{padding:0.5rem 0.75rem;cursor:pointer}.fast-input__dropdown-item:hover{background:#f0f0f0}.fast-input__dropdown-loading{padding:0.5rem 0.75rem;color:#999;font-style:italic}`;
|
|
6604
|
+
|
|
6605
|
+
class FastInput {
|
|
6606
|
+
constructor(hostRef) {
|
|
6607
|
+
registerInstance(this, hostRef);
|
|
6608
|
+
this.inputSubmit = createEvent(this, "inputSubmit");
|
|
6609
|
+
this.inputChanged = createEvent(this, "inputChanged");
|
|
6610
|
+
}
|
|
6611
|
+
placeholder = 'Search...';
|
|
6612
|
+
value = '';
|
|
6613
|
+
paramName = 'keyword';
|
|
6614
|
+
enableAutocomplete = false;
|
|
6615
|
+
autocompleteUrl = '/api/jobs/autocomplete';
|
|
6616
|
+
targetPath;
|
|
6617
|
+
debounceMs = 300;
|
|
6618
|
+
minChars = 3;
|
|
6619
|
+
inputSubmit;
|
|
6620
|
+
inputChanged;
|
|
6621
|
+
inputValue = '';
|
|
6622
|
+
suggestions = [];
|
|
6623
|
+
showDropdown = false;
|
|
6624
|
+
autocompleteLoading = false;
|
|
6625
|
+
debounceTimer;
|
|
6626
|
+
popstateHandler;
|
|
6627
|
+
async getValue() {
|
|
6628
|
+
return this.inputValue;
|
|
6629
|
+
}
|
|
6630
|
+
async getParamName() {
|
|
6631
|
+
return this.paramName;
|
|
6632
|
+
}
|
|
6633
|
+
connectedCallback() {
|
|
6634
|
+
const urlValue = this.getUrlParam();
|
|
6635
|
+
this.inputValue = urlValue !== null ? urlValue : this.value;
|
|
6636
|
+
this.popstateHandler = () => {
|
|
6637
|
+
this.inputValue = this.getUrlParam() ?? '';
|
|
6638
|
+
};
|
|
6639
|
+
window.addEventListener('popstate', this.popstateHandler);
|
|
6640
|
+
}
|
|
6641
|
+
disconnectedCallback() {
|
|
6642
|
+
window.removeEventListener('popstate', this.popstateHandler);
|
|
6643
|
+
clearTimeout(this.debounceTimer);
|
|
6644
|
+
}
|
|
6645
|
+
getUrlParam() {
|
|
6646
|
+
const params = new URLSearchParams(window.location.search);
|
|
6647
|
+
return params.get(this.paramName);
|
|
6648
|
+
}
|
|
6649
|
+
handleInput = (e) => {
|
|
6650
|
+
const value = e.target.value;
|
|
6651
|
+
this.inputValue = value;
|
|
6652
|
+
this.inputChanged.emit({ value });
|
|
6653
|
+
if (this.enableAutocomplete) {
|
|
6654
|
+
this.scheduleAutocomplete(value);
|
|
6655
|
+
}
|
|
6656
|
+
};
|
|
6657
|
+
handleKeydown = (e) => {
|
|
6658
|
+
if (e.key === 'Enter') {
|
|
6659
|
+
e.preventDefault();
|
|
6660
|
+
this.showDropdown = false;
|
|
6661
|
+
this.inputSubmit.emit();
|
|
6662
|
+
}
|
|
6663
|
+
else if (e.key === 'Escape') {
|
|
6664
|
+
this.showDropdown = false;
|
|
6665
|
+
}
|
|
6666
|
+
};
|
|
6667
|
+
handleBlur = () => {
|
|
6668
|
+
this.showDropdown = false;
|
|
6669
|
+
};
|
|
6670
|
+
scheduleAutocomplete(value) {
|
|
6671
|
+
clearTimeout(this.debounceTimer);
|
|
6672
|
+
if (value.length < this.minChars) {
|
|
6673
|
+
this.showDropdown = false;
|
|
6674
|
+
return;
|
|
6675
|
+
}
|
|
6676
|
+
this.debounceTimer = setTimeout(() => this.fetchSuggestions(value), this.debounceMs);
|
|
6677
|
+
}
|
|
6678
|
+
async fetchSuggestions(keyword) {
|
|
6679
|
+
if (!this.targetPath) {
|
|
6680
|
+
console.warn('[fast-input] target-path is required for autocomplete');
|
|
6681
|
+
return;
|
|
6682
|
+
}
|
|
6683
|
+
this.autocompleteLoading = true;
|
|
6684
|
+
this.showDropdown = true;
|
|
6685
|
+
try {
|
|
6686
|
+
const res = await fetch(this.autocompleteUrl, {
|
|
6687
|
+
method: 'POST',
|
|
6688
|
+
headers: { 'Content-Type': 'application/json' },
|
|
6689
|
+
body: JSON.stringify({ keyword, target_path: this.targetPath }),
|
|
6690
|
+
});
|
|
6691
|
+
if (!res.ok)
|
|
6692
|
+
throw new Error('autocomplete request failed');
|
|
6693
|
+
const data = await res.json();
|
|
6694
|
+
this.suggestions = data;
|
|
6695
|
+
}
|
|
6696
|
+
catch {
|
|
6697
|
+
this.showDropdown = false;
|
|
6698
|
+
this.suggestions = [];
|
|
6699
|
+
}
|
|
6700
|
+
finally {
|
|
6701
|
+
this.autocompleteLoading = false;
|
|
6702
|
+
}
|
|
6703
|
+
}
|
|
6704
|
+
selectSuggestion(title) {
|
|
6705
|
+
this.inputValue = title;
|
|
6706
|
+
this.showDropdown = false;
|
|
6707
|
+
this.inputSubmit.emit();
|
|
6708
|
+
}
|
|
6709
|
+
render() {
|
|
6710
|
+
return (hAsync("div", { key: 'ea03f3dd68d0da4fc30cbc18a1ef66b5974a4f89', class: "fast-input" }, hAsync("input", { key: '31d85c4c90dde0e10ea9424b960c5e4f4a3ca54a', type: "text", class: "fast-input__field", placeholder: this.placeholder, value: this.inputValue, onInput: this.handleInput, onKeyDown: this.handleKeydown, onBlur: this.handleBlur }), this.enableAutocomplete && this.showDropdown && (hAsync("ul", { key: '0de6fd68709d906bafd2fec684f0a73045be3705', class: "fast-input__dropdown" }, this.autocompleteLoading ? (hAsync("li", { class: "fast-input__dropdown-loading" }, "Loading...")) : (this.suggestions.map(s => (hAsync("li", { class: "fast-input__dropdown-item", onMouseDown: e => {
|
|
6711
|
+
e.preventDefault();
|
|
6712
|
+
}, onClick: () => this.selectSuggestion(s.title) }, s.title))))))));
|
|
6713
|
+
}
|
|
6714
|
+
static get style() { return fastInputCss(); }
|
|
6715
|
+
static get cmpMeta() { return {
|
|
6716
|
+
"$flags$": 512,
|
|
6717
|
+
"$tagName$": "fast-input",
|
|
6718
|
+
"$members$": {
|
|
6719
|
+
"placeholder": [1],
|
|
6720
|
+
"value": [1],
|
|
6721
|
+
"paramName": [1, "param-name"],
|
|
6722
|
+
"enableAutocomplete": [4, "enable-autocomplete"],
|
|
6723
|
+
"autocompleteUrl": [1, "autocomplete-url"],
|
|
6724
|
+
"targetPath": [1, "target-path"],
|
|
6725
|
+
"debounceMs": [2, "debounce-ms"],
|
|
6726
|
+
"minChars": [2, "min-chars"],
|
|
6727
|
+
"inputValue": [32],
|
|
6728
|
+
"suggestions": [32],
|
|
6729
|
+
"showDropdown": [32],
|
|
6730
|
+
"autocompleteLoading": [32],
|
|
6731
|
+
"getValue": [64],
|
|
6732
|
+
"getParamName": [64]
|
|
6733
|
+
},
|
|
6734
|
+
"$listeners$": undefined,
|
|
6735
|
+
"$lazyBundleId$": "-",
|
|
6736
|
+
"$attrsToReflect$": []
|
|
6737
|
+
}; }
|
|
6738
|
+
}
|
|
6739
|
+
|
|
6510
6740
|
const jobCardCss = () => `.job-card{display:block;padding:16px;border:1px solid #e0e0e0;border-radius:8px;background-color:#fff;box-shadow:0 2px 4px rgba(0, 0, 0, 0.08);transition:box-shadow 0.2s ease, border-color 0.2s ease}.job-card:hover{box-shadow:0 4px 8px rgba(0, 0, 0, 0.12);border-color:#d0d0d0}.job-card__header{margin-bottom:12px}.job-card__title{margin:0;font-size:18px;font-weight:700;display:flex;align-items:center;flex-wrap:wrap;gap:8px}.job-card__title--link{text-decoration:none;color:#1f9755;transition:color 0.2s ease}.job-card__title--link:hover{text-decoration:underline;color:#1a7a43}.job-card__reference{font-size:0.875em;color:#666;background-color:#f5f5f5;padding:2px 6px;border-radius:3px}.job-card__reference--empty{display:none}.job-card__remote{background:#e8f5e9;color:#2e7d32;border-radius:100px;padding:4px 12px;text-transform:uppercase;font-size:11px;font-weight:700;line-height:1.5;white-space:nowrap}.job-card__remote--empty{display:none}.job-card__distance{display:inline-flex;align-items:center;gap:4px;margin-top:6px;font-size:13px;font-weight:500;color:#555}.job-card__distance--icon{display:inline-flex;align-items:center}.job-card__distance--icon svg{width:16px;height:16px;color:#1f9755}.job-card__content{display:flex;align-items:flex-start;justify-content:space-between;gap:12px}.job-card__info{flex:1;display:flex;flex-direction:column;gap:8px}.job-card__street,.job-card__brand,.job-card__employment-type{display:flex;align-items:center;flex-wrap:wrap;gap:4px 6px;font-size:14px}.job-card__street--empty,.job-card__brand--empty,.job-card__employment-type--empty{color:#999}.job-card__street--icon,.job-card__brand--icon,.job-card__employment-type--icon{display:inline-flex;align-items:center;flex-shrink:0}.job-card__street--icon svg,.job-card__brand--icon svg,.job-card__employment-type--icon svg{width:16px;height:16px;color:#666}.job-card__street--label,.job-card__brand--label,.job-card__employment-type--label{color:#333}.job-card__street--label__wrapper{display:flex;align-items:center;gap:6px}.job-card__street--more-locations__wrapper{display:flex;align-items:center;gap:2px;font-size:12px;margin-left:2px}.job-card__street--amount{font-weight:600;color:#1f9755}.job-card__street--more-locations{color:#999}.job-card__apply{display:inline-flex;align-items:center;justify-content:center;gap:6px;padding:10px 16px;background-color:#198754;color:#fff;border-radius:4px;text-decoration:none;font-weight:600;font-size:14px;transition:background-color 0.2s ease, transform 0.1s ease;white-space:nowrap;flex-shrink:0}.job-card__apply:hover{background-color:#1a6f47;transform:translateY(-1px)}.job-card__apply:active{transform:translateY(0)}.job-card__apply--icon{display:inline-flex;align-items:center}.job-card__apply--icon svg{width:14px;height:14px}@media (max-width: 768px){.job-card{padding:12px}.job-card__content{flex-direction:column;gap:10px}.job-card__apply{width:100%;justify-content:center}.job-card__title{font-size:16px}}@media (max-width: 480px){.job-card{padding:10px}.job-card__title{font-size:15px}.job-card__distance{font-size:12px}.job-card__street,.job-card__brand,.job-card__employment-type{font-size:13px}}`;
|
|
6511
6741
|
|
|
6512
6742
|
/**
|
|
@@ -6829,6 +7059,7 @@ const defaultNoResultsLine2 = 'Please refine your keywords in the search bar abo
|
|
|
6829
7059
|
class JobsListOnly {
|
|
6830
7060
|
constructor(hostRef) {
|
|
6831
7061
|
registerInstance(this, hostRef);
|
|
7062
|
+
this.fetchComplete = createEvent(this, "fetchComplete");
|
|
6832
7063
|
}
|
|
6833
7064
|
/**
|
|
6834
7065
|
* When "true", use built-in mock data (for local/dev/docs). Otherwise use `jobs` from API/parent.
|
|
@@ -6852,16 +7083,84 @@ class JobsListOnly {
|
|
|
6852
7083
|
enableKilometers = false;
|
|
6853
7084
|
/** Extra CSS class on the root element (avoid prop name "class" / "classname" reserved). */
|
|
6854
7085
|
rootClass = '';
|
|
7086
|
+
/** Template string for count display. Tokens: {count} = jobs on page, {total} = total from API. */
|
|
7087
|
+
showCountText = '';
|
|
6855
7088
|
showSuggestions = false;
|
|
6856
7089
|
clearResultSuggestionsTitleText = 'Suggestions';
|
|
6857
7090
|
clearResultSuggestionsLine1 = 'Try different keywords';
|
|
6858
7091
|
clearResultSuggestionsLine2 = 'Make sure everything is spelled correctly';
|
|
6859
7092
|
clearResultSuggestionsLine3 = 'Try other locations';
|
|
6860
7093
|
clearResultSuggestionsLine4 = '';
|
|
7094
|
+
/** When true, component manages its own data fetching */
|
|
7095
|
+
autoFetch = false;
|
|
7096
|
+
/** Jobs search endpoint */
|
|
7097
|
+
apiUrl = '/api/get-jobs';
|
|
7098
|
+
/** Comma-separated URL param names to watch and forward to the API */
|
|
7099
|
+
watchParams = 'keyword';
|
|
7100
|
+
fetchedJobs = [];
|
|
7101
|
+
fetchedTotal = 0;
|
|
7102
|
+
fetchLoading = false;
|
|
7103
|
+
fetchComplete;
|
|
7104
|
+
searchExecutedHandler;
|
|
7105
|
+
popstateHandler;
|
|
7106
|
+
connectedCallback() {
|
|
7107
|
+
if (this.autoFetch) {
|
|
7108
|
+
this.fetchJobs();
|
|
7109
|
+
this.searchExecutedHandler = () => this.fetchJobs();
|
|
7110
|
+
this.popstateHandler = () => this.fetchJobs();
|
|
7111
|
+
document.addEventListener('search-executed', this.searchExecutedHandler);
|
|
7112
|
+
window.addEventListener('popstate', this.popstateHandler);
|
|
7113
|
+
}
|
|
7114
|
+
}
|
|
7115
|
+
disconnectedCallback() {
|
|
7116
|
+
if (this.autoFetch) {
|
|
7117
|
+
document.removeEventListener('search-executed', this.searchExecutedHandler);
|
|
7118
|
+
window.removeEventListener('popstate', this.popstateHandler);
|
|
7119
|
+
}
|
|
7120
|
+
}
|
|
7121
|
+
async fetchJobs() {
|
|
7122
|
+
this.fetchLoading = true;
|
|
7123
|
+
const params = new URLSearchParams(window.location.search);
|
|
7124
|
+
const watchList = this.watchParams.split(',').map(p => p.trim()).filter(Boolean);
|
|
7125
|
+
const query = new URLSearchParams();
|
|
7126
|
+
for (const key of watchList) {
|
|
7127
|
+
const val = params.get(key);
|
|
7128
|
+
if (val !== null)
|
|
7129
|
+
query.set(key, val);
|
|
7130
|
+
}
|
|
7131
|
+
const url = `${this.apiUrl}?${query.toString()}`;
|
|
7132
|
+
try {
|
|
7133
|
+
const res = await fetch(url, {
|
|
7134
|
+
method: 'POST',
|
|
7135
|
+
headers: { 'Content-Type': 'application/json' },
|
|
7136
|
+
body: JSON.stringify({ disable_switch_search_mode: false }),
|
|
7137
|
+
});
|
|
7138
|
+
if (!res.ok)
|
|
7139
|
+
throw new Error('fetch failed');
|
|
7140
|
+
const data = await res.json();
|
|
7141
|
+
this.fetchedJobs = data.jobs;
|
|
7142
|
+
this.fetchedTotal = data.totalJob;
|
|
7143
|
+
this.fetchComplete.emit({ jobs: data.jobs, totalJob: data.totalJob });
|
|
7144
|
+
}
|
|
7145
|
+
catch {
|
|
7146
|
+
// preserve stale data, just stop loading
|
|
7147
|
+
}
|
|
7148
|
+
finally {
|
|
7149
|
+
this.fetchLoading = false;
|
|
7150
|
+
}
|
|
7151
|
+
}
|
|
7152
|
+
renderCountText(count, total) {
|
|
7153
|
+
return this.showCountText
|
|
7154
|
+
.replace('{count}', String(count))
|
|
7155
|
+
.replace('{total}', String(total));
|
|
7156
|
+
}
|
|
6861
7157
|
getJobsArray() {
|
|
6862
7158
|
if (this.mockData) {
|
|
6863
7159
|
return mockJobsListOnly;
|
|
6864
7160
|
}
|
|
7161
|
+
if (this.autoFetch) {
|
|
7162
|
+
return this.fetchedJobs;
|
|
7163
|
+
}
|
|
6865
7164
|
const j = this.jobs;
|
|
6866
7165
|
if (Array.isArray(j))
|
|
6867
7166
|
return j;
|
|
@@ -6881,11 +7180,15 @@ class JobsListOnly {
|
|
|
6881
7180
|
}
|
|
6882
7181
|
render() {
|
|
6883
7182
|
const jobsArray = this.getJobsArray();
|
|
6884
|
-
const loading = this.mockData ? false : this.loading;
|
|
6885
|
-
const totalJob = this.mockData
|
|
7183
|
+
const loading = this.mockData ? false : (this.autoFetch ? this.fetchLoading : this.loading);
|
|
7184
|
+
const totalJob = this.mockData
|
|
7185
|
+
? jobsArray.length
|
|
7186
|
+
: this.autoFetch
|
|
7187
|
+
? this.fetchedTotal
|
|
7188
|
+
: (this.totalJob || jobsArray.length);
|
|
6886
7189
|
const showNoResults = !loading && totalJob === 0 && !this.showSuggestions;
|
|
6887
7190
|
const showSuggestionsBlock = !loading && totalJob === 0 && this.showSuggestions;
|
|
6888
|
-
return (hAsync("div", { key: '
|
|
7191
|
+
return (hAsync("div", { key: '1974ecb7e1ded8237d851560fc4b20dd63b4e941', class: `jobs-list-root ${this.rootClass}`.trim() }, hAsync("div", { key: '3d80283e8508cbe9ec4aa4516a6f832479374e08', class: "results-container" }, this.autoFetch && this.fetchLoading && (hAsync("div", { key: 'c5d3c5362a10ce2442925093118d3436227e8058', class: "jobs-list-only__loading" }, "Loading...")), hAsync("div", { key: 'c68e5aebee17cce16947029031b63364ab25ecda', class: loading ? 'loader' : 'loader hide', "aria-hidden": !loading }), totalJob > 0 && this.showCountText && (hAsync("p", { key: 'e353fa146040fed1aed050ed3ed833903efcdf41', class: "jobs-list-only__count" }, this.renderCountText(jobsArray.length, totalJob))), totalJob > 0 && (hAsync("div", { key: 'e38346f641a1e776a7e70525bf8f3a6a38b6eea5', class: "card" }, hAsync("ul", { key: 'db82d99df76e33ad6041d4ec8dd7908cdf8b89d7', class: "results-list front" }, jobsArray.map((job, index) => this.renderJobItem(job, index))))), showNoResults && (hAsync("div", { key: '8bd8f45ddb9fcd534c7f386919c1e6cd7a4fb6f3', class: "share-jobs__no-results" }, hAsync("h2", { key: '228d32e9dd38f61bcec9f522d3bc4207e17b5365' }, this.noResultsLine1), hAsync("h3", { key: '4289b10974936669a00afba6f1d55e33874198b1' }, this.noResultsLine2))), showSuggestionsBlock && (hAsync("div", { key: '949e1fe01b2db39a69729a9fbc2eebaf2ea461ba', class: "card primary-color" }, hAsync("h4", { key: 'af3361f98987a3a19d45afc1174a99fc4174a65a', class: "result-suggestions-title" }, this.clearResultSuggestionsTitleText, ":"), hAsync("ul", { key: 'd7b9236dbbeb9f9596d642aa588d1c1305ed658b', class: "results-list front" }, hAsync("li", { key: '0e65c9b985e5708096c8a4b0ea1455b6696db6dd', class: "result-suggestions-line" }, this.clearResultSuggestionsLine1), hAsync("li", { key: 'a7fe8459960af60acc81822b48436a32c0e4ad0c', class: "result-suggestions-line" }, this.clearResultSuggestionsLine2), hAsync("li", { key: '1e41d5730de755d6b2cb9e5fbda33704816f9096', class: "result-suggestions-line" }, this.clearResultSuggestionsLine3), this.clearResultSuggestionsLine4 && (hAsync("li", { key: '9ab1bee87135bfda9996b2c99134597475bfaecb', class: "result-suggestions-line" }, this.clearResultSuggestionsLine4))))))));
|
|
6889
7192
|
}
|
|
6890
7193
|
static get style() { return jobsListOnlyCss(); }
|
|
6891
7194
|
static get cmpMeta() { return {
|
|
@@ -6907,12 +7210,136 @@ class JobsListOnly {
|
|
|
6907
7210
|
"remoteLocationText": [1, "remote-location-text"],
|
|
6908
7211
|
"enableKilometers": [4, "enable-kilometers"],
|
|
6909
7212
|
"rootClass": [1, "root-class"],
|
|
7213
|
+
"showCountText": [1, "show-count-text"],
|
|
6910
7214
|
"showSuggestions": [4, "show-suggestions"],
|
|
6911
7215
|
"clearResultSuggestionsTitleText": [1, "clear-result-suggestions-title-text"],
|
|
6912
7216
|
"clearResultSuggestionsLine1": [1, "clear-result-suggestions-line-1"],
|
|
6913
7217
|
"clearResultSuggestionsLine2": [1, "clear-result-suggestions-line-2"],
|
|
6914
7218
|
"clearResultSuggestionsLine3": [1, "clear-result-suggestions-line-3"],
|
|
6915
|
-
"clearResultSuggestionsLine4": [1, "clear-result-suggestions-line-4"]
|
|
7219
|
+
"clearResultSuggestionsLine4": [1, "clear-result-suggestions-line-4"],
|
|
7220
|
+
"autoFetch": [4, "auto-fetch"],
|
|
7221
|
+
"apiUrl": [1, "api-url"],
|
|
7222
|
+
"watchParams": [1, "watch-params"],
|
|
7223
|
+
"fetchedJobs": [32],
|
|
7224
|
+
"fetchedTotal": [32],
|
|
7225
|
+
"fetchLoading": [32]
|
|
7226
|
+
},
|
|
7227
|
+
"$listeners$": undefined,
|
|
7228
|
+
"$lazyBundleId$": "-",
|
|
7229
|
+
"$attrsToReflect$": []
|
|
7230
|
+
}; }
|
|
7231
|
+
}
|
|
7232
|
+
|
|
7233
|
+
const jobsListReactiveCss = () => `jobs-list-reactive{display:block}jobs-list-reactive.loading{opacity:0.6;pointer-events:none}`;
|
|
7234
|
+
|
|
7235
|
+
class JobsListReactive {
|
|
7236
|
+
constructor(hostRef) {
|
|
7237
|
+
registerInstance(this, hostRef);
|
|
7238
|
+
this.fetchComplete = createEvent(this, "fetchComplete");
|
|
7239
|
+
}
|
|
7240
|
+
get el() { return getElement(this); }
|
|
7241
|
+
/** Jobs search endpoint */
|
|
7242
|
+
apiUrl = '/api/get-jobs';
|
|
7243
|
+
/** Comma-separated URL param names to watch and forward to the API */
|
|
7244
|
+
watchParams = 'keyword,location_name';
|
|
7245
|
+
/** CSS class added to container while fetching */
|
|
7246
|
+
loadingClass = 'loading';
|
|
7247
|
+
isLoading = false;
|
|
7248
|
+
fetchComplete;
|
|
7249
|
+
templateEl = null;
|
|
7250
|
+
searchExecutedHandler;
|
|
7251
|
+
popstateHandler;
|
|
7252
|
+
connectedCallback() {
|
|
7253
|
+
this.templateEl = this.el.querySelector('template');
|
|
7254
|
+
this.searchExecutedHandler = () => this.fetchJobs();
|
|
7255
|
+
this.popstateHandler = () => this.fetchJobs();
|
|
7256
|
+
document.addEventListener('search-executed', this.searchExecutedHandler);
|
|
7257
|
+
window.addEventListener('popstate', this.popstateHandler);
|
|
7258
|
+
}
|
|
7259
|
+
disconnectedCallback() {
|
|
7260
|
+
document.removeEventListener('search-executed', this.searchExecutedHandler);
|
|
7261
|
+
window.removeEventListener('popstate', this.popstateHandler);
|
|
7262
|
+
}
|
|
7263
|
+
buildQueryString() {
|
|
7264
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
7265
|
+
const watchList = this.watchParams.split(',').map(p => p.trim()).filter(Boolean);
|
|
7266
|
+
const query = new URLSearchParams();
|
|
7267
|
+
for (const key of watchList) {
|
|
7268
|
+
const val = urlParams.get(key);
|
|
7269
|
+
if (val !== null && val !== '') {
|
|
7270
|
+
query.set(key, val);
|
|
7271
|
+
}
|
|
7272
|
+
}
|
|
7273
|
+
return query.toString();
|
|
7274
|
+
}
|
|
7275
|
+
async fetchJobs() {
|
|
7276
|
+
this.isLoading = true;
|
|
7277
|
+
this.el.classList.add(this.loadingClass);
|
|
7278
|
+
const queryString = this.buildQueryString();
|
|
7279
|
+
const url = queryString ? `${this.apiUrl}?${queryString}` : this.apiUrl;
|
|
7280
|
+
try {
|
|
7281
|
+
const res = await fetch(url, {
|
|
7282
|
+
method: 'POST',
|
|
7283
|
+
headers: { 'Content-Type': 'application/json' },
|
|
7284
|
+
body: JSON.stringify({ disable_switch_search_mode: false }),
|
|
7285
|
+
});
|
|
7286
|
+
if (!res.ok)
|
|
7287
|
+
throw new Error('fetch failed');
|
|
7288
|
+
const data = await res.json();
|
|
7289
|
+
this.renderJobs(data.jobs);
|
|
7290
|
+
this.updateCountElements(data.jobs.length, data.totalJob);
|
|
7291
|
+
this.fetchComplete.emit({ jobs: data.jobs, totalJob: data.totalJob });
|
|
7292
|
+
}
|
|
7293
|
+
catch {
|
|
7294
|
+
// Preserve stale data on error
|
|
7295
|
+
}
|
|
7296
|
+
finally {
|
|
7297
|
+
this.isLoading = false;
|
|
7298
|
+
this.el.classList.remove(this.loadingClass);
|
|
7299
|
+
}
|
|
7300
|
+
}
|
|
7301
|
+
renderJobs(jobs) {
|
|
7302
|
+
if (!this.templateEl)
|
|
7303
|
+
return;
|
|
7304
|
+
// Remove all children except the template
|
|
7305
|
+
const children = Array.from(this.el.children);
|
|
7306
|
+
for (const child of children) {
|
|
7307
|
+
if (child !== this.templateEl) {
|
|
7308
|
+
child.remove();
|
|
7309
|
+
}
|
|
7310
|
+
}
|
|
7311
|
+
// Clone template and render each job
|
|
7312
|
+
for (const job of jobs) {
|
|
7313
|
+
const clone = this.templateEl.content.cloneNode(true);
|
|
7314
|
+
const jobCard = clone.querySelector('job-card');
|
|
7315
|
+
if (jobCard) {
|
|
7316
|
+
jobCard.setAttribute('job', JSON.stringify(job));
|
|
7317
|
+
}
|
|
7318
|
+
this.el.appendChild(clone);
|
|
7319
|
+
}
|
|
7320
|
+
}
|
|
7321
|
+
updateCountElements(count, total) {
|
|
7322
|
+
const countEls = document.querySelectorAll('[data-job-count]');
|
|
7323
|
+
const totalEls = document.querySelectorAll('[data-job-total]');
|
|
7324
|
+
countEls.forEach(el => {
|
|
7325
|
+
el.textContent = String(count);
|
|
7326
|
+
});
|
|
7327
|
+
totalEls.forEach(el => {
|
|
7328
|
+
el.textContent = String(total);
|
|
7329
|
+
});
|
|
7330
|
+
}
|
|
7331
|
+
render() {
|
|
7332
|
+
return hAsync("slot", { key: '9f3ab802e19a298a790cfb5e86a4f4888e466804' });
|
|
7333
|
+
}
|
|
7334
|
+
static get style() { return jobsListReactiveCss(); }
|
|
7335
|
+
static get cmpMeta() { return {
|
|
7336
|
+
"$flags$": 772,
|
|
7337
|
+
"$tagName$": "jobs-list-reactive",
|
|
7338
|
+
"$members$": {
|
|
7339
|
+
"apiUrl": [1, "api-url"],
|
|
7340
|
+
"watchParams": [1, "watch-params"],
|
|
7341
|
+
"loadingClass": [1, "loading-class"],
|
|
7342
|
+
"isLoading": [32]
|
|
6916
7343
|
},
|
|
6917
7344
|
"$listeners$": undefined,
|
|
6918
7345
|
"$lazyBundleId$": "-",
|
|
@@ -6922,10 +7349,13 @@ class JobsListOnly {
|
|
|
6922
7349
|
|
|
6923
7350
|
registerComponents([
|
|
6924
7351
|
AppCarousel,
|
|
6925
|
-
|
|
7352
|
+
FastButton,
|
|
7353
|
+
FastForm,
|
|
7354
|
+
FastInput,
|
|
6926
7355
|
JobCard,
|
|
6927
7356
|
JobsItem,
|
|
6928
7357
|
JobsListOnly,
|
|
7358
|
+
JobsListReactive,
|
|
6929
7359
|
]);
|
|
6930
7360
|
|
|
6931
7361
|
exports.hydrateApp = hydrateApp;
|