@sneat/components 0.1.3 → 0.1.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.
- package/esm2022/index.js +15 -0
- package/esm2022/index.js.map +1 -0
- package/esm2022/lib/app-version/app-version.component.js +16 -0
- package/esm2022/lib/app-version/app-version.component.js.map +1 -0
- package/esm2022/lib/app-version/build-info.js +5 -0
- package/esm2022/lib/app-version/build-info.js.map +1 -0
- package/esm2022/lib/app-version/index.js +3 -0
- package/esm2022/lib/app-version/index.js.map +1 -0
- package/esm2022/lib/card-list/index.js +2 -0
- package/esm2022/lib/card-list/index.js.map +1 -0
- package/esm2022/lib/card-list/sneat-card-list.component.js +106 -0
- package/esm2022/lib/card-list/sneat-card-list.component.js.map +1 -0
- package/esm2022/lib/copyright/copyright.component.js +11 -0
- package/esm2022/lib/copyright/copyright.component.js.map +1 -0
- package/esm2022/lib/copyright/index.js +2 -0
- package/esm2022/lib/copyright/index.js.map +1 -0
- package/esm2022/lib/country-input/country-input.component.js +59 -0
- package/esm2022/lib/country-input/country-input.component.js.map +1 -0
- package/esm2022/lib/country-input/index.js +2 -0
- package/esm2022/lib/country-input/index.js.map +1 -0
- package/esm2022/lib/country-selector/countries-loader.service.js +91 -0
- package/esm2022/lib/country-selector/countries-loader.service.js.map +1 -0
- package/esm2022/lib/country-selector/countries.js +22 -0
- package/esm2022/lib/country-selector/countries.js.map +1 -0
- package/esm2022/lib/country-selector/country-selector.component.js +103 -0
- package/esm2022/lib/country-selector/country-selector.component.js.map +1 -0
- package/esm2022/lib/country-selector/country-selector.service.js +15 -0
- package/esm2022/lib/country-selector/country-selector.service.js.map +1 -0
- package/esm2022/lib/country-selector/index.js +5 -0
- package/esm2022/lib/country-selector/index.js.map +1 -0
- package/esm2022/lib/date-input/date-input.component.js +70 -0
- package/esm2022/lib/date-input/date-input.component.js.map +1 -0
- package/esm2022/lib/date-input/date-modal.component.js +53 -0
- package/esm2022/lib/date-input/date-modal.component.js.map +1 -0
- package/esm2022/lib/dialog-header/dialog-header.component.js +23 -0
- package/esm2022/lib/dialog-header/dialog-header.component.js.map +1 -0
- package/esm2022/lib/dialog-header/index.js +2 -0
- package/esm2022/lib/dialog-header/index.js.map +1 -0
- package/esm2022/lib/error-card/index.js +2 -0
- package/esm2022/lib/error-card/index.js.map +1 -0
- package/esm2022/lib/error-card/sneat-error-card.component.js +23 -0
- package/esm2022/lib/error-card/sneat-error-card.component.js.map +1 -0
- package/esm2022/lib/filter-item/filter-item.component.js +37 -0
- package/esm2022/lib/filter-item/filter-item.component.js.map +1 -0
- package/esm2022/lib/filter-item/index.js +2 -0
- package/esm2022/lib/filter-item/index.js.map +1 -0
- package/esm2022/lib/pipes/country-emoji.pipe.js +69 -0
- package/esm2022/lib/pipes/country-emoji.pipe.js.map +1 -0
- package/esm2022/lib/pipes/decimal64p2.pipe.js +47 -0
- package/esm2022/lib/pipes/decimal64p2.pipe.js.map +1 -0
- package/esm2022/lib/pipes/gender.pipes.js +69 -0
- package/esm2022/lib/pipes/gender.pipes.js.map +1 -0
- package/esm2022/lib/pipes/index.js +7 -0
- package/esm2022/lib/pipes/index.js.map +1 -0
- package/esm2022/lib/pipes/long-month-name.pipe.js +41 -0
- package/esm2022/lib/pipes/long-month-name.pipe.js.map +1 -0
- package/esm2022/lib/pipes/short-month-name.pipe.js +31 -0
- package/esm2022/lib/pipes/short-month-name.pipe.js.map +1 -0
- package/esm2022/lib/pipes/team-emoji.pipe.js +31 -0
- package/esm2022/lib/pipes/team-emoji.pipe.js.map +1 -0
- package/esm2022/lib/save-event.js +2 -0
- package/esm2022/lib/save-event.js.map +1 -0
- package/esm2022/lib/user-country/user-country.component.js +136 -0
- package/esm2022/lib/user-country/user-country.component.js.map +1 -0
- package/esm2022/lib/virtual-slider/virtual-slider.js +83 -0
- package/esm2022/lib/virtual-slider/virtual-slider.js.map +1 -0
- package/esm2022/sneat-components.js +5 -0
- package/esm2022/sneat-components.js.map +1 -0
- package/lib/app-version/app-version.component.d.ts +9 -0
- package/lib/app-version/build-info.d.ts +4 -0
- package/lib/card-list/sneat-card-list.component.d.ts +43 -0
- package/lib/copyright/copyright.component.d.ts +5 -0
- package/lib/country-input/country-input.component.d.ts +16 -0
- package/lib/country-selector/countries-loader.service.d.ts +43 -0
- package/lib/country-selector/countries.d.ts +25 -0
- package/lib/country-selector/country-selector.component.d.ts +31 -0
- package/lib/country-selector/country-selector.service.d.ts +8 -0
- package/lib/date-input/date-input.component.d.ts +21 -0
- package/lib/date-input/date-modal.component.d.ts +13 -0
- package/lib/dialog-header/dialog-header.component.d.ts +8 -0
- package/lib/error-card/sneat-error-card.component.d.ts +8 -0
- package/lib/filter-item/filter-item.component.d.ts +13 -0
- package/lib/pipes/country-emoji.pipe.d.ts +29 -0
- package/lib/pipes/decimal64p2.pipe.d.ts +12 -0
- package/lib/pipes/gender.pipes.d.ts +20 -0
- package/lib/pipes/long-month-name.pipe.d.ts +7 -0
- package/lib/pipes/short-month-name.pipe.d.ts +8 -0
- package/lib/pipes/team-emoji.pipe.d.ts +8 -0
- package/lib/save-event.d.ts +5 -0
- package/lib/user-country/user-country.component.d.ts +24 -0
- package/lib/virtual-slider/virtual-slider.d.ts +13 -0
- package/package.json +14 -2
- package/sneat-components.d.ts +5 -0
- package/eslint.config.js +0 -7
- package/ng-package.json +0 -10
- package/project.json +0 -38
- package/src/assets/data/countries.json +0 -1730
- package/src/lib/app-version/app-version.component.html +0 -15
- package/src/lib/app-version/app-version.component.spec.ts +0 -25
- package/src/lib/app-version/app-version.component.ts +0 -17
- package/src/lib/app-version/build-info.ts +0 -8
- package/src/lib/card-list/sneat-card-list.component.html +0 -108
- package/src/lib/card-list/sneat-card-list.component.spec.ts +0 -131
- package/src/lib/card-list/sneat-card-list.component.ts +0 -125
- package/src/lib/copyright/copyright.component.html +0 -1
- package/src/lib/copyright/copyright.component.spec.ts +0 -24
- package/src/lib/copyright/copyright.component.ts +0 -7
- package/src/lib/country-input/country-input.component.html +0 -33
- package/src/lib/country-input/country-input.component.spec.ts +0 -84
- package/src/lib/country-input/country-input.component.ts +0 -76
- package/src/lib/country-selector/countries-loader.service.spec.ts +0 -149
- package/src/lib/country-selector/countries-loader.service.ts +0 -100
- package/src/lib/country-selector/countries.ts +0 -42
- package/src/lib/country-selector/country-selector.component.html +0 -24
- package/src/lib/country-selector/country-selector.component.spec.ts +0 -5
- package/src/lib/country-selector/country-selector.component.ts +0 -125
- package/src/lib/country-selector/country-selector.service.spec.ts +0 -23
- package/src/lib/country-selector/country-selector.service.ts +0 -11
- package/src/lib/date-input/date-input.component.html +0 -39
- package/src/lib/date-input/date-input.component.spec.ts +0 -179
- package/src/lib/date-input/date-input.component.ts +0 -97
- package/src/lib/date-input/date-modal.component.html +0 -23
- package/src/lib/date-input/date-modal.component.spec.ts +0 -105
- package/src/lib/date-input/date-modal.component.ts +0 -67
- package/src/lib/dialog-header/dialog-header.component.html +0 -8
- package/src/lib/dialog-header/dialog-header.component.spec.ts +0 -67
- package/src/lib/dialog-header/dialog-header.component.ts +0 -26
- package/src/lib/dismissable.ts +0 -6
- package/src/lib/error-card/sneat-error-card.component.html +0 -20
- package/src/lib/error-card/sneat-error-card.component.spec.ts +0 -49
- package/src/lib/error-card/sneat-error-card.component.ts +0 -28
- package/src/lib/filter-item/filter-item.component.html +0 -19
- package/src/lib/filter-item/filter-item.component.spec.ts +0 -83
- package/src/lib/filter-item/filter-item.component.ts +0 -47
- package/src/lib/pipes/country-emoji.pipe.spec.ts +0 -116
- package/src/lib/pipes/country-emoji.pipe.ts +0 -67
- package/src/lib/pipes/decimal64p2.pipe.spec.ts +0 -61
- package/src/lib/pipes/decimal64p2.pipe.ts +0 -35
- package/src/lib/pipes/gender.pipes.spec.ts +0 -84
- package/src/lib/pipes/gender.pipes.ts +0 -65
- package/src/lib/pipes/long-month-name.pipe.spec.ts +0 -36
- package/src/lib/pipes/long-month-name.pipe.ts +0 -35
- package/src/lib/pipes/short-month-name.pipe.spec.ts +0 -28
- package/src/lib/pipes/short-month-name.pipe.ts +0 -26
- package/src/lib/pipes/team-emoji.pipe.spec.ts +0 -27
- package/src/lib/pipes/team-emoji.pipe.ts +0 -26
- package/src/lib/save-event.ts +0 -5
- package/src/lib/test-ide-bug.ts +0 -24
- package/src/lib/user-country/user-country.component.html +0 -44
- package/src/lib/user-country/user-country.component.spec.ts +0 -136
- package/src/lib/user-country/user-country.component.ts +0 -172
- package/src/lib/virtual-slider/odd-even-virtual-slider.ts +0 -1
- package/src/lib/virtual-slider/virtual-slider.ts +0 -130
- package/src/lib/webstorm-type-err-demo.component.ts +0 -35
- package/src/test-setup.ts +0 -3
- package/tsconfig.json +0 -13
- package/tsconfig.lib.json +0 -19
- package/tsconfig.lib.prod.json +0 -7
- package/tsconfig.spec.json +0 -31
- package/vite.config.mts +0 -10
- /package/{src/index.ts → index.d.ts} +0 -0
- /package/{src/lib/app-version/index.ts → lib/app-version/index.d.ts} +0 -0
- /package/{src/lib/card-list/index.ts → lib/card-list/index.d.ts} +0 -0
- /package/{src/lib/copyright/index.ts → lib/copyright/index.d.ts} +0 -0
- /package/{src/lib/country-input/index.ts → lib/country-input/index.d.ts} +0 -0
- /package/{src/lib/country-selector/index.ts → lib/country-selector/index.d.ts} +0 -0
- /package/{src/lib/dialog-header/index.ts → lib/dialog-header/index.d.ts} +0 -0
- /package/{src/lib/error-card/index.ts → lib/error-card/index.d.ts} +0 -0
- /package/{src/lib/filter-item/index.ts → lib/filter-item/index.d.ts} +0 -0
- /package/{src/lib/pipes/index.ts → lib/pipes/index.d.ts} +0 -0
package/esm2022/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export * from './lib/app-version';
|
|
2
|
+
export * from './lib/pipes';
|
|
3
|
+
export * from './lib/virtual-slider/virtual-slider';
|
|
4
|
+
export * from './lib/card-list';
|
|
5
|
+
export * from './lib/error-card';
|
|
6
|
+
export * from './lib/country-selector';
|
|
7
|
+
export * from './lib/filter-item';
|
|
8
|
+
export * from './lib/copyright';
|
|
9
|
+
export * from './lib/dialog-header';
|
|
10
|
+
export * from './lib/country-input';
|
|
11
|
+
export * from './lib/save-event';
|
|
12
|
+
export * from './lib/date-input/date-input.component';
|
|
13
|
+
export * from './lib/user-country/user-country.component';
|
|
14
|
+
export * from './lib/card-list/sneat-card-list.component';
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../libs/components/src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,aAAa,CAAC;AAC5B,cAAc,qCAAqC,CAAC;AACpD,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,kBAAkB,CAAC;AACjC,cAAc,uCAAuC,CAAC;AACtD,cAAc,2CAA2C,CAAC;AAC1D,cAAc,2CAA2C,CAAC","sourcesContent":["export * from './lib/app-version';\nexport * from './lib/pipes';\nexport * from './lib/virtual-slider/virtual-slider';\nexport * from './lib/card-list';\nexport * from './lib/error-card';\nexport * from './lib/country-selector';\nexport * from './lib/filter-item';\nexport * from './lib/copyright';\nexport * from './lib/dialog-header';\nexport * from './lib/country-input';\nexport * from './lib/save-event';\nexport * from './lib/date-input/date-input.component';\nexport * from './lib/user-country/user-country.component';\nexport * from './lib/card-list/sneat-card-list.component';\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import { IonInput, IonItem, IonItemDivider, IonLabel, } from '@ionic/angular/standalone';
|
|
3
|
+
import { buildInfo } from './build-info';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
export class AppVersionComponent {
|
|
6
|
+
constructor() {
|
|
7
|
+
this.buildInfo = buildInfo;
|
|
8
|
+
}
|
|
9
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AppVersionComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
10
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.0", type: AppVersionComponent, isStandalone: true, selector: "sneat-app-version", ngImport: i0, template: "<ion-item-divider color=\"light\">\n <ion-label>App version</ion-label>\n</ion-item-divider>\n<ion-item>\n <ion-input\n label=\"Build:\"\n color=\"medium\"\n readonly=\"true\"\n disabled=\"true\"\n [value]=\"\n buildInfo.gitHash.substring(0, 7) + ' @ ' + buildInfo.buildTimestamp\n \"\n [title]=\"buildInfo.gitHash\"\n />\n</ion-item>\n", dependencies: [{ kind: "component", type: IonItemDivider, selector: "ion-item-divider", inputs: ["color", "mode", "sticky"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }] }); }
|
|
11
|
+
}
|
|
12
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: AppVersionComponent, decorators: [{
|
|
13
|
+
type: Component,
|
|
14
|
+
args: [{ selector: 'sneat-app-version', imports: [IonItemDivider, IonLabel, IonItem, IonInput], template: "<ion-item-divider color=\"light\">\n <ion-label>App version</ion-label>\n</ion-item-divider>\n<ion-item>\n <ion-input\n label=\"Build:\"\n color=\"medium\"\n readonly=\"true\"\n disabled=\"true\"\n [value]=\"\n buildInfo.gitHash.substring(0, 7) + ' @ ' + buildInfo.buildTimestamp\n \"\n [title]=\"buildInfo.gitHash\"\n />\n</ion-item>\n" }]
|
|
15
|
+
}] });
|
|
16
|
+
//# sourceMappingURL=app-version.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-version.component.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/app-version/app-version.component.ts","../../../../../../libs/components/src/lib/app-version/app-version.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAC1C,OAAO,EACL,QAAQ,EACR,OAAO,EACP,cAAc,EACd,QAAQ,GACT,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;;AAOzC,MAAM,OAAO,mBAAmB;IALhC;QAMqB,cAAS,GAAG,SAAS,CAAC;KAC1C;8GAFY,mBAAmB;kGAAnB,mBAAmB,6ECdhC,+WAeA,4CDHY,cAAc,kGAAE,QAAQ,6FAAE,OAAO,0NAAE,QAAQ;;2FAE1C,mBAAmB;kBAL/B,SAAS;+BACE,mBAAmB,WAEpB,CAAC,cAAc,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC","sourcesContent":["import { Component } from '@angular/core';\nimport {\n IonInput,\n IonItem,\n IonItemDivider,\n IonLabel,\n} from '@ionic/angular/standalone';\nimport { buildInfo } from './build-info';\n\n@Component({\n selector: 'sneat-app-version',\n templateUrl: 'app-version.component.html',\n imports: [IonItemDivider, IonLabel, IonItem, IonInput],\n})\nexport class AppVersionComponent {\n protected readonly buildInfo = buildInfo;\n}\n","<ion-item-divider color=\"light\">\n <ion-label>App version</ion-label>\n</ion-item-divider>\n<ion-item>\n <ion-input\n label=\"Build:\"\n color=\"medium\"\n readonly=\"true\"\n disabled=\"true\"\n [value]=\"\n buildInfo.gitHash.substring(0, 7) + ' @ ' + buildInfo.buildTimestamp\n \"\n [title]=\"buildInfo.gitHash\"\n />\n</ion-item>\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build-info.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/app-version/build-info.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,SAAS,GAIlB;IACF,OAAO,EAAE,iBAAiB;IAC1B,cAAc,EAAE,mBAAmB;CACpC,CAAC","sourcesContent":["export const buildInfo: {\n // TODO: Needs pre-commit hook to check gitHash and buildTimestamp are NOT changed.\n readonly gitHash: string;\n readonly buildTimestamp: string;\n} = {\n gitHash: 'gitHash t0be$et',\n buildTimestamp: 'timestamp t0be$et',\n};\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/app-version/index.ts"],"names":[],"mappings":"AAAA,cAAc,yBAAyB,CAAC;AACxC,cAAc,cAAc,CAAC","sourcesContent":["export * from './app-version.component';\nexport * from './build-info';\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/card-list/index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC","sourcesContent":["export * from './sneat-card-list.component';\n"]}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Component, EventEmitter, Input, Output, ViewChild, inject, } from '@angular/core';
|
|
2
|
+
import { FormsModule } from '@angular/forms';
|
|
3
|
+
import { RouterModule } from '@angular/router';
|
|
4
|
+
import { IonButton, IonButtons, IonCard, IonCardContent, IonIcon, IonInput, IonItem, IonLabel, IonList, IonSegment, IonSegmentButton, IonSkeletonText, } from '@ionic/angular/standalone';
|
|
5
|
+
import { ErrorLogger } from '@sneat/core';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
import * as i1 from "@angular/router";
|
|
8
|
+
import * as i2 from "@angular/forms";
|
|
9
|
+
export class SneatCardListComponent {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.errorLogger = inject(ErrorLogger);
|
|
12
|
+
this.getRouterLink = () => undefined;
|
|
13
|
+
this.cardTitleClick = new EventEmitter();
|
|
14
|
+
this.itemClick = new EventEmitter();
|
|
15
|
+
this.tabChanged = new EventEmitter();
|
|
16
|
+
this.filter = '';
|
|
17
|
+
this.mode = 'list';
|
|
18
|
+
this.name = '';
|
|
19
|
+
}
|
|
20
|
+
click(event, item) {
|
|
21
|
+
event.preventDefault();
|
|
22
|
+
event.stopPropagation();
|
|
23
|
+
this.itemClick.emit(item);
|
|
24
|
+
}
|
|
25
|
+
showAddForm(event) {
|
|
26
|
+
event.preventDefault();
|
|
27
|
+
event.stopPropagation();
|
|
28
|
+
this.mode = 'add';
|
|
29
|
+
setTimeout(() => {
|
|
30
|
+
// console.log(this.addInput);
|
|
31
|
+
if (this.addInput) {
|
|
32
|
+
this.addInput
|
|
33
|
+
?.setFocus()
|
|
34
|
+
.catch((err) => this.errorLogger.logError(err, 'Failed to set focus'));
|
|
35
|
+
}
|
|
36
|
+
}, 200);
|
|
37
|
+
}
|
|
38
|
+
tryCreate() {
|
|
39
|
+
this.isAdding = true;
|
|
40
|
+
if (this.create) {
|
|
41
|
+
this.create(this.name.trim()).subscribe({
|
|
42
|
+
next: (item) => {
|
|
43
|
+
this.items?.push(item);
|
|
44
|
+
this.isAdding = false;
|
|
45
|
+
this.mode = 'list';
|
|
46
|
+
this.name = '';
|
|
47
|
+
},
|
|
48
|
+
error: (err) => {
|
|
49
|
+
this.errorLogger.logError(err, 'Failed to create new item');
|
|
50
|
+
this.isAdding = false;
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SneatCardListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
56
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: SneatCardListComponent, isStandalone: true, selector: "sneat-card-list", inputs: { title: "title", isFilterable: "isFilterable", isLoading: "isLoading", items: "items", create: "create", itemIcon: "itemIcon", tab: "tab", tabs: "tabs", noItemsText: "noItemsText", getRouterLink: "getRouterLink" }, outputs: { cardTitleClick: "cardTitleClick", itemClick: "itemClick", tabChanged: "tabChanged" }, viewQueries: [{ propertyName: "addInput", first: true, predicate: IonInput, descendants: true }], ngImport: i0, template: "<ion-card>\n @if (title) {\n <ion-item (click)=\"cardTitleClick.emit()\" tappable>\n @if (itemIcon && !isLoading && !items?.length) {\n <ion-icon [name]=\"itemIcon\" slot=\"start\" />\n }\n <ion-label style=\"font-weight: bold\">{{ title }}</ion-label>\n @if (isFilterable) {\n <ion-input [(ngModel)]=\"filter\" placeholder=\"(type to filter)\" />\n }\n <ion-buttons slot=\"end\">\n @if (filter) {\n <ion-button (click)=\"filter = ''\" title=\"Clear filter\">\n <ion-icon name=\"close-outline\" color=\"medium\" />\n </ion-button>\n }\n @if (mode !== \"add\" && create) {\n <ion-button (click)=\"showAddForm($event)\">\n <ion-icon color=\"primary\" slot=\"start\" name=\"add\" />\n <ion-label color=\"medium\">Add</ion-label>\n </ion-button>\n }\n </ion-buttons>\n </ion-item>\n }\n @if (tabs) {\n <ion-segment [(ngModel)]=\"tab\" (ionChange)=\"tabChanged.emit(tab || '')\">\n @for (tab of tabs; track tab.id) {\n <ion-segment-button [value]=\"tab.id\">\n <ion-label>{{ tab.title }}</ion-label>\n </ion-segment-button>\n }\n </ion-segment>\n <ion-buttons>\n @if (mode !== \"add\" && create) {\n <ion-button (click)=\"showAddForm($event)\">\n <ion-icon color=\"primary\" slot=\"start\" name=\"add\" />\n <ion-label color=\"medium\">Add</ion-label>\n </ion-button>\n }\n </ion-buttons>\n }\n @if (isLoading) {\n <ion-card-content>\n <ion-skeleton-text animated=\"\" style=\"width: 100%\" />\n </ion-card-content>\n } @else {\n <ion-list>\n @for (item of items; track item.id) {\n <ion-item\n tappable\n (click)=\"itemClick && click($event, item)\"\n [routerLink]=\"getRouterLink(item)\"\n >\n @if (itemIcon) {\n <ion-icon [name]=\"itemIcon\" slot=\"start\" />\n }\n <ion-label>{{ item.title || item.id }}</ion-label>\n </ion-item>\n }\n @if (mode === \"add\") {\n <ion-item>\n <ion-icon name=\"earth-outline\" slot=\"start\" color=\"medium\" />\n <ion-input\n [(ngModel)]=\"name\"\n placeholder=\"Name\"\n [disabled]=\"!!isAdding\"\n />\n <ion-buttons slot=\"end\">\n <ion-button\n fill=\"solid\"\n color=\"primary\"\n [disabled]=\"isAdding || !name.trim()\"\n (click)=\"tryCreate()\"\n >\n Create\n </ion-button>\n <ion-button\n (click)=\"mode = 'list'\"\n color=\"medium\"\n title=\"Cancel\"\n [disabled]=\"isAdding\"\n >\n <ion-icon name=\"close-outline\" />\n </ion-button>\n </ion-buttons>\n </ion-item>\n }\n </ion-list>\n @if (!items?.length && mode !== \"add\") {\n <ion-card-content>\n @if (!noItemsText) {\n <p>\n {{ noItemsText }}\n </p>\n } @else {\n <p>\n Not defined for this project yet. Click the\n <span style=\"background-color: whitesmoke; padding: 4px 8px\"\n >+ Add</span\n >\n button above in the header of this card to create a first one.\n </p>\n }\n </ion-card-content>\n }\n }\n</ion-card>\n", dependencies: [{ kind: "ngmodule", type: RouterModule }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: IonCard, selector: "ion-card", inputs: ["button", "color", "disabled", "download", "href", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }, { kind: "component", type: IonLabel, selector: "ion-label", inputs: ["color", "mode", "position"] }, { kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonSegment, selector: "ion-segment", inputs: ["color", "disabled", "mode", "scrollable", "selectOnFocus", "swipeGesture", "value"] }, { kind: "component", type: IonSegmentButton, selector: "ion-segment-button", inputs: ["contentId", "disabled", "layout", "mode", "type", "value"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IonCardContent, selector: "ion-card-content", inputs: ["mode"] }, { kind: "component", type: IonSkeletonText, selector: "ion-skeleton-text", inputs: ["animated"] }, { kind: "component", type: IonList, selector: "ion-list", inputs: ["inset", "lines", "mode"] }] }); }
|
|
57
|
+
}
|
|
58
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: SneatCardListComponent, decorators: [{
|
|
59
|
+
type: Component,
|
|
60
|
+
args: [{ selector: 'sneat-card-list', imports: [
|
|
61
|
+
RouterModule,
|
|
62
|
+
IonCard,
|
|
63
|
+
IonItem,
|
|
64
|
+
IonIcon,
|
|
65
|
+
IonLabel,
|
|
66
|
+
IonInput,
|
|
67
|
+
IonButtons,
|
|
68
|
+
IonButton,
|
|
69
|
+
IonSegment,
|
|
70
|
+
IonSegmentButton,
|
|
71
|
+
FormsModule,
|
|
72
|
+
IonCardContent,
|
|
73
|
+
IonSkeletonText,
|
|
74
|
+
IonList,
|
|
75
|
+
], template: "<ion-card>\n @if (title) {\n <ion-item (click)=\"cardTitleClick.emit()\" tappable>\n @if (itemIcon && !isLoading && !items?.length) {\n <ion-icon [name]=\"itemIcon\" slot=\"start\" />\n }\n <ion-label style=\"font-weight: bold\">{{ title }}</ion-label>\n @if (isFilterable) {\n <ion-input [(ngModel)]=\"filter\" placeholder=\"(type to filter)\" />\n }\n <ion-buttons slot=\"end\">\n @if (filter) {\n <ion-button (click)=\"filter = ''\" title=\"Clear filter\">\n <ion-icon name=\"close-outline\" color=\"medium\" />\n </ion-button>\n }\n @if (mode !== \"add\" && create) {\n <ion-button (click)=\"showAddForm($event)\">\n <ion-icon color=\"primary\" slot=\"start\" name=\"add\" />\n <ion-label color=\"medium\">Add</ion-label>\n </ion-button>\n }\n </ion-buttons>\n </ion-item>\n }\n @if (tabs) {\n <ion-segment [(ngModel)]=\"tab\" (ionChange)=\"tabChanged.emit(tab || '')\">\n @for (tab of tabs; track tab.id) {\n <ion-segment-button [value]=\"tab.id\">\n <ion-label>{{ tab.title }}</ion-label>\n </ion-segment-button>\n }\n </ion-segment>\n <ion-buttons>\n @if (mode !== \"add\" && create) {\n <ion-button (click)=\"showAddForm($event)\">\n <ion-icon color=\"primary\" slot=\"start\" name=\"add\" />\n <ion-label color=\"medium\">Add</ion-label>\n </ion-button>\n }\n </ion-buttons>\n }\n @if (isLoading) {\n <ion-card-content>\n <ion-skeleton-text animated=\"\" style=\"width: 100%\" />\n </ion-card-content>\n } @else {\n <ion-list>\n @for (item of items; track item.id) {\n <ion-item\n tappable\n (click)=\"itemClick && click($event, item)\"\n [routerLink]=\"getRouterLink(item)\"\n >\n @if (itemIcon) {\n <ion-icon [name]=\"itemIcon\" slot=\"start\" />\n }\n <ion-label>{{ item.title || item.id }}</ion-label>\n </ion-item>\n }\n @if (mode === \"add\") {\n <ion-item>\n <ion-icon name=\"earth-outline\" slot=\"start\" color=\"medium\" />\n <ion-input\n [(ngModel)]=\"name\"\n placeholder=\"Name\"\n [disabled]=\"!!isAdding\"\n />\n <ion-buttons slot=\"end\">\n <ion-button\n fill=\"solid\"\n color=\"primary\"\n [disabled]=\"isAdding || !name.trim()\"\n (click)=\"tryCreate()\"\n >\n Create\n </ion-button>\n <ion-button\n (click)=\"mode = 'list'\"\n color=\"medium\"\n title=\"Cancel\"\n [disabled]=\"isAdding\"\n >\n <ion-icon name=\"close-outline\" />\n </ion-button>\n </ion-buttons>\n </ion-item>\n }\n </ion-list>\n @if (!items?.length && mode !== \"add\") {\n <ion-card-content>\n @if (!noItemsText) {\n <p>\n {{ noItemsText }}\n </p>\n } @else {\n <p>\n Not defined for this project yet. Click the\n <span style=\"background-color: whitesmoke; padding: 4px 8px\"\n >+ Add</span\n >\n button above in the header of this card to create a first one.\n </p>\n }\n </ion-card-content>\n }\n }\n</ion-card>\n" }]
|
|
76
|
+
}], propDecorators: { title: [{
|
|
77
|
+
type: Input
|
|
78
|
+
}], isFilterable: [{
|
|
79
|
+
type: Input
|
|
80
|
+
}], isLoading: [{
|
|
81
|
+
type: Input
|
|
82
|
+
}], items: [{
|
|
83
|
+
type: Input
|
|
84
|
+
}], create: [{
|
|
85
|
+
type: Input
|
|
86
|
+
}], itemIcon: [{
|
|
87
|
+
type: Input
|
|
88
|
+
}], tab: [{
|
|
89
|
+
type: Input
|
|
90
|
+
}], tabs: [{
|
|
91
|
+
type: Input
|
|
92
|
+
}], noItemsText: [{
|
|
93
|
+
type: Input
|
|
94
|
+
}], getRouterLink: [{
|
|
95
|
+
type: Input
|
|
96
|
+
}], cardTitleClick: [{
|
|
97
|
+
type: Output
|
|
98
|
+
}], itemClick: [{
|
|
99
|
+
type: Output
|
|
100
|
+
}], tabChanged: [{
|
|
101
|
+
type: Output
|
|
102
|
+
}], addInput: [{
|
|
103
|
+
type: ViewChild,
|
|
104
|
+
args: [IonInput, { static: false }]
|
|
105
|
+
}] } });
|
|
106
|
+
//# sourceMappingURL=sneat-card-list.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sneat-card-list.component.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/card-list/sneat-card-list.component.ts","../../../../../../libs/components/src/lib/card-list/sneat-card-list.component.html"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,YAAY,EACZ,KAAK,EACL,MAAM,EACN,SAAS,EACT,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAC/C,OAAO,EACL,SAAS,EACT,UAAU,EACV,OAAO,EACP,cAAc,EACd,OAAO,EACP,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,OAAO,EACP,UAAU,EACV,gBAAgB,EAChB,eAAe,GAChB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,WAAW,EAAgB,MAAM,aAAa,CAAC;;;;AAiCxD,MAAM,OAAO,sBAAsB;IApBnC;QAqBmB,gBAAW,GAAG,MAAM,CAAe,WAAW,CAAC,CAAC;QAWxD,kBAAa,GAA8B,GAAG,EAAE,CACvD,SAA8B,CAAC;QAEd,mBAAc,GAAG,IAAI,YAAY,EAAQ,CAAC;QAC1C,cAAS,GAAG,IAAI,YAAY,EAAW,CAAC;QACxC,eAAU,GAAG,IAAI,YAAY,EAAU,CAAC;QAI3D,WAAM,GAAG,EAAE,CAAC;QAEF,SAAI,GAAmB,MAAM,CAAC;QAC9B,SAAI,GAAG,EAAE,CAAC;KA0CrB;IAvCW,KAAK,CAAC,KAAY,EAAE,IAAa;QACzC,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,KAAK,CAAC,eAAe,EAAE,CAAC;QACxB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAES,WAAW,CAAC,KAAY;QAChC,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,KAAK,CAAC,eAAe,EAAE,CAAC;QACxB,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC;QAClB,UAAU,CAAC,GAAG,EAAE;YACd,8BAA8B;YAC9B,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAClB,IAAI,CAAC,QAAQ;oBACX,EAAE,QAAQ,EAAE;qBACX,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,qBAAqB,CAAC,CACtD,CAAC;YACN,CAAC;QACH,CAAC,EAAE,GAAG,CAAC,CAAC;IACV,CAAC;IAES,SAAS;QACjB,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,SAAS,CAAC;gBACtC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE;oBACb,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;oBACvB,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;oBACtB,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC;oBACnB,IAAI,CAAC,IAAI,GAAG,EAAE,CAAC;gBACjB,CAAC;gBACD,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE;oBACb,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;oBAC5D,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;gBACxB,CAAC;aACF,CAAC,CAAC;QACL,CAAC;IACH,CAAC;8GAjEU,sBAAsB;kGAAtB,sBAAsB,sbAmBtB,QAAQ,gDC7ErB,27GA4GA,2CDlEI,YAAY,gRACZ,OAAO,yLACP,OAAO,0NACP,OAAO,2JACP,QAAQ,6FACR,QAAQ,8eACR,UAAU,8EACV,SAAS,oPACT,UAAU,uJACV,gBAAgB,oIAChB,WAAW,+VACX,cAAc,+EACd,eAAe,oFACf,OAAO;;2FAGE,sBAAsB;kBApBlC,SAAS;+BACE,iBAAiB,WAElB;wBACP,YAAY;wBACZ,OAAO;wBACP,OAAO;wBACP,OAAO;wBACP,QAAQ;wBACR,QAAQ;wBACR,UAAU;wBACV,SAAS;wBACT,UAAU;wBACV,gBAAgB;wBAChB,WAAW;wBACX,cAAc;wBACd,eAAe;wBACf,OAAO;qBACR;;sBAKA,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBAGL,MAAM;;sBACN,MAAM;;sBACN,MAAM;;sBAEN,SAAS;uBAAC,QAAQ,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE","sourcesContent":["import {\n Component,\n EventEmitter,\n Input,\n Output,\n ViewChild,\n inject,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport { RouterModule } from '@angular/router';\nimport {\n IonButton,\n IonButtons,\n IonCard,\n IonCardContent,\n IonIcon,\n IonInput,\n IonItem,\n IonLabel,\n IonList,\n IonSegment,\n IonSegmentButton,\n IonSkeletonText,\n} from '@ionic/angular/standalone';\nimport { IRecord } from '@sneat/data';\nimport { ErrorLogger, IErrorLogger } from '@sneat/core';\nimport { Observable } from 'rxjs';\n\nexport interface ICardTab {\n id: string;\n title: string;\n}\n\ninterface IOptionallyTitled {\n id?: string;\n title?: string;\n}\n\n@Component({\n selector: 'sneat-card-list',\n templateUrl: './sneat-card-list.component.html',\n imports: [\n RouterModule,\n IonCard,\n IonItem,\n IonIcon,\n IonLabel,\n IonInput,\n IonButtons,\n IonButton,\n IonSegment,\n IonSegmentButton,\n FormsModule,\n IonCardContent,\n IonSkeletonText,\n IonList,\n ],\n})\nexport class SneatCardListComponent {\n private readonly errorLogger = inject<IErrorLogger>(ErrorLogger);\n\n @Input() title?: string;\n @Input() isFilterable?: boolean;\n @Input() isLoading?: boolean;\n @Input() items?: { id?: unknown; title?: string }[];\n @Input() create?: (name: string) => Observable<IRecord<IOptionallyTitled>>;\n @Input() itemIcon?: string;\n @Input() tab?: string;\n @Input() tabs?: ICardTab[];\n @Input() noItemsText?: string;\n @Input() getRouterLink: (item: unknown) => string = () =>\n undefined as unknown as string;\n\n @Output() readonly cardTitleClick = new EventEmitter<void>();\n @Output() readonly itemClick = new EventEmitter<unknown>();\n @Output() readonly tabChanged = new EventEmitter<string>();\n\n @ViewChild(IonInput, { static: false }) addInput?: IonInput;\n\n filter = '';\n\n protected mode: 'list' | 'add' = 'list';\n protected name = '';\n protected isAdding?: boolean;\n\n protected click(event: Event, item: unknown): void {\n event.preventDefault();\n event.stopPropagation();\n this.itemClick.emit(item);\n }\n\n protected showAddForm(event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n this.mode = 'add';\n setTimeout(() => {\n // console.log(this.addInput);\n if (this.addInput) {\n this.addInput\n ?.setFocus()\n .catch((err) =>\n this.errorLogger.logError(err, 'Failed to set focus'),\n );\n }\n }, 200);\n }\n\n protected tryCreate(): void {\n this.isAdding = true;\n if (this.create) {\n this.create(this.name.trim()).subscribe({\n next: (item) => {\n this.items?.push(item);\n this.isAdding = false;\n this.mode = 'list';\n this.name = '';\n },\n error: (err) => {\n this.errorLogger.logError(err, 'Failed to create new item');\n this.isAdding = false;\n },\n });\n }\n }\n}\n","<ion-card>\n @if (title) {\n <ion-item (click)=\"cardTitleClick.emit()\" tappable>\n @if (itemIcon && !isLoading && !items?.length) {\n <ion-icon [name]=\"itemIcon\" slot=\"start\" />\n }\n <ion-label style=\"font-weight: bold\">{{ title }}</ion-label>\n @if (isFilterable) {\n <ion-input [(ngModel)]=\"filter\" placeholder=\"(type to filter)\" />\n }\n <ion-buttons slot=\"end\">\n @if (filter) {\n <ion-button (click)=\"filter = ''\" title=\"Clear filter\">\n <ion-icon name=\"close-outline\" color=\"medium\" />\n </ion-button>\n }\n @if (mode !== \"add\" && create) {\n <ion-button (click)=\"showAddForm($event)\">\n <ion-icon color=\"primary\" slot=\"start\" name=\"add\" />\n <ion-label color=\"medium\">Add</ion-label>\n </ion-button>\n }\n </ion-buttons>\n </ion-item>\n }\n @if (tabs) {\n <ion-segment [(ngModel)]=\"tab\" (ionChange)=\"tabChanged.emit(tab || '')\">\n @for (tab of tabs; track tab.id) {\n <ion-segment-button [value]=\"tab.id\">\n <ion-label>{{ tab.title }}</ion-label>\n </ion-segment-button>\n }\n </ion-segment>\n <ion-buttons>\n @if (mode !== \"add\" && create) {\n <ion-button (click)=\"showAddForm($event)\">\n <ion-icon color=\"primary\" slot=\"start\" name=\"add\" />\n <ion-label color=\"medium\">Add</ion-label>\n </ion-button>\n }\n </ion-buttons>\n }\n @if (isLoading) {\n <ion-card-content>\n <ion-skeleton-text animated=\"\" style=\"width: 100%\" />\n </ion-card-content>\n } @else {\n <ion-list>\n @for (item of items; track item.id) {\n <ion-item\n tappable\n (click)=\"itemClick && click($event, item)\"\n [routerLink]=\"getRouterLink(item)\"\n >\n @if (itemIcon) {\n <ion-icon [name]=\"itemIcon\" slot=\"start\" />\n }\n <ion-label>{{ item.title || item.id }}</ion-label>\n </ion-item>\n }\n @if (mode === \"add\") {\n <ion-item>\n <ion-icon name=\"earth-outline\" slot=\"start\" color=\"medium\" />\n <ion-input\n [(ngModel)]=\"name\"\n placeholder=\"Name\"\n [disabled]=\"!!isAdding\"\n />\n <ion-buttons slot=\"end\">\n <ion-button\n fill=\"solid\"\n color=\"primary\"\n [disabled]=\"isAdding || !name.trim()\"\n (click)=\"tryCreate()\"\n >\n Create\n </ion-button>\n <ion-button\n (click)=\"mode = 'list'\"\n color=\"medium\"\n title=\"Cancel\"\n [disabled]=\"isAdding\"\n >\n <ion-icon name=\"close-outline\" />\n </ion-button>\n </ion-buttons>\n </ion-item>\n }\n </ion-list>\n @if (!items?.length && mode !== \"add\") {\n <ion-card-content>\n @if (!noItemsText) {\n <p>\n {{ noItemsText }}\n </p>\n } @else {\n <p>\n Not defined for this project yet. Click the\n <span style=\"background-color: whitesmoke; padding: 4px 8px\"\n >+ Add</span\n >\n button above in the header of this card to create a first one.\n </p>\n }\n </ion-card-content>\n }\n }\n</ion-card>\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { Component } from '@angular/core';
|
|
2
|
+
import * as i0 from "@angular/core";
|
|
3
|
+
export class CopyrightComponent {
|
|
4
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CopyrightComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
5
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.0", type: CopyrightComponent, isStandalone: true, selector: "sneat-copyright", ngImport: i0, template: "<p>2020 © Sneat.team</p>\n" }); }
|
|
6
|
+
}
|
|
7
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CopyrightComponent, decorators: [{
|
|
8
|
+
type: Component,
|
|
9
|
+
args: [{ selector: 'sneat-copyright', template: "<p>2020 © Sneat.team</p>\n" }]
|
|
10
|
+
}] });
|
|
11
|
+
//# sourceMappingURL=copyright.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copyright.component.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/copyright/copyright.component.ts","../../../../../../libs/components/src/lib/copyright/copyright.component.html"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;;AAM1C,MAAM,OAAO,kBAAkB;8GAAlB,kBAAkB;kGAAlB,kBAAkB,2ECN/B,iCACA;;2FDKa,kBAAkB;kBAJ9B,SAAS;+BACE,iBAAiB","sourcesContent":["import { Component } from '@angular/core';\n\n@Component({\n selector: 'sneat-copyright',\n templateUrl: './copyright.component.html',\n})\nexport class CopyrightComponent {}\n","<p>2020 © Sneat.team</p>\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/copyright/index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC","sourcesContent":["export * from './copyright.component';\n"]}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Component, EventEmitter, inject, Input, Output, signal, } from '@angular/core';
|
|
2
|
+
import { FormsModule } from '@angular/forms';
|
|
3
|
+
import { IonButton, IonButtons, IonIcon, IonItem, IonSelect, IonSelectOption, } from '@ionic/angular/standalone';
|
|
4
|
+
import { CountriesLoaderService } from '../country-selector';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "@angular/forms";
|
|
7
|
+
export class CountryInputComponent {
|
|
8
|
+
constructor() {
|
|
9
|
+
this.countriesLoader = inject(CountriesLoaderService);
|
|
10
|
+
this.canReset = true;
|
|
11
|
+
this.label = 'Country';
|
|
12
|
+
this.countryID = '';
|
|
13
|
+
this.countryIDChange = new EventEmitter();
|
|
14
|
+
this.countries = signal([], ...(ngDevMode ? [{ debugName: "countries" }] : []));
|
|
15
|
+
}
|
|
16
|
+
ngOnInit() {
|
|
17
|
+
// Load countries data
|
|
18
|
+
this.countriesLoader.getCountries().then((countries) => {
|
|
19
|
+
this.countries.set(countries);
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
// constructor(
|
|
23
|
+
// // private readonly countrySelectorService: CountrySelectorService,
|
|
24
|
+
// ) {
|
|
25
|
+
// }
|
|
26
|
+
onCountryChanged() {
|
|
27
|
+
// console.log('CountryInputComponent.onCountryChanged()', this.countryID);
|
|
28
|
+
this.countryIDChange.emit(this.countryID);
|
|
29
|
+
}
|
|
30
|
+
reset(event) {
|
|
31
|
+
event.preventDefault();
|
|
32
|
+
event.stopPropagation();
|
|
33
|
+
this.countryID = '';
|
|
34
|
+
this.countryIDChange.emit('');
|
|
35
|
+
}
|
|
36
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CountryInputComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
37
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: CountryInputComponent, isStandalone: true, selector: "sneat-country-input", inputs: { canReset: "canReset", label: "label", countryID: "countryID" }, outputs: { countryIDChange: "countryIDChange" }, ngImport: i0, template: "<ion-item class=\"sneat-tiny-end-padding\" lines=\"none\">\n <ion-select\n interface=\"popover\"\n [label]=\"label\"\n [(ngModel)]=\"countryID\"\n (ionChange)=\"onCountryChanged()\"\n >\n <ion-select-option value=\"\">All</ion-select-option>\n @for (c of countries(); track c.id) {\n <ion-select-option [value]=\"c.id\">\n {{ c.title }} {{ c.emoji }}\n </ion-select-option>\n }\n </ion-select>\n @if (countryID && canReset) {\n <ion-buttons slot=\"end\">\n <ion-button color=\"medium\" (click)=\"reset($event)\">\n <ion-icon name=\"close-outline\" />\n </ion-button>\n </ion-buttons>\n }\n <!-- disable for now as select is showing incorrectyl and lookup us not linked-->\n <!--\t<ion-buttons slot=\"end\" class=\"ion-no-margin ion-no-padding\">-->\n <!--\t\t<ion-button *ngIf=\"canReset && countryID\"-->\n <!--\t\t\t\t\t\t\t\tcolor=\"medium\"-->\n <!--\t\t\t\t\t\t\t\t(click)=\"reset($event)\" [disabled]=\"!canReset || !countryID\">-->\n <!--\t\t\t<ion-icon name=\"close-outline\"></ion-icon>-->\n <!--\t\t</ion-button>-->\n <!--\t\t<ion-button (click)=\"openCountrySelector($event)\">-->\n <!--\t\t\t<ion-label>...</ion-label>-->\n <!--\t\t</ion-button>-->\n <!--\t</ion-buttons>-->\n</ion-item>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "component", type: IonIcon, selector: "ion-icon", inputs: ["color", "flipRtl", "icon", "ios", "lazy", "md", "mode", "name", "sanitize", "size", "src"] }] }); }
|
|
38
|
+
}
|
|
39
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CountryInputComponent, decorators: [{
|
|
40
|
+
type: Component,
|
|
41
|
+
args: [{ selector: 'sneat-country-input', imports: [
|
|
42
|
+
FormsModule,
|
|
43
|
+
IonItem,
|
|
44
|
+
IonSelect,
|
|
45
|
+
IonSelectOption,
|
|
46
|
+
IonButtons,
|
|
47
|
+
IonButton,
|
|
48
|
+
IonIcon,
|
|
49
|
+
], template: "<ion-item class=\"sneat-tiny-end-padding\" lines=\"none\">\n <ion-select\n interface=\"popover\"\n [label]=\"label\"\n [(ngModel)]=\"countryID\"\n (ionChange)=\"onCountryChanged()\"\n >\n <ion-select-option value=\"\">All</ion-select-option>\n @for (c of countries(); track c.id) {\n <ion-select-option [value]=\"c.id\">\n {{ c.title }} {{ c.emoji }}\n </ion-select-option>\n }\n </ion-select>\n @if (countryID && canReset) {\n <ion-buttons slot=\"end\">\n <ion-button color=\"medium\" (click)=\"reset($event)\">\n <ion-icon name=\"close-outline\" />\n </ion-button>\n </ion-buttons>\n }\n <!-- disable for now as select is showing incorrectyl and lookup us not linked-->\n <!--\t<ion-buttons slot=\"end\" class=\"ion-no-margin ion-no-padding\">-->\n <!--\t\t<ion-button *ngIf=\"canReset && countryID\"-->\n <!--\t\t\t\t\t\t\t\tcolor=\"medium\"-->\n <!--\t\t\t\t\t\t\t\t(click)=\"reset($event)\" [disabled]=\"!canReset || !countryID\">-->\n <!--\t\t\t<ion-icon name=\"close-outline\"></ion-icon>-->\n <!--\t\t</ion-button>-->\n <!--\t\t<ion-button (click)=\"openCountrySelector($event)\">-->\n <!--\t\t\t<ion-label>...</ion-label>-->\n <!--\t\t</ion-button>-->\n <!--\t</ion-buttons>-->\n</ion-item>\n" }]
|
|
50
|
+
}], propDecorators: { canReset: [{
|
|
51
|
+
type: Input
|
|
52
|
+
}], label: [{
|
|
53
|
+
type: Input
|
|
54
|
+
}], countryID: [{
|
|
55
|
+
type: Input
|
|
56
|
+
}], countryIDChange: [{
|
|
57
|
+
type: Output
|
|
58
|
+
}] } });
|
|
59
|
+
//# sourceMappingURL=country-input.component.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"country-input.component.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/country-input/country-input.component.ts","../../../../../../libs/components/src/lib/country-input/country-input.component.html"],"names":[],"mappings":"AAAA,OAAO,EACL,SAAS,EACT,YAAY,EACZ,MAAM,EACN,KAAK,EAEL,MAAM,EACN,MAAM,GACP,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EACL,SAAS,EACT,UAAU,EACV,OAAO,EACP,OAAO,EACP,SAAS,EACT,eAAe,GAChB,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAY,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;;;AAevE,MAAM,OAAO,qBAAqB;IAblC;QAcmB,oBAAe,GAAG,MAAM,CAAC,sBAAsB,CAAC,CAAC;QAEzD,aAAQ,GAAG,IAAI,CAAC;QAChB,UAAK,GAAG,SAAS,CAAC;QAClB,cAAS,GAAG,EAAE,CAAC;QACd,oBAAe,GAAG,IAAI,YAAY,EAAU,CAAC;QAE9C,cAAS,GAAG,MAAM,CAAsB,EAAE,qDAAC,CAAC;KAkCtD;IAhCC,QAAQ;QACN,sBAAsB;QACtB,IAAI,CAAC,eAAe,CAAC,YAAY,EAAE,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE;YACrD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,eAAe;IACf,uEAAuE;IACvE,MAAM;IACN,IAAI;IAEG,gBAAgB;QACrB,2EAA2E;QAC3E,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,KAAY;QAChB,KAAK,CAAC,cAAc,EAAE,CAAC;QACvB,KAAK,CAAC,eAAe,EAAE,CAAC;QACxB,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAChC,CAAC;8GAhCU,qBAAqB;kGAArB,qBAAqB,0MCjClC,gwCAiCA,2CDTI,WAAW,+VACX,OAAO,0NACP,SAAS,kVACT,eAAe,6FACf,UAAU,8EACV,SAAS,oPACT,OAAO;;2FAGE,qBAAqB;kBAbjC,SAAS;+BACE,qBAAqB,WAEtB;wBACP,WAAW;wBACX,OAAO;wBACP,SAAS;wBACT,eAAe;wBACf,UAAU;wBACV,SAAS;wBACT,OAAO;qBACR;;sBAKA,KAAK;;sBACL,KAAK;;sBACL,KAAK;;sBACL,MAAM","sourcesContent":["import {\n Component,\n EventEmitter,\n inject,\n Input,\n OnInit,\n Output,\n signal,\n} from '@angular/core';\nimport { FormsModule } from '@angular/forms';\nimport {\n IonButton,\n IonButtons,\n IonIcon,\n IonItem,\n IonSelect,\n IonSelectOption,\n} from '@ionic/angular/standalone';\nimport { ICountry, CountriesLoaderService } from '../country-selector';\n\n@Component({\n selector: 'sneat-country-input',\n templateUrl: './country-input.component.html',\n imports: [\n FormsModule,\n IonItem,\n IonSelect,\n IonSelectOption,\n IonButtons,\n IonButton,\n IonIcon,\n ],\n})\nexport class CountryInputComponent implements OnInit {\n private readonly countriesLoader = inject(CountriesLoaderService);\n\n @Input() canReset = true;\n @Input() label = 'Country';\n @Input() countryID = '';\n @Output() countryIDChange = new EventEmitter<string>();\n\n readonly countries = signal<readonly ICountry[]>([]);\n\n ngOnInit(): void {\n // Load countries data\n this.countriesLoader.getCountries().then((countries) => {\n this.countries.set(countries);\n });\n }\n\n // constructor(\n // \t// private readonly countrySelectorService: CountrySelectorService,\n // ) {\n // }\n\n public onCountryChanged(): void {\n // console.log('CountryInputComponent.onCountryChanged()', this.countryID);\n this.countryIDChange.emit(this.countryID);\n }\n\n reset(event: Event): void {\n event.preventDefault();\n event.stopPropagation();\n this.countryID = '';\n this.countryIDChange.emit('');\n }\n\n // protected openCountrySelector(): void {\n // \t// const options: ISelectorOptions<ICountry> = {\n // \t// \titems: of(countries),\n // \t// };\n // \t// this.countrySelectorService\n // \t// \t.selectSingleInModal(options)\n // \t// \t.then();\n // }\n}\n","<ion-item class=\"sneat-tiny-end-padding\" lines=\"none\">\n <ion-select\n interface=\"popover\"\n [label]=\"label\"\n [(ngModel)]=\"countryID\"\n (ionChange)=\"onCountryChanged()\"\n >\n <ion-select-option value=\"\">All</ion-select-option>\n @for (c of countries(); track c.id) {\n <ion-select-option [value]=\"c.id\">\n {{ c.title }} {{ c.emoji }}\n </ion-select-option>\n }\n </ion-select>\n @if (countryID && canReset) {\n <ion-buttons slot=\"end\">\n <ion-button color=\"medium\" (click)=\"reset($event)\">\n <ion-icon name=\"close-outline\" />\n </ion-button>\n </ion-buttons>\n }\n <!-- disable for now as select is showing incorrectyl and lookup us not linked-->\n <!--\t<ion-buttons slot=\"end\" class=\"ion-no-margin ion-no-padding\">-->\n <!--\t\t<ion-button *ngIf=\"canReset && countryID\"-->\n <!--\t\t\t\t\t\t\t\tcolor=\"medium\"-->\n <!--\t\t\t\t\t\t\t\t(click)=\"reset($event)\" [disabled]=\"!canReset || !countryID\">-->\n <!--\t\t\t<ion-icon name=\"close-outline\"></ion-icon>-->\n <!--\t\t</ion-button>-->\n <!--\t\t<ion-button (click)=\"openCountrySelector($event)\">-->\n <!--\t\t\t<ion-label>...</ion-label>-->\n <!--\t\t</ion-button>-->\n <!--\t</ion-buttons>-->\n</ion-item>\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/country-input/index.ts"],"names":[],"mappings":"AAAA,cAAc,2BAA2B,CAAC","sourcesContent":["export * from './country-input.component';\n"]}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { inject, Injectable } from '@angular/core';
|
|
2
|
+
import { HttpClient } from '@angular/common/http';
|
|
3
|
+
import { firstValueFrom } from 'rxjs';
|
|
4
|
+
import * as i0 from "@angular/core";
|
|
5
|
+
/**
|
|
6
|
+
* Service to lazy load country data.
|
|
7
|
+
* This reduces the initial bundle size by loading country data on-demand.
|
|
8
|
+
*/
|
|
9
|
+
export class CountriesLoaderService {
|
|
10
|
+
constructor() {
|
|
11
|
+
this.http = inject(HttpClient);
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Loads country data from JSON file.
|
|
15
|
+
* Subsequent calls return the same promise (singleton pattern).
|
|
16
|
+
*/
|
|
17
|
+
async loadCountries() {
|
|
18
|
+
if (this.countriesData) {
|
|
19
|
+
return; // Already loaded
|
|
20
|
+
}
|
|
21
|
+
if (!this.loadPromise) {
|
|
22
|
+
this.loadPromise = (async () => {
|
|
23
|
+
try {
|
|
24
|
+
this.countriesData = await firstValueFrom(this.http.get('assets/data/countries.json'));
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
console.error('Failed to load countries:', error);
|
|
28
|
+
// Set to empty to avoid repeated failures
|
|
29
|
+
this.countriesData = {
|
|
30
|
+
countriesByID: {},
|
|
31
|
+
unknownCountry: {
|
|
32
|
+
id: '--',
|
|
33
|
+
id3: '---',
|
|
34
|
+
title: 'Unknown',
|
|
35
|
+
geoRegions: [],
|
|
36
|
+
emoji: '🏳️',
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
})();
|
|
41
|
+
}
|
|
42
|
+
return this.loadPromise;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Gets all countries as an array.
|
|
46
|
+
* Automatically loads country data if not yet loaded.
|
|
47
|
+
*/
|
|
48
|
+
async getCountries() {
|
|
49
|
+
await this.loadCountries();
|
|
50
|
+
return Object.values(this.countriesData.countriesByID);
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Gets countries by ID lookup.
|
|
54
|
+
* Automatically loads country data if not yet loaded.
|
|
55
|
+
*/
|
|
56
|
+
async getCountriesByID() {
|
|
57
|
+
await this.loadCountries();
|
|
58
|
+
return this.countriesData.countriesByID;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Gets a specific country by ID.
|
|
62
|
+
* Automatically loads country data if not yet loaded.
|
|
63
|
+
*/
|
|
64
|
+
async getCountryByID(id) {
|
|
65
|
+
await this.loadCountries();
|
|
66
|
+
return this.countriesData.countriesByID[id];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Gets the unknown country constant.
|
|
70
|
+
* Automatically loads country data if not yet loaded.
|
|
71
|
+
*/
|
|
72
|
+
async getUnknownCountry() {
|
|
73
|
+
await this.loadCountries();
|
|
74
|
+
return this.countriesData.unknownCountry;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Gets countries filtered by geo region.
|
|
78
|
+
* Automatically loads country data if not yet loaded.
|
|
79
|
+
*/
|
|
80
|
+
async getCountriesByRegion(region) {
|
|
81
|
+
const countries = await this.getCountries();
|
|
82
|
+
return countries.filter((c) => c.geoRegions.includes(region));
|
|
83
|
+
}
|
|
84
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CountriesLoaderService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
85
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CountriesLoaderService, providedIn: 'root' }); }
|
|
86
|
+
}
|
|
87
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CountriesLoaderService, decorators: [{
|
|
88
|
+
type: Injectable,
|
|
89
|
+
args: [{ providedIn: 'root' }]
|
|
90
|
+
}] });
|
|
91
|
+
//# sourceMappingURL=countries-loader.service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"countries-loader.service.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/country-selector/countries-loader.service.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;;AAQtC;;;GAGG;AAEH,MAAM,OAAO,sBAAsB;IADnC;QAEmB,SAAI,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;KAmF5C;IA/EC;;;OAGG;IACK,KAAK,CAAC,aAAa;QACzB,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,OAAO,CAAC,iBAAiB;QAC3B,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC,WAAW,GAAG,CAAC,KAAK,IAAI,EAAE;gBAC7B,IAAI,CAAC;oBACH,IAAI,CAAC,aAAa,GAAG,MAAM,cAAc,CACvC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAgB,4BAA4B,CAAC,CAC3D,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,OAAO,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;oBAClD,0CAA0C;oBAC1C,IAAI,CAAC,aAAa,GAAG;wBACnB,aAAa,EAAE,EAAE;wBACjB,cAAc,EAAE;4BACd,EAAE,EAAE,IAAI;4BACR,GAAG,EAAE,KAAK;4BACV,KAAK,EAAE,SAAS;4BAChB,UAAU,EAAE,EAAE;4BACd,KAAK,EAAE,KAAK;yBACb;qBACF,CAAC;gBACJ,CAAC;YACH,CAAC,CAAC,EAAE,CAAC;QACP,CAAC;QAED,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,YAAY;QAChB,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC3B,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,aAAc,CAAC,aAAa,CAAC,CAAC;IAC1D,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,gBAAgB;QACpB,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,aAAc,CAAC,aAAa,CAAC;IAC3C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,cAAc,CAAC,EAAU;QAC7B,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,aAAc,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,iBAAiB;QACrB,MAAM,IAAI,CAAC,aAAa,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,aAAc,CAAC,cAAc,CAAC;IAC5C,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,oBAAoB,CAAC,MAAiB;QAC1C,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,YAAY,EAAE,CAAC;QAC5C,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IAChE,CAAC;8GAnFU,sBAAsB;kHAAtB,sBAAsB,cADT,MAAM;;2FACnB,sBAAsB;kBADlC,UAAU;mBAAC,EAAE,UAAU,EAAE,MAAM,EAAE","sourcesContent":["import { inject, Injectable } from '@angular/core';\nimport { HttpClient } from '@angular/common/http';\nimport { firstValueFrom } from 'rxjs';\nimport { GeoRegion, ICountry } from './countries';\n\ninterface CountriesData {\n countriesByID: Record<string, ICountry>;\n unknownCountry: ICountry;\n}\n\n/**\n * Service to lazy load country data.\n * This reduces the initial bundle size by loading country data on-demand.\n */\n@Injectable({ providedIn: 'root' })\nexport class CountriesLoaderService {\n private readonly http = inject(HttpClient);\n private countriesData?: CountriesData;\n private loadPromise?: Promise<void>;\n\n /**\n * Loads country data from JSON file.\n * Subsequent calls return the same promise (singleton pattern).\n */\n private async loadCountries(): Promise<void> {\n if (this.countriesData) {\n return; // Already loaded\n }\n\n if (!this.loadPromise) {\n this.loadPromise = (async () => {\n try {\n this.countriesData = await firstValueFrom(\n this.http.get<CountriesData>('assets/data/countries.json'),\n );\n } catch (error) {\n console.error('Failed to load countries:', error);\n // Set to empty to avoid repeated failures\n this.countriesData = {\n countriesByID: {},\n unknownCountry: {\n id: '--',\n id3: '---',\n title: 'Unknown',\n geoRegions: [],\n emoji: '🏳️',\n },\n };\n }\n })();\n }\n\n return this.loadPromise;\n }\n\n /**\n * Gets all countries as an array.\n * Automatically loads country data if not yet loaded.\n */\n async getCountries(): Promise<readonly ICountry[]> {\n await this.loadCountries();\n return Object.values(this.countriesData!.countriesByID);\n }\n\n /**\n * Gets countries by ID lookup.\n * Automatically loads country data if not yet loaded.\n */\n async getCountriesByID(): Promise<Record<string, ICountry>> {\n await this.loadCountries();\n return this.countriesData!.countriesByID;\n }\n\n /**\n * Gets a specific country by ID.\n * Automatically loads country data if not yet loaded.\n */\n async getCountryByID(id: string): Promise<ICountry | undefined> {\n await this.loadCountries();\n return this.countriesData!.countriesByID[id];\n }\n\n /**\n * Gets the unknown country constant.\n * Automatically loads country data if not yet loaded.\n */\n async getUnknownCountry(): Promise<ICountry> {\n await this.loadCountries();\n return this.countriesData!.unknownCountry;\n }\n\n /**\n * Gets countries filtered by geo region.\n * Automatically loads country data if not yet loaded.\n */\n async getCountriesByRegion(region: GeoRegion): Promise<readonly ICountry[]> {\n const countries = await this.getCountries();\n return countries.filter((c) => c.geoRegions.includes(region));\n }\n}\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated Use CountriesLoaderService.getCountriesByID() instead.
|
|
3
|
+
* Country data is now lazy-loaded to reduce bundle size.
|
|
4
|
+
*/
|
|
5
|
+
export const countriesByID = {};
|
|
6
|
+
/**
|
|
7
|
+
* @deprecated Use CountriesLoaderService.getUnknownCountry() instead.
|
|
8
|
+
* Country data is now lazy-loaded to reduce bundle size.
|
|
9
|
+
*/
|
|
10
|
+
export const unknownCountry = {
|
|
11
|
+
id: '--',
|
|
12
|
+
id3: '---',
|
|
13
|
+
title: 'Unknown',
|
|
14
|
+
geoRegions: [],
|
|
15
|
+
emoji: '🏳️',
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* @deprecated Use CountriesLoaderService.getCountries() instead.
|
|
19
|
+
* Country data is now lazy-loaded to reduce bundle size.
|
|
20
|
+
*/
|
|
21
|
+
export const countries = [];
|
|
22
|
+
//# sourceMappingURL=countries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"countries.js","sourceRoot":"","sources":["../../../../../../libs/components/src/lib/country-selector/countries.ts"],"names":[],"mappings":"AAmBA;;;GAGG;AACH,MAAM,CAAC,MAAM,aAAa,GAA6B,EAAE,CAAC;AAE1D;;;GAGG;AACH,MAAM,CAAC,MAAM,cAAc,GAAa;IACtC,EAAE,EAAE,IAAI;IACR,GAAG,EAAE,KAAK;IACV,KAAK,EAAE,SAAS;IAChB,UAAU,EAAE,EAAE;IACd,KAAK,EAAE,KAAK;CACb,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAe,EAAE,CAAC","sourcesContent":["export type GeoRegion =\n | 'Europe'\n | 'Asia'\n | 'Americas'\n | 'South America'\n | 'North America'\n | 'Pacific Ocean'\n | 'Africa';\n\nexport interface ICountry {\n id: string;\n id3: string;\n geoRegions: GeoRegion[];\n title: string;\n longTitle?: string;\n shortTitle?: string;\n emoji: string;\n}\n\n/**\n * @deprecated Use CountriesLoaderService.getCountriesByID() instead.\n * Country data is now lazy-loaded to reduce bundle size.\n */\nexport const countriesByID: Record<string, ICountry> = {};\n\n/**\n * @deprecated Use CountriesLoaderService.getUnknownCountry() instead.\n * Country data is now lazy-loaded to reduce bundle size.\n */\nexport const unknownCountry: ICountry = {\n id: '--',\n id3: '---',\n title: 'Unknown',\n geoRegions: [],\n emoji: '🏳️',\n};\n\n/**\n * @deprecated Use CountriesLoaderService.getCountries() instead.\n * Country data is now lazy-loaded to reduce bundle size.\n */\nexport const countries: ICountry[] = [];\n"]}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Component, computed, EventEmitter, inject, Input, Output, signal, } from '@angular/core';
|
|
2
|
+
import { FormsModule } from '@angular/forms';
|
|
3
|
+
import { IonSegment, IonSegmentButton } from '@ionic/angular/standalone';
|
|
4
|
+
import { SelectFromListComponent } from '@sneat/ui';
|
|
5
|
+
import { CountriesLoaderService } from './countries-loader.service';
|
|
6
|
+
import * as i0 from "@angular/core";
|
|
7
|
+
import * as i1 from "@angular/forms";
|
|
8
|
+
export class CountrySelectorComponent {
|
|
9
|
+
constructor() {
|
|
10
|
+
this.countriesLoader = inject(CountriesLoaderService);
|
|
11
|
+
this.geoRegions = [
|
|
12
|
+
{ id: 'Europe' },
|
|
13
|
+
{ id: 'Asia' },
|
|
14
|
+
{ id: 'Americas' },
|
|
15
|
+
{ id: 'Africa' },
|
|
16
|
+
];
|
|
17
|
+
this.readonly = false;
|
|
18
|
+
this.disabled = false;
|
|
19
|
+
this.label = 'search';
|
|
20
|
+
this.canBeUnknown = false;
|
|
21
|
+
this.countryIDChange = new EventEmitter();
|
|
22
|
+
this.filter = signal('', ...(ngDevMode ? [{ debugName: "filter" }] : []));
|
|
23
|
+
this.geoRegion = signal('All', ...(ngDevMode ? [{ debugName: "geoRegion" }] : []));
|
|
24
|
+
this.allCountries = signal([], ...(ngDevMode ? [{ debugName: "allCountries" }] : []));
|
|
25
|
+
this.unknownCountry = signal(undefined, ...(ngDevMode ? [{ debugName: "unknownCountry" }] : []));
|
|
26
|
+
this.countries = computed(() => {
|
|
27
|
+
const allCountries = this.allCountries();
|
|
28
|
+
if (allCountries.length === 0) {
|
|
29
|
+
return []; // Data not loaded yet
|
|
30
|
+
}
|
|
31
|
+
const filter = this.filter();
|
|
32
|
+
let countriesToShow = filter
|
|
33
|
+
? allCountries
|
|
34
|
+
: allCountries.filter((c) => this.geoRegion() === 'All' ||
|
|
35
|
+
(this.geoRegion() === 'Americas' &&
|
|
36
|
+
(c.geoRegions.includes('North America') ||
|
|
37
|
+
c.geoRegions.includes('South America'))) ||
|
|
38
|
+
c.geoRegions.includes(this.geoRegion()));
|
|
39
|
+
if (this.canBeUnknown && this.unknownCountry()) {
|
|
40
|
+
countriesToShow = [...countriesToShow, this.unknownCountry()];
|
|
41
|
+
}
|
|
42
|
+
return countriesToShow;
|
|
43
|
+
}, ...(ngDevMode ? [{ debugName: "countries" }] : []));
|
|
44
|
+
this.filterCountryByCode = (item, filter) => {
|
|
45
|
+
const f = filter.trim().toUpperCase();
|
|
46
|
+
const c = item;
|
|
47
|
+
return c.id === f || c.id3.startsWith(f);
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
ngOnInit() {
|
|
51
|
+
// Load countries data
|
|
52
|
+
this.countriesLoader.getCountries().then((countries) => {
|
|
53
|
+
this.allCountries.set(countries);
|
|
54
|
+
});
|
|
55
|
+
this.countriesLoader.getUnknownCountry().then((unknown) => {
|
|
56
|
+
this.unknownCountry.set(unknown);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
// protected geoRegion: GeoRegion | 'All' | 'Americas' = 'All';
|
|
60
|
+
onChanged() {
|
|
61
|
+
this.countryIDChange.emit(this.countryID);
|
|
62
|
+
}
|
|
63
|
+
onFilterChanged(filter) {
|
|
64
|
+
this.filter.set(filter);
|
|
65
|
+
}
|
|
66
|
+
ngOnChanges(changes) {
|
|
67
|
+
if (changes['country'] && this.countryID === '--' && !this.canBeUnknown) {
|
|
68
|
+
this.countryID = undefined;
|
|
69
|
+
}
|
|
70
|
+
if (changes['defaultCountryID'] &&
|
|
71
|
+
!this.countryID &&
|
|
72
|
+
this.defaultCountryID &&
|
|
73
|
+
this.defaultCountryID !== '--') {
|
|
74
|
+
this.countryID = this.defaultCountryID;
|
|
75
|
+
this.countryIDChange.emit(this.countryID);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
onRegionChanged(event) {
|
|
79
|
+
this.geoRegion.set(event.detail.value);
|
|
80
|
+
}
|
|
81
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CountrySelectorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
82
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: CountrySelectorComponent, isStandalone: true, selector: "sneat-country-selector", inputs: { countryID: "countryID", defaultCountryID: "defaultCountryID", readonly: "readonly", disabled: "disabled", label: "label", canBeUnknown: "canBeUnknown" }, outputs: { countryIDChange: "countryIDChange" }, usesOnChanges: true, ngImport: i0, template: "<sneat-select-from-list\n [value]=\"countryID || ''\"\n [isFilterable]=\"true\"\n [filterLabel]=\"label\"\n [label]=\"label\"\n [items]=\"countries()\"\n [(ngModel)]=\"countryID\"\n (ngModelChange)=\"onChanged()\"\n [isReadonly]=\"readonly\"\n [filterItem]=\"filterCountryByCode\"\n (filterChanged)=\"onFilterChanged($event)\"\n labelPlacement=\"start\"\n>\n @if (!countryID && !filter()) {\n <ion-segment [(ngModel)]=\"geoRegion\" (ionChange)=\"onRegionChanged($event)\">\n <ion-segment-button value=\"All\">All</ion-segment-button>\n @for (region of geoRegions; track region.id) {\n <ion-segment-button [value]=\"region.id\">\n <small>{{ region.id }}</small>\n </ion-segment-button>\n }\n </ion-segment>\n }\n</sneat-select-from-list>\n", dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: SelectFromListComponent, selector: "sneat-select-from-list", inputs: ["value", "filterLabel", "label", "listLabel", "listLabelColor", "isFilterable", "isLoading", "items", "items$", "lastItemLines", "labelPlacement", "justify", "other", "canAdd", "filterItem", "selectMode", "isReadonly", "$isProcessing", "sortBy"], outputs: ["valueChange", "filterChanged"] }, { kind: "component", type: IonSegment, selector: "ion-segment", inputs: ["color", "disabled", "mode", "scrollable", "selectOnFocus", "swipeGesture", "value"] }, { kind: "component", type: IonSegmentButton, selector: "ion-segment-button", inputs: ["contentId", "disabled", "layout", "mode", "type", "value"] }] }); }
|
|
83
|
+
}
|
|
84
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CountrySelectorComponent, decorators: [{
|
|
85
|
+
type: Component,
|
|
86
|
+
args: [{ selector: 'sneat-country-selector', imports: [FormsModule, SelectFromListComponent, IonSegment, IonSegmentButton], template: "<sneat-select-from-list\n [value]=\"countryID || ''\"\n [isFilterable]=\"true\"\n [filterLabel]=\"label\"\n [label]=\"label\"\n [items]=\"countries()\"\n [(ngModel)]=\"countryID\"\n (ngModelChange)=\"onChanged()\"\n [isReadonly]=\"readonly\"\n [filterItem]=\"filterCountryByCode\"\n (filterChanged)=\"onFilterChanged($event)\"\n labelPlacement=\"start\"\n>\n @if (!countryID && !filter()) {\n <ion-segment [(ngModel)]=\"geoRegion\" (ionChange)=\"onRegionChanged($event)\">\n <ion-segment-button value=\"All\">All</ion-segment-button>\n @for (region of geoRegions; track region.id) {\n <ion-segment-button [value]=\"region.id\">\n <small>{{ region.id }}</small>\n </ion-segment-button>\n }\n </ion-segment>\n }\n</sneat-select-from-list>\n" }]
|
|
87
|
+
}], propDecorators: { countryID: [{
|
|
88
|
+
type: Input,
|
|
89
|
+
args: [{ required: true }]
|
|
90
|
+
}], defaultCountryID: [{
|
|
91
|
+
type: Input
|
|
92
|
+
}], readonly: [{
|
|
93
|
+
type: Input
|
|
94
|
+
}], disabled: [{
|
|
95
|
+
type: Input
|
|
96
|
+
}], label: [{
|
|
97
|
+
type: Input
|
|
98
|
+
}], canBeUnknown: [{
|
|
99
|
+
type: Input
|
|
100
|
+
}], countryIDChange: [{
|
|
101
|
+
type: Output
|
|
102
|
+
}] } });
|
|
103
|
+
//# sourceMappingURL=country-selector.component.js.map
|