diff --git a/CHANGELOG.md b/CHANGELOG.md index 26965b13148..d45c95a24e5 100755 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,47 @@ # Changelog +## [17.15.0](https://github.com/primefaces/primeng/tree/17.15.0) (2024-04-26) +[Full Changelog](https://github.com/primefaces/primeng/compare/17.14.1...17.15.0) + +**Deprecated:** +- MultiSelect | Deprecate checkicon template [\#15374](https://github.com/primefaces/primeng/issues/15374) + +**Implemented New Features and Enhancements:** +- MultiSelect | Add new checkbox templates [\#15373](https://github.com/primefaces/primeng/issues/15373) +- Autocomplete: optionValue support [\#14599](https://github.com/primefaces/primeng/issues/14599) + +**Fixed bugs:** +- Component: colorPicker - color not updated in selection square with reactive forms [\#15266](https://github.com/primefaces/primeng/issues/15266) +- Component: Checkbox; Array value not working when using with formControlName [\#15185](https://github.com/primefaces/primeng/issues/15185) +- Component: p-fileUpload mode=advanced auto=true not uploading on select [\#15212](https://github.com/primefaces/primeng/issues/15212) +- Dropdown: 'Enter' from numeric pad does not select option [\#15016](https://github.com/primefaces/primeng/issues/15016) +- Component: TreeSelect onFilter returned object [\#15379](https://github.com/primefaces/primeng/issues/15379) +- p-calendar "Date After" filters do not exclude date inclusive [\#14886](https://github.com/primefaces/primeng/issues/14886) +- Dialog: Dialog moves to another position instead of closing after pressing close button [\#15022](https://github.com/primefaces/primeng/issues/15022) +- FilterService: match modes "equals" and "not equals" do not work with numeric filter on fractional values [\#14978](https://github.com/primefaces/primeng/issues/14978) +- TreeSelect Disabled State Not Updating Properly [\#15378](https://github.com/primefaces/primeng/issues/15378) +- Treeselect: Scroll height should be removed when there are no result in treeselect-items. [\#15349](https://github.com/primefaces/primeng/issues/15349) +- Component: KeyFilter [\#14639](https://github.com/primefaces/primeng/issues/14639) +- Menubar: Enter key moves focus at first menuitem [\#15040](https://github.com/primefaces/primeng/issues/15040) +- Fileupload breaks http requests interceptor cycle when imported in a standalone context [\#15360](https://github.com/primefaces/primeng/issues/15360) +- Divider: dotted vertical divider is not working [\#15350](https://github.com/primefaces/primeng/issues/15350) +- SpeedDial: Non-linear menu items are misaligned [\#15367](https://github.com/primefaces/primeng/issues/15367) +- Table: Column resize not working on Ipads/Tablets [\#14803](https://github.com/primefaces/primeng/issues/14803) +- Table: breakpoint property has wrong default value [\#15306](https://github.com/primefaces/primeng/issues/15306) +- Component: Table #15302 [\#15303](https://github.com/primefaces/primeng/issues/15303) +- p-editor only shows unstyled buttons when it's inside of p-sidebar [\#15297](https://github.com/primefaces/primeng/issues/15297) +- Tooltip does not hide on multiSelect clear [\#15304](https://github.com/primefaces/primeng/issues/15304) +- Component: Card [\#15013](https://github.com/primefaces/primeng/issues/15013) + ## [17.14.1](https://github.com/primefaces/primeng/tree/17.14.1) (2024-04-19) [Full Changelog](https://github.com/primefaces/primeng/compare/17.14.0...17.14.1) + **Fixed bugs:** - Stepper | Core css is overriden and broken [\#15317](https://github.com/primefaces/primeng/issues/15317) ## [17.14.0](https://github.com/primefaces/primeng/tree/17.14.0) (2024-04-19) [Full Changelog](https://github.com/primefaces/primeng/compare/17.13.0...17.14.0) -**Breaking Changes:** +**Deprecated:** - Badge | Deprecate "size" property [\#15314](https://github.com/primefaces/primeng/issues/15314) **Implemented New Features and Enhancements:** @@ -779,6 +813,14 @@ - p-dialog: ExpressionChangedAfterItHasBeenCheckedError with attr.aria-labelledby [\#13636](https://github.com/primefaces/primeng/issues/13636) - Textarea: autoResize doesn't work when used inside a Dialog [\#9231](https://github.com/primefaces/primeng/issues/9231) +## [16.4.4](https://github.com/primefaces/primeng/tree/16.4.4) (2024-04-26) + +[Full Changelog](https://github.com/primefaces/primeng/compare/16.4.3...16.4.4) + +**Fixed bugs:** +- TreeTable | selectionKeys support for checkbox selection mode [\#15216](https://github.com/primefaces/primeng/issues/15216) +- p-treeTableHeaderCheckbox doesn't select/unselect all when TreeTable has dataKey property [\#9188](https://github.com/primefaces/primeng/issues/9188) + ## [16.4.3](https://github.com/primefaces/primeng/tree/16.4.3) (2024-01-04) [Full Changelog](https://github.com/primefaces/primeng/compare/16.4.2...16.4.3) diff --git a/LICENSE.md b/LICENSE.md index c6d6640d34c..999fb85bfeb 100755 --- a/LICENSE.md +++ b/LICENSE.md @@ -2,7 +2,7 @@ The MIT License (MIT) -Copyright (c) 2016-2022 PrimeTek +Copyright (c) 2016-2024 PrimeTek Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -30,59 +30,46 @@ The term “Software” includes all source and object code, in whole and/or par ## Summary -* Can be used on unlimited sites and servers -* Source-code cannot be resold or distributed -* Commercial use allowed -* Can modify source-code but cannot distribute modifications (derivative works) +- Can be used on unlimited sites and servers +- Source-code cannot be resold or distributed +- Commercial use allowed +- Can modify source-code but cannot distribute modifications (derivative works) ## Terms and Conditions 1. **License Grant:** Licensor hereby grants Licensee a Personal, Non-assignable and non-transferable, Commercial, Royalty free, Including the rights to create but not distribute derivative works, Non-exclusive license identified with a unique key stated in section 3, all with accordance with the terms set forth and other legal restrictions set forth in 3rd party software used while running Software. - + 1. **Limited:** Licensee may use Software for the purpose of: - + 1. Running Software on Licensee’s Website\[s\] and Server\[s\]; 2. Allowing 3rd Parties to run Software on Licensee’s Website\[s\] and Server\[s\]; 3. Publishing Software’s output to Licensee and 3rd Parties; 4. Distribute verbatim copies of Software’s output (including compiled binaries); 5. Modify Software to suit Licensee’s needs and specifications. + 2. **Non Assignable and Non-Transferable:** Licensee may not assign or transfer his rights and duties under this license. - 3. **Commercial, Royalty Free:** Licensee may use Software for any purpose, including paid-services, without any royalties - 4. **Including the Right to Create Derivative Works:** Licensee may create derivative works based on Software, including amending Software’s source code, modifying it, integrating it into a larger work or removing portions of Software, as long as no distribution of the derivative works is made - + 2. **Term & Termination:** The Term of this license shall be until terminated. Licensor may terminate this Agreement, including Licensee’s license in the case where Licensee : 1. became insolvent or otherwise entered into any liquidation process; or - 2. exported The Software to any jurisdiction where licensor may not enforce his rights under this agreements in; or - 3. Licensee was in breach of any of this license's terms and conditions and such breach was not cured, immediately upon notification; or - 4. Licensee in breach of any of the terms of clause 2 to this license; or - 5. Licensee otherwise entered into any arrangement which caused Licensor to be unable to enforce his rights under this License. - 3. **Payment:** In consideration of the License granted under clause 2, Licensee shall pay Licensor a fee, via credit card or any other mean which Licensor may deem adequate. Failure to perform payment shall construe as material breach of this Agreement. Transaction id of the payment is the unique license key granted to Licensee. 4. **Upgrades, Updates and Fixes:** . - + 1. **Fix:** for the purpose of this license, a fix shall be a minor amendment in The Software, intended to remove bugs or alter minor features which impair the The Software's functionality. A fix shall be marked as a new sub-sub-version number. For example, should Licensee purchase Software under version 1.1.1, an upgrade shall commence under number 1.1.2. - + 5. **Support:** Software is provided under an AS-IS basis and without any support, updates or maintenance. Nothing in this Agreement shall require Licensor to provide Licensee with support or fixes to any bug, failure, mis-performance or other defect in The Software. - 6. **Liability:** To the extent permitted under Law, The Software is provided under an AS-IS basis. Licensor shall never, and without any limit, be liable for any damage, cost, expense or any other payment incurred by Licesee as a result of Software’s actions, failure, bugs and/or any other interaction between The Software and Licesee’s end-equipment, computers, other software or any 3rd party, end-equipment, computer or services. Moreover, Licensor shall never be liable for any defect in source code written by Licensee when relying on The Software or using The Software’s source code. - 7. **Warranty:** - + 1. **Intellectual Property:** Licensor hereby warrants that The Software does not violate or infringe any 3rd party claims in regards to intellectual property, patents and/or trademarks and that to the best of its knowledge no legal action has been taken against it for any infringement or violation of any 3rd party intellectual property rights. - 2. **No-Warranty:** The Software is provided without any warranty; Licensor hereby disclaims any warranty that The Software shall be error free, without defects or code which may cause damage to Licensee’s computers or to Licensee, and that Software shall be functional. Licensee shall be solely liable to any damage, defect or loss incurred as a result of operating software and undertake the risks contained in running The Software on License’s Server\[s\] and Website\[s\]. - 3. **Prior Inspection:** Licensee hereby states that he inspected The Software thoroughly and found it satisfactory and adequate to his needs, that it does not interfere with his regular operation and that it does meet the standards and scope of his computer systems and architecture. Licensee found that The Software interacts with his development, website and server environment and that it does not infringe any of End User License Agreement of any software Licensee may use in performing his services. Licensee hereby waives any claims regarding The Software's incompatibility, performance, results and features, and warrants that he inspected the The Software. - + 8. **No Refunds:** Licensee warrants that he inspected The Software according to clause 7(c) and that it is adequate to his needs. Accordingly, as The Software is intangible goods, Licensee shall not be, ever, entitled to any refund, rebate, compensation or restitution for any reason whatsoever, even if The Software contains material flaws. - 9. **Indemnification:** Licensee hereby warrants to hold Licensor harmless and indemnify Licensor for any lawsuit brought against it in regards to Licensee’s use of The Software in means that violate, breach or otherwise circumvent this license, Licensor's intellectual property rights or Licensor's title in The Software. Licensor shall promptly notify Licensee in case of such legal action and request Licensee’s consent prior to any settlement in relation to such lawsuit or claim. - -10. **Governing Law, Jurisdiction:** Licensee hereby agrees not to initiate class-action lawsuits against Licensor in relation to this license and to compensate Licensor for any legal fees, cost or attorney fees should any claim brought by Licensee against Licensor be denied, in part or in full. - +10. **Governing Law, Jurisdiction:** Licensee hereby agrees not to initiate class-action lawsuits against Licensor in relation to this license and to compensate Licensor for any legal fees, cost or attorney fees should any claim brought by Licensee against Licensor be denied, in part or in full. diff --git a/angular.json b/angular.json index 7673791eebf..c67b15de71b 100644 --- a/angular.json +++ b/angular.json @@ -63,6 +63,10 @@ "rgbcolor" ], "server": "src/main.server.ts", + "prerender": { + "discoverRoutes": false, + "routesFile": "routes.txt" + }, "ssr": { "entry": "server.ts" } diff --git a/package-lock.json b/package-lock.json index fd49c715bb6..2d2912363aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "primeng", - "version": "17.13.0", + "version": "17.15.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "primeng", - "version": "17.13.0", + "version": "17.15.0", "license": "SEE LICENSE IN LICENSE.md", "devDependencies": { "@angular-devkit/build-angular": "^17.3.1", diff --git a/package.json b/package.json index 9866c562398..c3c30a4251f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "primeng", - "version": "17.14.1", + "version": "17.15.0", "license": "SEE LICENSE IN LICENSE.md", "scripts": { "ng": "ng", @@ -10,13 +10,13 @@ "e2e": "ng e2e", "lint": "ng lint", "format": "prettier --write \"**/*.{js,ts,d.ts}\"", + "build": "ng build", "format:check": "prettier --check \"**/*.{js,ts,d.ts}\"", "build:lib": "npm run build:check && npm run build:package", "build:package": "BROWSERSLIST_ENV=library ng build primeng-library && gulp build-assets", "build:check": "npm run format:check && npm run security:check", "security:check": "npm audit --production --audit-level high", - "apidoc": "node ./api-generator/build-apidoc.ts", - "vercel-build": "ng build" + "apidoc": "node ./api-generator/build-apidoc.ts" }, "repository": { "type": "git", diff --git a/routes.txt b/routes.txt new file mode 100644 index 00000000000..3f3eac8186f --- /dev/null +++ b/routes.txt @@ -0,0 +1,130 @@ +/ +/accordion +/animateonscroll +/autocomplete +/autofocus +/avatar +/badge +/blockui +/breadcrumb +/button +/calendar +/card +/carousel +/cascadeselect +/chart +/checkbox +/chip +/chips +/colorpicker +/colors +/configuration +/confirmdialog +/confirmpopup +/contextmenu +/customicons +/dataview +/defer +/dialog +/divider +/dock +/dragdrop +/dropdown +/dynamicdialog +/editor +/fieldset +/fileupload +/filterservice +/floatlabel +/focustrap +/galleria +/guides +/guides/accessibility +/guides/csslayer +/guides/templateupdate +/iconfield +/icons +/image +/inplace +/inputgroup +/inputmask +/inputnumber +/inputotp +/inputswitch +/inputtext +/inputtextarea +/installation +/keyfilter +/knob +/listbox +/lts +/megamenu +/menu +/menubar +/messages +/metergroup +/multiselect +/notfound +/orderlist +/organizationchart +/overlay +/overlaypanel +/paginator +/panel +/panelmenu +/partners +/password +/picklist +/playground +/progressbar +/progressspinner +/radiobutton +/rating +/ripple +/roadmap +/scroller +/scrollpanel +/scrolltop +/selectbutton +/sidebar +/skeleton +/slider +/speeddial +/splitbutton +/splitter +/stepper +/steps +/steps/confirmation +/steps/payment +/steps/personal +/steps/seat +/styleclass +/support +/table +/tabmenu +/tabview +/tag +/team +/templates +/templates/apollo +/templates/atlantis +/templates/avalon +/templates/diamond +/templates/freya +/templates/poseidon +/templates/sakai +/templates/ultima +/templates/verona +/terminal +/theming +/tieredmenu +/timeline +/toast +/togglebutton +/toolbar +/tooltip +/tree +/treeselect +/treetable +/tristatecheckbox +/uikit \ No newline at end of file diff --git a/server.ts b/server.ts index d5e8374acef..4382faf534d 100644 --- a/server.ts +++ b/server.ts @@ -1,27 +1,27 @@ import { APP_BASE_HREF } from '@angular/common'; import { CommonEngine } from '@angular/ssr'; import express from 'express'; -import { join } from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { dirname, join, resolve } from 'node:path'; import bootstrap from './src/main.server'; -import { environment } from 'src/environments/environment'; - // The Express app is exported so that it can be used by serverless Functions. export function app(): express.Express { const server = express(); - const distFolder = join(process.cwd(), 'dist/primeng/browser'); - const indexHtml = join(distFolder, 'index.html'); + const serverDistFolder = dirname(fileURLToPath(import.meta.url)); + const browserDistFolder = resolve(serverDistFolder, '../browser'); + const indexHtml = join(serverDistFolder, 'index.server.html'); const commonEngine = new CommonEngine(); server.set('view engine', 'html'); - server.set('views', distFolder); + server.set('views', browserDistFolder); // Example Express Rest API endpoints // server.get('/api/**', (req, res) => { }); // Serve static files from /browser server.get( '*.*', - express.static(distFolder, { + express.static(browserDistFolder, { maxAge: '1y' }) ); @@ -35,7 +35,7 @@ export function app(): express.Express { bootstrap, documentFilePath: indexHtml, url: `${protocol}://${headers.host}${originalUrl}`, - publicPath: distFolder, + publicPath: browserDistFolder, providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }] }) .then((html) => res.send(html)) @@ -44,3 +44,15 @@ export function app(): express.Express { return server; } + +function run(): void { + const port = process.env['PORT'] || 4000; + + // Start up the Node server + const server = app(); + server.listen(port, () => { + console.log(`Node Express server listening on http://localhost:${port}`); + }); +} + +run(); diff --git a/src/app/components/api/filterservice.spec.ts b/src/app/components/api/filterservice.spec.ts index f6f821abc5b..d2d8f5847fc 100644 --- a/src/app/components/api/filterservice.spec.ts +++ b/src/app/components/api/filterservice.spec.ts @@ -1,16 +1,16 @@ import { FilterService } from './filterservice'; describe('FilterService Suite', () => { let data: any = [ - { brand: 'VW', year: 2012, color: { name: 'Orange' }, vin: 'dsad231ff' }, - { brand: 'Audi', year: 2011, color: { name: 'Black' }, vin: 'gwregre345' }, - { brand: 'Renault', year: 2005, color: { name: 'Black' }, vin: 'h354htr' }, - { brand: 'BMW', year: 2003, color: { name: 'Blue' }, vin: 'j6w54qgh' }, - { brand: 'Mercedes', year: 1995, color: { name: 'Red' }, vin: 'hrtwy34' }, - { brand: 'Volvo', year: 2005, color: { name: 'Orange' }, vin: 'jejtyj' }, - { brand: 'Honda', year: 2012, color: { name: 'Blue' }, vin: 'g43gr' }, - { brand: 'Jaguar', year: 2013, color: { name: 'Black' }, vin: 'greg34' }, - { brand: 'Ford', year: 2000, color: { name: 'White' }, vin: 'h54hw5' }, - { brand: 'Fiat', year: 2013, color: { name: 'Yellow' }, vin: '245t2s' } + { brand: 'VW', year: 2012, color: { name: 'Orange' }, vin: 'dsad231ff', price: '1000.0' }, + { brand: 'Audi', year: 2011, color: { name: 'Black' }, vin: 'gwregre345', price: '4000.0' }, + { brand: 'Renault', year: 2005, color: { name: 'Black' }, vin: 'h354htr', price: '5000.0' }, + { brand: 'BMW', year: 2003, color: { name: 'Blue' }, vin: 'j6w54qgh', price: '3000.0000000' }, + { brand: 'Mercedes', year: 1995, color: { name: 'Red' }, vin: 'hrtwy34', price: '2000.0' }, + { brand: 'Volvo', year: 2005, color: { name: 'Orange' }, vin: 'jejtyj', price: '2000.0' }, + { brand: 'Honda', year: 2012, color: { name: 'Blue' }, vin: 'g43gr', price: '4000.0' }, + { brand: 'Jaguar', year: 2013, color: { name: 'Black' }, vin: 'greg34', price: '1000.0' }, + { brand: 'Ford', year: 2000, color: { name: 'White' }, vin: 'h54hw5', price: '2000.0' }, + { brand: 'Fiat', year: 2013, color: { name: 'Yellow' }, vin: '245t2s', price: '5000.0' } ]; let timeData = [{ date: 'Tue Aug 04 2019 00:00:00 GMT+0300 (GMT+03:00)' }, { date: 'Tue Aug 05 2019 00:00:00 GMT+0300 (GMT+03:00)' }, { date: 'Tue Aug 07 2019 00:00:00 GMT+0300 (GMT+03:00)' }]; @@ -48,6 +48,10 @@ describe('FilterService Suite', () => { expect(filteredValue.length).toEqual(10); filteredValue = filterService.filter(data, [''], 'BMW', 'equals'); expect(filteredValue.length).toEqual(0); + filteredValue = filterService.filter(data, ['price'], 3000, 'equals'); + expect(filteredValue.length).toEqual(1); + filteredValue = filterService.filter(data, ['year'], 2012, 'equals'); + expect(filteredValue.length).toEqual(2); }); it('Should filter by notEquals', () => { let filteredValue = filterService.filter(data, ['brand'], 'BMW', 'notEquals'); @@ -56,6 +60,10 @@ describe('FilterService Suite', () => { expect(filteredValue.length).toEqual(0); filteredValue = filterService.filter(data, [''], 'BMW', 'notEquals'); expect(filteredValue.length).toEqual(10); + filteredValue = filterService.filter(data, ['price'], 3000, 'notEquals'); + expect(filteredValue.length).toEqual(9); + filteredValue = filterService.filter(data, ['year'], 2012, 'notEquals'); + expect(filteredValue.length).toEqual(8); }); it('Should filter by lt', () => { let filteredValue = filterService.filter(timeData, ['date'], 'Tue Aug 05 2019 00:00:00 GMT+0300 (GMT+03:00)', 'lt'); diff --git a/src/app/components/api/filterservice.ts b/src/app/components/api/filterservice.ts index 4df914bcedd..7d97e0d3d66 100644 --- a/src/app/components/api/filterservice.ts +++ b/src/app/components/api/filterservice.ts @@ -93,6 +93,7 @@ export class FilterService { } if (value.getTime && filter.getTime) return value.getTime() === filter.getTime(); + else if (value == filter) return true; else return ObjectUtils.removeAccents(value.toString()).toLocaleLowerCase(filterLocale) == ObjectUtils.removeAccents(filter.toString()).toLocaleLowerCase(filterLocale); }, @@ -106,6 +107,7 @@ export class FilterService { } if (value.getTime && filter.getTime) return value.getTime() !== filter.getTime(); + else if (value == filter) return false; else return ObjectUtils.removeAccents(value.toString()).toLocaleLowerCase(filterLocale) != ObjectUtils.removeAccents(filter.toString()).toLocaleLowerCase(filterLocale); }, @@ -248,6 +250,7 @@ export class FilterService { if (value === undefined || value === null) { return false; } + value.setHours(0, 0, 0, 0); return value.getTime() > filter.getTime(); } diff --git a/src/app/components/autocomplete/autocomplete.ts b/src/app/components/autocomplete/autocomplete.ts index 918cb0ed994..fb19fd8c32b 100755 --- a/src/app/components/autocomplete/autocomplete.ts +++ b/src/app/components/autocomplete/autocomplete.ts @@ -558,6 +558,11 @@ export class AutoComplete implements AfterViewChecked, AfterContentInit, OnDestr * @group Props */ @Input() optionLabel: string | ((item: any) => string) | undefined; + /** + * Property name or getter function to use as the value of an option. + * @group Props + */ + @Input() optionValue: string | ((item: any) => string) | undefined; /** * Unique identifier of the component. * @group Props @@ -768,9 +773,11 @@ export class AutoComplete implements AfterViewChecked, AfterContentInit, OnDestr inputValue = computed(() => { const modelValue = this.modelValue(); + const selectedOption = this.optionValueSelected ? (this.suggestions || []).find((item: any) => ObjectUtils.resolveFieldData(item, this.optionValue) === modelValue) : modelValue; + if (modelValue) { - if (typeof modelValue === 'object') { - const label = this.getOptionLabel(modelValue); + if (typeof modelValue === 'object' || this.optionValueSelected) { + const label = this.getOptionLabel(selectedOption); return label != null ? label : modelValue; } else { @@ -856,6 +863,10 @@ export class AutoComplete implements AfterViewChecked, AfterContentInit, OnDestr return !this.virtualScroll; } + get optionValueSelected() { + return typeof this.modelValue() === 'string' && this.optionValue; + } + constructor(@Inject(DOCUMENT) private document: Document, public el: ElementRef, public renderer: Renderer2, public cd: ChangeDetectorRef, public config: PrimeNGConfig, public overlayService: OverlayService, private zone: NgZone) { effect(() => { this.filled = ObjectUtils.isNotEmpty(this.modelValue()); @@ -1564,7 +1575,7 @@ export class AutoComplete implements AfterViewChecked, AfterContentInit, OnDestr } getOptionValue(option) { - return option; // TODO: The 'optionValue' properties can be added. + return this.optionValue ? ObjectUtils.resolveFieldData(option, this.optionValue) : option && option.value != undefined ? option.value : option; } getOptionIndex(index, scrollerOptions) { diff --git a/src/app/components/badge/badge.ts b/src/app/components/badge/badge.ts index 0833ce52730..16994fb0f71 100755 --- a/src/app/components/badge/badge.ts +++ b/src/app/components/badge/badge.ts @@ -27,7 +27,7 @@ export class BadgeDirective implements OnChanges, AfterViewInit { /** * Size of the badge, valid options are "large" and "xlarge". * @group Props - * @deprecated + * @deprecated use badgeSize instead. */ @Input() public set size(value: 'large' | 'xlarge') { this._size = value; @@ -237,7 +237,7 @@ export class Badge { /** * Size of the badge, valid options are "large" and "xlarge". * @group Props - * @deprecated + * @deprecated use badgeSize instead. */ @Input() public set size(value: 'large' | 'xlarge') { this._size = value; diff --git a/src/app/components/card/card.ts b/src/app/components/card/card.ts index d81c1f6a1a2..c4db6adf4e9 100755 --- a/src/app/components/card/card.ts +++ b/src/app/components/card/card.ts @@ -1,6 +1,7 @@ import { CommonModule } from '@angular/common'; -import { AfterContentInit, ChangeDetectionStrategy, Component, ContentChild, ContentChildren, ElementRef, Input, NgModule, QueryList, TemplateRef, ViewEncapsulation } from '@angular/core'; +import { AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, ContentChild, ContentChildren, ElementRef, Input, NgModule, QueryList, SimpleChange, TemplateRef, ViewEncapsulation, signal } from '@angular/core'; import { BlockableUI, Footer, Header, PrimeTemplate, SharedModule } from 'primeng/api'; +import { ObjectUtils } from 'primeng/utils'; /** * Card is a flexible container component. * @group Components @@ -8,7 +9,7 @@ import { BlockableUI, Footer, Header, PrimeTemplate, SharedModule } from 'primen @Component({ selector: 'p-card', template: ` -
+
@@ -55,7 +56,11 @@ export class Card implements AfterContentInit, BlockableUI { * Inline style of the element. * @group Props */ - @Input() style: { [klass: string]: any } | null | undefined; + @Input() set style(value: { [klass: string]: any } | null | undefined) { + if (!ObjectUtils.equals(this._style(), value)) { + this._style.set(value); + } + } /** * Class of the element. * @group Props @@ -78,6 +83,8 @@ export class Card implements AfterContentInit, BlockableUI { footerTemplate: TemplateRef | undefined; + _style = signal<{ [klass: string]: any } | null | undefined>(null); + constructor(private el: ElementRef) {} ngAfterContentInit() { diff --git a/src/app/components/checkbox/checkbox.ts b/src/app/components/checkbox/checkbox.ts index 3c451482fa1..9bcaefbff45 100755 --- a/src/app/components/checkbox/checkbox.ts +++ b/src/app/components/checkbox/checkbox.ts @@ -8,6 +8,7 @@ import { ElementRef, EventEmitter, forwardRef, + Injector, Input, NgModule, numberAttribute, @@ -17,7 +18,7 @@ import { ViewChild, ViewEncapsulation } from '@angular/core'; -import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms'; import { PrimeTemplate, SharedModule } from 'primeng/api'; import { AutoFocusModule } from 'primeng/autofocus'; import { CheckIcon } from 'primeng/icons/check'; @@ -235,7 +236,7 @@ export class Checkbox implements ControlValueAccessor { focused: boolean = false; - constructor(public cd: ChangeDetectorRef) {} + constructor(public cd: ChangeDetectorRef, private readonly injector: Injector) {} ngAfterContentInit() { this.templates.forEach((item) => { @@ -264,9 +265,18 @@ export class Checkbox implements ControlValueAccessor { updateModel(event) { let newModelValue; + /* + * When `formControlName` or `formControl` is used - `writeValue` is not called after control changes. + * Otherwise it is causing multiple references to the actual value: there is one array reference inside the component and another one in the control value. + * `selfControl` is the source of truth of references, it is made to avoid reference loss. + * */ + const selfControl = this.injector.get(NgControl, null, { optional: true, self: true }); + + const currentModelValue = selfControl && !this.formControl ? selfControl.value : this.model; + if (!this.binary) { - if (this.checked()) newModelValue = this.model.filter((val) => !ObjectUtils.equals(val, this.value)); - else newModelValue = this.model ? [...this.model, this.value] : [this.value]; + if (this.checked()) newModelValue = currentModelValue.filter((val) => !ObjectUtils.equals(val, this.value)); + else newModelValue = currentModelValue ? [...currentModelValue, this.value] : [this.value]; this.onModelChange(newModelValue); this.model = newModelValue; diff --git a/src/app/components/colorpicker/colorpicker.ts b/src/app/components/colorpicker/colorpicker.ts index 34182d15364..fb2c2593dd0 100755 --- a/src/app/components/colorpicker/colorpicker.ts +++ b/src/app/components/colorpicker/colorpicker.ts @@ -379,6 +379,7 @@ export class ColorPicker implements ControlValueAccessor, OnDestroy { updateModel(): void { this.onModelChange(this.getValueToUpdate()); + this.cd.markForCheck(); } writeValue(value: any): void { diff --git a/src/app/components/confirmpopup/confirmpopup.ts b/src/app/components/confirmpopup/confirmpopup.ts index c966c3f7458..46fd3371aec 100755 --- a/src/app/components/confirmpopup/confirmpopup.ts +++ b/src/app/components/confirmpopup/confirmpopup.ts @@ -299,7 +299,7 @@ export class ConfirmPopup implements AfterContentInit, OnDestroy { if (!this.confirmation) { return; } - DomHandler.absolutePosition(this.container, this.confirmation?.target); + DomHandler.absolutePosition(this.container, this.confirmation?.target, false); const containerOffset = DomHandler.getOffset(this.container); const targetOffset = DomHandler.getOffset(this.confirmation?.target); diff --git a/src/app/components/dialog/dialog.ts b/src/app/components/dialog/dialog.ts index 14f284d4a2c..01bd042f87a 100755 --- a/src/app/components/dialog/dialog.ts +++ b/src/app/components/dialog/dialog.ts @@ -706,7 +706,7 @@ export class Dialog implements AfterContentInit, OnInit, OnDestroy { } initDrag(event: MouseEvent) { - if (DomHandler.hasClass(event.target, 'p-dialog-header-icon') || DomHandler.hasClass((event.target).parentElement, 'p-dialog-header-icon')) { + if (DomHandler.hasClass(event.target, 'p-dialog-header-icon') || DomHandler.hasClass(event.target, 'p-dialog-header-close-icon') || DomHandler.hasClass((event.target).parentElement, 'p-dialog-header-icon')) { return; } diff --git a/src/app/components/divider/divider.css b/src/app/components/divider/divider.css index 2738f847c0b..e64ed71bcc9 100644 --- a/src/app/components/divider/divider.css +++ b/src/app/components/divider/divider.css @@ -80,7 +80,7 @@ border-top-style: dotted; } - .p-divider-dotted.p-divider-horizontal:before { + .p-divider-dotted.p-divider-vertical:before { border-left-style: dotted; } } diff --git a/src/app/components/dom/domhandler.ts b/src/app/components/dom/domhandler.ts index 9a610179d3f..5ee8c37821b 100755 --- a/src/app/components/dom/domhandler.ts +++ b/src/app/components/dom/domhandler.ts @@ -118,7 +118,7 @@ export class DomHandler { } } - public static relativePosition(element: any, target: any): void { + public static relativePosition(element: any, target: any, gutter: boolean = true): void { const getClosestRelativeElement = (el) => { if (!el) return; @@ -161,9 +161,10 @@ export class DomHandler { element.style.top = top + 'px'; element.style.left = left + 'px'; + gutter && (element.style.marginTop = origin === 'bottom' ? 'calc(var(--p-anchor-gutter) * -1)' : 'calc(var(--p-anchor-gutter))'); } - public static absolutePosition(element: any, target: any): void { + public static absolutePosition(element: any, target: any, gutter: boolean = true): void { const elementDimensions = element.offsetParent ? { width: element.offsetWidth, height: element.offsetHeight } : this.getHiddenElementDimensions(element); const elementOuterHeight = elementDimensions.height; const elementOuterWidth = elementDimensions.width; @@ -192,6 +193,7 @@ export class DomHandler { element.style.top = top + 'px'; element.style.left = left + 'px'; + gutter && (element.style.marginTop = origin === 'bottom' ? 'calc(var(--p-anchor-gutter) * -1)' : 'calc(var(--p-anchor-gutter))'); } static getParents(element: any, parents: any = []): any { diff --git a/src/app/components/dropdown/dropdown.interface.ts b/src/app/components/dropdown/dropdown.interface.ts index fc00cad6473..3a0bf5f5c07 100644 --- a/src/app/components/dropdown/dropdown.interface.ts +++ b/src/app/components/dropdown/dropdown.interface.ts @@ -66,7 +66,7 @@ export interface DropdownLazyLoadEvent { */ export interface DropdownTemplates { /** - * Custom header template. + * Custom item template. * @param {Object} context - item data. */ item(context: { diff --git a/src/app/components/dropdown/dropdown.ts b/src/app/components/dropdown/dropdown.ts index e0f58eb78ab..cd92bbc78be 100755 --- a/src/app/components/dropdown/dropdown.ts +++ b/src/app/components/dropdown/dropdown.ts @@ -1497,6 +1497,7 @@ export class Dropdown implements OnInit, AfterViewInit, AfterContentInit, AfterV break; case 'Enter': + case 'NumpadEnter': this.onEnterKey(event, true); break; diff --git a/src/app/components/editor/editor.ts b/src/app/components/editor/editor.ts index 9e578437fe7..0690125d1ac 100755 --- a/src/app/components/editor/editor.ts +++ b/src/app/components/editor/editor.ts @@ -200,10 +200,7 @@ export class Editor implements AfterContentInit, ControlValueAccessor { */ afterNextRender(() => { this.initQuillElements(); - - if (this.isAttachedQuillEditorToDOM) { - this.initQuillEditor(); - } + this.initQuillEditor(); }); } diff --git a/src/app/components/fileupload/fileupload.ts b/src/app/components/fileupload/fileupload.ts index ecc54ff1c5c..1fddc8100dc 100755 --- a/src/app/components/fileupload/fileupload.ts +++ b/src/app/components/fileupload/fileupload.ts @@ -1,5 +1,5 @@ import { CommonModule, DOCUMENT, isPlatformBrowser } from '@angular/common'; -import { HttpClient, HttpClientModule, HttpEvent, HttpEventType, HttpHeaders } from '@angular/common/http'; +import { HttpClient, HttpEvent, HttpEventType, HttpHeaders } from '@angular/common/http'; import { AfterContentInit, AfterViewInit, @@ -584,7 +584,7 @@ export class FileUpload implements AfterViewInit, AfterContentInit, OnInit, OnDe // this will check the fileLimit with the uploaded files this.checkFileLimit(files); - if (this.hasFiles() && this.auto && (!(this.mode === 'advanced') || !this.isFileLimitExceeded())) { + if (this.hasFiles() && this.auto && (this.mode !== 'advanced' || !this.isFileLimitExceeded())) { this.upload(); } @@ -932,7 +932,7 @@ export class FileUpload implements AfterViewInit, AfterContentInit, OnInit, OnDe } @NgModule({ - imports: [CommonModule, HttpClientModule, SharedModule, ButtonModule, ProgressBarModule, MessagesModule, RippleModule, PlusIcon, UploadIcon, TimesIcon], + imports: [CommonModule, SharedModule, ButtonModule, ProgressBarModule, MessagesModule, RippleModule, PlusIcon, UploadIcon, TimesIcon], exports: [FileUpload, SharedModule, ButtonModule, ProgressBarModule, MessagesModule], declarations: [FileUpload] }) diff --git a/src/app/components/keyfilter/keyfilter.ts b/src/app/components/keyfilter/keyfilter.ts index cd9d2f71d55..3870746e09e 100755 --- a/src/app/components/keyfilter/keyfilter.ts +++ b/src/app/components/keyfilter/keyfilter.ts @@ -1,7 +1,7 @@ -import { NgModule, Directive, ElementRef, HostListener, Input, forwardRef, Output, EventEmitter, Inject, PLATFORM_ID, Provider, booleanAttribute } from '@angular/core'; import { CommonModule, DOCUMENT, isPlatformBrowser } from '@angular/common'; +import { Directive, ElementRef, EventEmitter, HostListener, Inject, Input, NgModule, Output, PLATFORM_ID, Provider, booleanAttribute, forwardRef } from '@angular/core'; +import { AbstractControl, NG_VALIDATORS, Validator } from '@angular/forms'; import { DomHandler } from 'primeng/dom'; -import { Validator, AbstractControl, NG_VALIDATORS } from '@angular/forms'; import { KeyFilterPattern } from './keyfilter.interface'; export const KEYFILTER_VALIDATOR: Provider = { @@ -31,15 +31,15 @@ type Keys = { }; const DEFAULT_MASKS: Record = { - pint: /[\d]/, - int: /[\d\-]/, - pnum: /[\d\.]/, - money: /[\d\.\s,]/, - num: /[\d\-\.]/, - hex: /[0-9a-f]/i, - email: /[a-z0-9_\.\-@]/i, - alpha: /[a-z_]/i, - alphanum: /[a-z0-9_]/i + pint: /^[\d]*$/, + int: /^[-]?[\d]*$/, + pnum: /^[\d\.]*$/, + money: /^[\d\.\s,]*$/, + num: /^[-]?[\d\.]*$/, + hex: /^[0-9a-f]*$/i, + email: /^[a-z0-9_\.\-@]*$/i, + alpha: /^[a-z_]*$/i, + alphanum: /^[a-z0-9_]*$/i }; const KEYS: Keys = { @@ -225,8 +225,8 @@ export class KeyFilter implements Validator { if (!browser.mozilla && (this.isSpecialKey(e) || !cc)) { return; } - - ok = (this.regex).test(cc); + let val = this.el.nativeElement.value + cc; + ok = (this.regex).test(val); if (!ok) { e.preventDefault(); diff --git a/src/app/components/menubar/menubar.ts b/src/app/components/menubar/menubar.ts index 9fe3bb1f8a4..600f2a1e9d6 100755 --- a/src/app/components/menubar/menubar.ts +++ b/src/app/components/menubar/menubar.ts @@ -1049,11 +1049,6 @@ export class Menubar implements AfterContentInit, OnDestroy, OnInit { const anchorElement = element && DomHandler.findSingle(element, 'a[data-pc-section="action"]'); anchorElement ? anchorElement.click() : element && element.click(); - - const processedItem = this.visibleItems[this.focusedItemInfo().index]; - const grouped = this.isProccessedItemGroup(processedItem); - - !grouped && (this.focusedItemInfo().index = this.findFirstFocusedItemIndex()); } event.preventDefault(); diff --git a/src/app/components/multiselect/multiselect.interface.ts b/src/app/components/multiselect/multiselect.interface.ts index 4721c38be4e..ebb1ee5e904 100644 --- a/src/app/components/multiselect/multiselect.interface.ts +++ b/src/app/components/multiselect/multiselect.interface.ts @@ -196,8 +196,31 @@ export interface MultiSelectTemplates { filtericon(): TemplateRef; /** * Custom check icon template. + * @deprecated Use headercheckboxicon or itemcheckboxicon instead. */ checkicon(): TemplateRef; + /** + * Custom check icon template for the header checkbox. + */ + headercheckboxicon(context: { + /** + * Defines if all items are selected. + */ + $implicit: boolean; + /** + * Defines if items are partially selected. + */ + partialSelected: boolean; + }): TemplateRef<{ $implicit: boolean; partialSelected: boolean }>; + /** + * Custom check icon template for the item checkbox. + */ + itemcheckboxicon(context: { + /** + * Selection status of the item. + */ + $implicit: boolean; + }): TemplateRef<{ $implicit: boolean }>; /** * Custom close icon template. */ diff --git a/src/app/components/multiselect/multiselect.ts b/src/app/components/multiselect/multiselect.ts index 76de3be2c45..a4bd07759f4 100755 --- a/src/app/components/multiselect/multiselect.ts +++ b/src/app/components/multiselect/multiselect.ts @@ -47,6 +47,7 @@ import { ChevronDownIcon } from 'primeng/icons/chevrondown'; import { Nullable } from 'primeng/ts-helpers'; import { AutoFocusModule } from 'primeng/autofocus'; import { MultiSelectRemoveEvent, MultiSelectFilterOptions, MultiSelectFilterEvent, MultiSelectBlurEvent, MultiSelectChangeEvent, MultiSelectFocusEvent, MultiSelectLazyLoadEvent, MultiSelectSelectAllChangeEvent } from './multiselect.interface'; +import { MinusIcon } from 'primeng/icons/minus'; export const MULTISELECT_VALUE_ACCESSOR: any = { provide: NG_VALUE_ACCESSOR, @@ -78,9 +79,10 @@ export const MULTISELECT_VALUE_ACCESSOR: any = {
- + - + +
@@ -117,6 +119,8 @@ export class MultiSelectItem { @Input() checkIconTemplate: TemplateRef | undefined; + @Input() itemCheckboxIconTemplate: TemplateRef | undefined; + @Output() onClick: EventEmitter = new EventEmitter(); @Output() onMouseEnter: EventEmitter = new EventEmitter(); @@ -170,7 +174,15 @@ export class MultiSelectItem { [autofocus]="autofocus" />
-
+
{{ label() || 'empty' }} @@ -263,11 +275,17 @@ export class MultiSelectItem { [attr.aria-checked]="allSelected()" [ngClass]="{ 'p-highlight': allSelected(), 'p-focus': headerCheckboxFocus, 'p-disabled': disabled || toggleAllDisabled }" > - - + + + + + + + +
@@ -349,6 +367,7 @@ export class MultiSelectItem { [disabled]="isOptionDisabled(option)" [template]="itemTemplate" [checkIconTemplate]="checkIconTemplate" + [itemCheckboxIconTemplate]="itemCheckboxIconTemplate" [itemSize]="scrollerOptions.itemSize" [focused]="focusedOptionIndex() === getOptionIndex(i, scrollerOptions)" [ariaPosInset]="getAriaPosInset(getOptionIndex(i, scrollerOptions))" @@ -921,6 +940,8 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft _selectionLimit: number | undefined; + _disableTooltip = false; + value: any[]; public _filteredOptions: any[] | undefined | null; @@ -965,6 +986,10 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft dropdownIconTemplate: TemplateRef | undefined; + itemCheckboxIconTemplate: TemplateRef | undefined; + + headerCheckboxIconTemplate: TemplateRef | undefined; + public headerCheckboxFocus: boolean | undefined; filterOptions: MultiSelectFilterOptions | undefined; @@ -1196,6 +1221,11 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft case 'checkicon': this.checkIconTemplate = item.template; + console.warn('checkicon is deprecated and will removed in v18. Use itemcheckboxicon or headercheckboxicon templates instead.'); + break; + + case 'headercheckboxicon': + this.headerCheckboxIconTemplate = item.template; break; case 'filtericon': @@ -1218,6 +1248,10 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft this.dropdownIconTemplate = item.template; break; + case 'itemcheckboxicon': + this.itemCheckboxIconTemplate = item.template; + break; + default: this.itemTemplate = item.template; break; @@ -1872,6 +1906,11 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft } } + if (this.partialSelected()) { + this.selectedOptions = null; + this.cd.markForCheck(); + } + this.onChange.emit({ originalEvent: event, value: this.value }); DomHandler.focus(this.headerCheckboxViewChild?.nativeElement); this.headerCheckboxFocus = true; @@ -1932,6 +1971,10 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft return this.selectAll !== null ? this.selectAll : ObjectUtils.isNotEmpty(this.visibleOptions()) && this.visibleOptions().every((option) => this.isOptionGroup(option) || this.isOptionDisabled(option) || this.isSelected(option)); } + partialSelected() { + return this.selectedOptions && this.selectedOptions.length > 0 && this.selectedOptions.length < this.options.length; + } + /** * Displays the panel. * @group Method @@ -2025,10 +2068,15 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft this.updateModel(null, event); this.selectedOptions = null; this.onClear.emit(); + this._disableTooltip = true; event.stopPropagation(); } + labelContainerMouseLeave() { + if (this._disableTooltip) this._disableTooltip = false; + } + removeOption(optionValue, event) { let value = this.modelValue().filter((val) => !ObjectUtils.equals(val, optionValue, this.equalityKey())); @@ -2160,7 +2208,7 @@ export class MultiSelect implements OnInit, AfterViewInit, AfterContentInit, Aft } @NgModule({ - imports: [CommonModule, OverlayModule, SharedModule, TooltipModule, RippleModule, ScrollerModule, AutoFocusModule, CheckIcon, SearchIcon, TimesCircleIcon, TimesIcon, ChevronDownIcon, CheckIcon], + imports: [CommonModule, OverlayModule, SharedModule, TooltipModule, RippleModule, ScrollerModule, AutoFocusModule, CheckIcon, SearchIcon, TimesCircleIcon, TimesIcon, ChevronDownIcon, CheckIcon, MinusIcon], exports: [MultiSelect, OverlayModule, SharedModule, ScrollerModule], declarations: [MultiSelect, MultiSelectItem] }) diff --git a/src/app/components/overlaypanel/overlaypanel.ts b/src/app/components/overlaypanel/overlaypanel.ts index d272d24637a..7c198fc2482 100755 --- a/src/app/components/overlaypanel/overlaypanel.ts +++ b/src/app/components/overlaypanel/overlaypanel.ts @@ -340,7 +340,7 @@ export class OverlayPanel implements AfterContentInit, OnDestroy { ZIndexUtils.set('overlay', this.container, this.baseZIndex + this.config.zIndex.overlay); } - DomHandler.absolutePosition(this.container, this.target); + DomHandler.absolutePosition(this.container, this.target, false); const containerOffset = DomHandler.getOffset(this.container); const targetOffset = DomHandler.getOffset(this.target); diff --git a/src/app/components/package.json b/src/app/components/package.json index c84b358ef67..4418e8a2d97 100644 --- a/src/app/components/package.json +++ b/src/app/components/package.json @@ -1,6 +1,6 @@ { "name": "primeng", - "version": "17.14.1", + "version": "17.15.0", "repository": { "type": "git", "url": "https://github.com/primefaces/primeng" diff --git a/src/app/components/speeddial/speeddial.css b/src/app/components/speeddial/speeddial.css index f6f7dd57b38..c2fd94184a9 100755 --- a/src/app/components/speeddial/speeddial.css +++ b/src/app/components/speeddial/speeddial.css @@ -5,6 +5,14 @@ z-index: 1; } + .p-speeddial:not(.p-speeddial-opened) { + pointer-events: none; + } + + .p-speeddial:not(.p-speeddial-opened) .p-speeddial-button { + pointer-events: auto; + } + .p-speeddial-list { margin: 0; padding: 0; diff --git a/src/app/components/speeddial/speeddial.ts b/src/app/components/speeddial/speeddial.ts index c0445e208b9..4db568de217 100644 --- a/src/app/components/speeddial/speeddial.ts +++ b/src/app/components/speeddial/speeddial.ts @@ -92,7 +92,7 @@ import { asapScheduler } from 'rxjs'; item.id === this.focusedOptionIndex); + const itemIndex = [...items].findIndex((item) => item.id === this.focusedOptionIndex()); this.onItemClick(event, this.model[itemIndex]); this.onBlur(event); diff --git a/src/app/components/stepper/stepper.ts b/src/app/components/stepper/stepper.ts index eec4da175fc..95fb22be473 100755 --- a/src/app/components/stepper/stepper.ts +++ b/src/app/components/stepper/stepper.ts @@ -129,10 +129,6 @@ export class StepperContent { @Output() nextCallback = new EventEmitter(); } -/** - * StepperPanel is a helper component for Stepper component. - * @group Components - */ @Component({ selector: 'p-stepperPanel', template: ` `, @@ -141,10 +137,6 @@ export class StepperContent { } }) export class StepperPanel { - /** - * Orientation of tab headers. - * @group Props - */ @Input() header: string | undefined; @ContentChildren(PrimeTemplate) templates: Nullable>; diff --git a/src/app/components/stepper/stepperpanel.interface.ts b/src/app/components/stepper/stepperpanel.interface.ts index d894fc32d4d..52e1e2fd634 100644 --- a/src/app/components/stepper/stepperpanel.interface.ts +++ b/src/app/components/stepper/stepperpanel.interface.ts @@ -1,4 +1,15 @@ import { TemplateRef } from '@angular/core'; +/** + * StepperPanel is a helper component for Stepper component. + * @group Components + */ +export interface StepperPanelProps { + /** + * Orientation of tab headers. + * @group Props + */ + header: string | undefined; +} /** * Defines valid templates in StepperPanel. @@ -8,11 +19,11 @@ export interface StepperPanelTemplates { /** * Custom header template. */ - header(context: StepperPanelHeaderProps): TemplateRef; + header(context: StepperPanelHeaderTemplate): TemplateRef; /** * Custom header template. */ - content(context: StepperPanelContentProps): TemplateRef; + content(context: StepperPanelContentTemplate): TemplateRef; /** * Custom separator template. */ @@ -23,7 +34,7 @@ export interface StepperPanelTemplates { * Props of stepper panel header. * @group Interface */ -export interface StepperPanelHeaderProps { +export interface StepperPanelHeaderTemplate { /** * Index of the stepperpanel. */ @@ -62,7 +73,7 @@ export interface StepperPanelHeaderProps { * Props of stepper panel content. * @group Interface */ -export interface StepperPanelContentProps { +export interface StepperPanelContentTemplate { /** * Index of the stepperpanel. */ diff --git a/src/app/components/table/columnfilter.interface.ts b/src/app/components/table/columnfilter.interface.ts index e752589f0a6..e7b3b01d700 100644 --- a/src/app/components/table/columnfilter.interface.ts +++ b/src/app/components/table/columnfilter.interface.ts @@ -1,4 +1,5 @@ import { TemplateRef } from '@angular/core'; +import { SelectItem } from 'primeng/api'; /** * Defines valid templates in Column Filter. @@ -8,7 +9,68 @@ export interface TableColumnFilterTemplates { /** * Custom filter template. */ - filterTemplate(): TemplateRef; + filterTemplate(context: { + /** + * filterConstraint.value. + */ + $implicit?: string; + /** + * filter callback. + */ + filterCallback?: (value: string) => void; + /** + * Type of the input. + */ + type?: string; + /** + * Filter constraint. + */ + filterConstraint?: string; + /** + * Input placeholder. + */ + placeholder?: boolean; + /** + * Minimum fraction of digits. + */ + minFractionDigits?: number; + /** + * Maximum fraction of digits. + */ + maxFractionDigits?: number; + /** + * Input prefix. + */ + prefix?: string; + /** + * Input suffix. + */ + suffix?: string; + /** + * Locale. + */ + locale?: string; + /** + * Locale matcher. + */ + localeMatcher?: string; + /** + * Enables currency input. + */ + currency?: boolean; + /** + * Display of the currency input. + */ + currencyDisplay?: boolean; + /** + * Defines if filter grouping will be enabled. + */ + useGrouping?: boolean; + /** + * Defines the visibility of buttons. + */ + showButtons?: boolean; + }): TemplateRef; /** * Custom header template. */ @@ -34,3 +96,154 @@ export interface TableColumnFilterTemplates { */ clearFilterIconTemplate(): TemplateRef; } + +/** + * Defines valid properties in ColumnFilter component. + * @group Components + */ +export interface ColumnFilterProps { + /** + * Property represented by the column. + * @defaultValue text + * @group Props + */ + field: string | undefined; + /** + * Type of the input. + * @defaultValue text + * @group Props + */ + type: string; + /** + * Filter display. + * @defaultValue row + * @group Props + */ + display: string; + /** + * Decides whether to display filter menu popup. + * @defaultValue true + * @group Props + */ + showMenu: boolean; + /** + * Filter match mode. + * @group Props + */ + matchMode: string | undefined; + /** + * Filter operator. + * @defaultValue 'AND' + * @group Props + */ + operator: string; + /** + * Decides whether to display filter operator. + * @defaultValue true + * @group Props + */ + showOperator: boolean; + /** + * Decides whether to display clear filter button. + * @defaultValue true + * @group Props + */ + showClearButton: boolean; + /** + * Decides whether to display apply filter button. + * @defaultValue true + * @group Props + */ + showApplyButton: boolean; + /** + * Decides whether to display filter match modes. + * @defaultValue true + * @group Props + */ + showMatchModes: boolean; + /** + * Decides whether to display add filter button. + * @defaultValue true + * @group Props + */ + showAddButton: boolean; + /** + * Decides whether to close popup on clear button click. + * @defaultValue true + * @group Props + */ + hideOnClear: boolean; + /** + * Filter placeholder. + * @group Props + */ + placeholder: string | undefined; + /** + * Filter match mode options. + * @group Props + */ + matchModeOptions: SelectItem[] | undefined; + /** + * Defines maximum amount of constraints. + * @defaultValue 2 + * @group Props + */ + maxConstraints: number; + /** + * Defines minimum fraction of digits. + * @group Props + */ + minFractionDigits: number | undefined; + /** + * Defines maximum fraction of digits. + * @group Props + */ + maxFractionDigits: number | undefined; + /** + * Defines prefix of the filter. + * @group Props + */ + prefix: string | undefined; + /** + * Defines suffix of the filter. + * @group Props + */ + suffix: string | undefined; + /** + * Defines filter locale. + * @group Props + */ + locale: string | undefined; + /** + * Defines filter locale matcher. + * @group Props + */ + localeMatcher: string | undefined; + /** + * Enables currency input. + * @group Props + */ + currency: boolean | undefined; + /** + * Defines the display of the currency input. + * @group Props + */ + currencyDisplay: string | undefined; + /** + * Defines if filter grouping will be enabled. + * @defaultValue true + * @group Props + */ + useGrouping: boolean; + /** + * Defines the visibility of buttons. + * @defaultValue true + * @group Props + */ + showButtons: boolean; + /** + * Defines the aria-label of the form element. + * @group Props + */ + ariaLabel: string | undefined; +} diff --git a/src/app/components/table/table.ts b/src/app/components/table/table.ts index 9d08e9b4e86..92b17555df0 100644 --- a/src/app/components/table/table.ts +++ b/src/app/components/table/table.ts @@ -708,7 +708,7 @@ export class Table implements OnInit, AfterViewInit, AfterContentInit, Blockable * The breakpoint to define the maximum width boundary when using stack responsive layout. * @group Props */ - @Input() breakpoint: string = '640px'; + @Input() breakpoint: string = '960px'; /** * Locale to be used in paginator formatting. * @group Props @@ -2483,7 +2483,11 @@ export class Table implements OnInit, AfterViewInit, AfterContentInit, Blockable let containerLeft = DomHandler.getOffset(this.containerViewChild?.nativeElement).left; this.resizeColumnElement = event.target.parentElement; this.columnResizing = true; - this.lastResizerHelperX = event.pageX - containerLeft + this.containerViewChild?.nativeElement.scrollLeft; + if (event.type == 'touchstart') { + this.lastResizerHelperX = event.changedTouches[0].clientX - containerLeft + this.containerViewChild?.nativeElement.scrollLeft; + } else { + this.lastResizerHelperX = event.pageX - containerLeft + this.containerViewChild?.nativeElement.scrollLeft; + } this.onColumnResize(event); event.preventDefault(); } @@ -2493,8 +2497,11 @@ export class Table implements OnInit, AfterViewInit, AfterContentInit, Blockable DomHandler.addClass(this.containerViewChild?.nativeElement, 'p-unselectable-text'); (this.resizeHelperViewChild).nativeElement.style.height = this.containerViewChild?.nativeElement.offsetHeight + 'px'; (this.resizeHelperViewChild).nativeElement.style.top = 0 + 'px'; - (this.resizeHelperViewChild).nativeElement.style.left = event.pageX - containerLeft + this.containerViewChild?.nativeElement.scrollLeft + 'px'; - + if (event.type == 'touchmove') { + (this.resizeHelperViewChild).nativeElement.style.left = event.changedTouches[0].clientX - containerLeft + this.containerViewChild?.nativeElement.scrollLeft + 'px'; + } else { + (this.resizeHelperViewChild).nativeElement.style.left = event.pageX - containerLeft + this.containerViewChild?.nativeElement.scrollLeft + 'px'; + } (this.resizeHelperViewChild).nativeElement.style.display = 'block'; } @@ -3305,11 +3312,22 @@ export class FrozenColumn implements AfterViewInit { ngAfterViewInit() { this.zone.runOutsideAngular(() => { setTimeout(() => { - this.updateStickyPosition(); + this.recalculateColumns(); }, 1000); }); } + @HostListener('window:resize', ['$event']) + recalculateColumns() { + const siblings = DomHandler.siblings(this.el.nativeElement); + const index = DomHandler.index(this.el.nativeElement); + const time = (siblings.length - index + 1) * 50; + + setTimeout(() => { + this.updateStickyPosition(); + }, time); + } + _frozen: boolean = true; updateStickyPosition() { @@ -3904,6 +3922,12 @@ export class ResizableColumn implements AfterViewInit, OnDestroy { resizerMouseDownListener: VoidListener; + resizerTouchStartListener: VoidListener; + + resizerTouchMoveListener: VoidListener; + + resizerTouchEndListener: VoidListener; + documentMouseMoveListener: VoidListener; documentMouseUpListener: VoidListener; @@ -3920,6 +3944,7 @@ export class ResizableColumn implements AfterViewInit, OnDestroy { this.zone.runOutsideAngular(() => { this.resizerMouseDownListener = this.renderer.listen(this.resizer, 'mousedown', this.onMouseDown.bind(this)); + this.resizerTouchStartListener = this.renderer.listen(this.resizer, 'touchstart', this.onTouchStart.bind(this)); }); } } @@ -3929,6 +3954,8 @@ export class ResizableColumn implements AfterViewInit, OnDestroy { this.zone.runOutsideAngular(() => { this.documentMouseMoveListener = this.renderer.listen(this.document, 'mousemove', this.onDocumentMouseMove.bind(this)); this.documentMouseUpListener = this.renderer.listen(this.document, 'mouseup', this.onDocumentMouseUp.bind(this)); + this.resizerTouchMoveListener = this.renderer.listen(this.resizer, 'touchmove', this.onTouchMove.bind(this)); + this.resizerTouchEndListener = this.renderer.listen(this.resizer, 'touchend', this.onTouchEnd.bind(this)); }); } @@ -3942,15 +3969,30 @@ export class ResizableColumn implements AfterViewInit, OnDestroy { this.documentMouseUpListener(); this.documentMouseUpListener = null; } + if (this.resizerTouchMoveListener) { + this.resizerTouchMoveListener(); + this.resizerTouchMoveListener = null; + } + + if (this.resizerTouchEndListener) { + this.resizerTouchEndListener(); + this.resizerTouchEndListener = null; + } } onMouseDown(event: MouseEvent) { - if (event.which === 1) { - this.dt.onColumnResizeBegin(event); - this.bindDocumentEvents(); - } + this.dt.onColumnResizeBegin(event); + this.bindDocumentEvents(); + } + + onTouchStart(event: TouchEvent) { + this.dt.onColumnResizeBegin(event); + this.bindDocumentEvents(); } + onTouchMove(event: TouchEvent) { + this.dt.onColumnResize(event); + } onDocumentMouseMove(event: MouseEvent) { this.dt.onColumnResize(event); } @@ -3960,6 +4002,11 @@ export class ResizableColumn implements AfterViewInit, OnDestroy { this.unbindDocumentEvents(); } + onTouchEnd(event: TouchEvent) { + this.dt.onColumnResizeEnd(); + this.unbindDocumentEvents(); + } + isEnabled() { return this.pResizableColumnDisabled !== true; } @@ -4943,10 +4990,7 @@ export class ReorderableRow implements AfterViewInit { this.unbindEvents(); } } -/** - * Column Filter element of Table. - * @group Components - */ + @Component({ selector: 'p-columnFilter', template: ` @@ -5199,7 +5243,7 @@ export class ColumnFilter implements AfterContentInit { * Enables currency input. * @group Props */ - @Input() currency: string | undefined; + @Input({ transform: booleanAttribute }) currency: boolean | undefined; /** * Defines the display of the currency input. * @group Props diff --git a/src/app/components/tree/tree.ts b/src/app/components/tree/tree.ts index 8a69c548c94..c5affadc7d4 100755 --- a/src/app/components/tree/tree.ts +++ b/src/app/components/tree/tree.ts @@ -737,64 +737,65 @@ export class UITreeNode implements OnInit {
- +
- - - -
    - -
-
- - - + + + +
    + +
+ + + + + +
+ +
+
    + +
+
-
- -
-
    - -
-
diff --git a/src/app/components/treeselect/treeselect.ts b/src/app/components/treeselect/treeselect.ts index 8fbf0cee626..f2527508518 100755 --- a/src/app/components/treeselect/treeselect.ts +++ b/src/app/components/treeselect/treeselect.ts @@ -26,7 +26,7 @@ import { SearchIcon } from 'primeng/icons/search'; import { TimesIcon } from 'primeng/icons/times'; import { Overlay, OverlayModule } from 'primeng/overlay'; import { RippleModule } from 'primeng/ripple'; -import { Tree, TreeModule, TreeNodeSelectEvent, TreeNodeUnSelectEvent } from 'primeng/tree'; +import { Tree, TreeFilterEvent, TreeModule, TreeNodeSelectEvent, TreeNodeUnSelectEvent } from 'primeng/tree'; import { ObjectUtils, UniqueComponentId } from 'primeng/utils'; import { Nullable } from 'primeng/ts-helpers'; import { AutoFocusModule } from 'primeng/autofocus'; @@ -126,7 +126,7 @@ export const TREESELECT_VALUE_ACCESSOR: any = {
= new EventEmitter(); + @Output() onFilter: EventEmitter = new EventEmitter(); /** * Callback to invoke when a node is unselected. * @param {TreeNodeUnSelectEvent} event - node unselect event. @@ -699,7 +699,7 @@ export class TreeSelect implements AfterContentInit { this.filterValue = (event.target as HTMLInputElement).value; this.treeViewChild?._filter(this.filterValue); this.onFilter.emit({ - originalEvent: event, + filter: this.filterValue, filteredValue: this.treeViewChild?.filteredNodes }); setTimeout(() => { @@ -937,8 +937,8 @@ export class TreeSelect implements AfterContentInit { setDisabledState(val: boolean): void { setTimeout(() => { this.disabled = val; + this.cd.markForCheck(); }); - this.cd.markForCheck(); } containerClass() { diff --git a/src/app/showcase/data/news.json b/src/app/showcase/data/news.json index 11e037f46b1..3042354cc33 100644 --- a/src/app/showcase/data/news.json +++ b/src/app/showcase/data/news.json @@ -1,6 +1,6 @@ { - "id": 63, - "content": "Introducing the new Aura theme", + "id": 64, + "content": "🌸 Spring Sale: Save Up to 50% on Premium Templates and More.", "linkText": "Learn More", - "linkHref": "https://primeng.org/theming" -} + "linkHref": "https://primefaces.org/store" +} \ No newline at end of file diff --git a/src/app/showcase/data/versions.json b/src/app/showcase/data/versions.json index a643e0881f0..02f1ff0aab2 100644 --- a/src/app/showcase/data/versions.json +++ b/src/app/showcase/data/versions.json @@ -1,6 +1,6 @@ [ { - "version": "v17.14.1", + "version": "v17.15.0", "name": "v17", "url": "https://primeng.org" }, diff --git a/src/app/showcase/doc/apidoc/index.json b/src/app/showcase/doc/apidoc/index.json index 755a5317b33..f1506b4ddb3 100644 --- a/src/app/showcase/doc/apidoc/index.json +++ b/src/app/showcase/doc/apidoc/index.json @@ -4470,6 +4470,14 @@ "type": "\"large\" | \"xlarge\"", "description": "Size of the badge, valid options are \"large\" and \"xlarge\"." }, + { + "name": "size", + "optional": false, + "readonly": false, + "type": "\"large\" | \"xlarge\"", + "description": "Size of the badge, valid options are \"large\" and \"xlarge\".", + "deprecated": "use badgeSize instead." + }, { "name": "severity", "optional": false, @@ -4534,6 +4542,14 @@ "type": "boolean", "default": "false", "description": "When specified, disables the component." + }, + { + "name": "size", + "optional": false, + "readonly": false, + "type": "\"large\" | \"xlarge\"", + "description": "Size of the badge, valid options are \"large\" and \"xlarge\".", + "deprecated": "use badgeSize instead." } ] } @@ -6005,7 +6021,7 @@ "name": "style", "optional": false, "readonly": false, - "type": "Object", + "type": null, "description": "Inline style of the element." }, { @@ -10297,7 +10313,7 @@ "description": "item data." } ], - "description": "Custom header template." + "description": "Custom item template." }, { "parent": "dropdown", @@ -16530,7 +16546,30 @@ "parent": "multiselect", "name": "checkicon", "parameters": [], - "description": "Custom check icon template." + "description": "Custom check icon template.", + "deprecated": "Use headercheckboxicon or itemcheckboxicon instead." + }, + { + "parent": "multiselect", + "name": "headercheckboxicon", + "parameters": [ + { + "name": "context", + "type": "{\n \t $implicit: boolean, // Defines if all items are selected.\n \t partialSelected: boolean, // Defines if items are partially selected.\n }" + } + ], + "description": "Custom check icon template for the header checkbox." + }, + { + "parent": "multiselect", + "name": "itemcheckboxicon", + "parameters": [ + { + "name": "context", + "type": "{\n \t $implicit: boolean, // Selection status of the item.\n }" + } + ], + "description": "Custom check icon template for the item checkbox." }, { "parent": "multiselect", @@ -22045,21 +22084,6 @@ }, "stepper": { "components": { - "StepperPanel": { - "description": "StepperPanel is a helper component for Stepper component.", - "props": { - "description": "Defines the input properties of the component.", - "values": [ - { - "name": "header", - "optional": false, - "readonly": false, - "type": "string", - "description": "Orientation of tab headers." - } - ] - } - }, "Stepper": { "description": "The Stepper component displays a wizard-like workflow by guiding users through the multi-step progression.", "props": { @@ -22157,7 +22181,23 @@ }, "stepperpanel": { "interfaces": { - "components": {}, + "components": { + "StepperPanelProps": { + "description": "StepperPanel is a helper component for Stepper component.", + "props": { + "description": "Defines the input properties of the component.", + "values": [ + { + "name": "header", + "optional": false, + "readonly": false, + "type": "string", + "description": "Orientation of tab headers." + } + ] + } + } + }, "templates": { "description": "Defines the templates used by the component.", "values": [ @@ -22167,7 +22207,7 @@ "parameters": [ { "name": "context", - "type": "StepperPanelHeaderProps" + "type": "StepperPanelHeaderTemplate" } ], "description": "Custom header template." @@ -22178,7 +22218,7 @@ "parameters": [ { "name": "context", - "type": "StepperPanelContentProps" + "type": "StepperPanelContentTemplate" } ], "description": "Custom header template." @@ -22200,7 +22240,7 @@ "description": "Defines the custom interfaces used by the module.", "values": [ { - "name": "StepperPanelHeaderProps", + "name": "StepperPanelHeaderTemplate", "description": "Props of stepper panel header.", "props": [ { @@ -22261,7 +22301,7 @@ ] }, { - "name": "StepperPanelContentProps", + "name": "StepperPanelContentTemplate", "description": "Props of stepper panel content.", "props": [ { @@ -22538,14 +22578,220 @@ }, "columnfilter": { "interfaces": { - "components": {}, + "components": { + "ColumnFilterProps": { + "description": "Defines valid properties in ColumnFilter component.", + "props": { + "description": "Defines the input properties of the component.", + "values": [ + { + "name": "field", + "optional": false, + "readonly": false, + "type": "string", + "description": "Property represented by the column." + }, + { + "name": "type", + "optional": false, + "readonly": false, + "type": "string", + "description": "Type of the input." + }, + { + "name": "display", + "optional": false, + "readonly": false, + "type": "string", + "description": "Filter display." + }, + { + "name": "showMenu", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "Decides whether to display filter menu popup." + }, + { + "name": "matchMode", + "optional": false, + "readonly": false, + "type": "string", + "description": "Filter match mode." + }, + { + "name": "operator", + "optional": false, + "readonly": false, + "type": "string", + "description": "Filter operator." + }, + { + "name": "showOperator", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "Decides whether to display filter operator." + }, + { + "name": "showClearButton", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "Decides whether to display clear filter button." + }, + { + "name": "showApplyButton", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "Decides whether to display apply filter button." + }, + { + "name": "showMatchModes", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "Decides whether to display filter match modes." + }, + { + "name": "showAddButton", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "Decides whether to display add filter button." + }, + { + "name": "hideOnClear", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "Decides whether to close popup on clear button click." + }, + { + "name": "placeholder", + "optional": false, + "readonly": false, + "type": "string", + "description": "Filter placeholder." + }, + { + "name": "matchModeOptions", + "optional": false, + "readonly": false, + "type": "SelectItem[]", + "description": "Filter match mode options." + }, + { + "name": "maxConstraints", + "optional": false, + "readonly": false, + "type": "number", + "description": "Defines maximum amount of constraints." + }, + { + "name": "minFractionDigits", + "optional": false, + "readonly": false, + "type": "number", + "description": "Defines minimum fraction of digits." + }, + { + "name": "maxFractionDigits", + "optional": false, + "readonly": false, + "type": "number", + "description": "Defines maximum fraction of digits." + }, + { + "name": "prefix", + "optional": false, + "readonly": false, + "type": "string", + "description": "Defines prefix of the filter." + }, + { + "name": "suffix", + "optional": false, + "readonly": false, + "type": "string", + "description": "Defines suffix of the filter." + }, + { + "name": "locale", + "optional": false, + "readonly": false, + "type": "string", + "description": "Defines filter locale." + }, + { + "name": "localeMatcher", + "optional": false, + "readonly": false, + "type": "string", + "description": "Defines filter locale matcher." + }, + { + "name": "currency", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "Enables currency input." + }, + { + "name": "currencyDisplay", + "optional": false, + "readonly": false, + "type": "string", + "description": "Defines the display of the currency input." + }, + { + "name": "useGrouping", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "Defines if filter grouping will be enabled." + }, + { + "name": "showButtons", + "optional": false, + "readonly": false, + "type": "boolean", + "default": "false", + "description": "Defines the visibility of buttons." + }, + { + "name": "ariaLabel", + "optional": false, + "readonly": false, + "type": "string", + "description": "Defines the aria-label of the form element." + } + ] + } + } + }, "templates": { "description": "Defines the templates used by the component.", "values": [ { "parent": "columnfilter", "name": "filterTemplate", - "parameters": [], + "parameters": [ + { + "name": "context", + "type": "{\n \t $implicit: string, // filterConstraint.value.\n \t filterCallback: undefined, // undefined\n \t type: string, // Type of the input.\n \t filterConstraint: string, // Filter constraint.\n \t placeholder: boolean, // Input placeholder.\n \t minFractionDigits: number, // Minimum fraction of digits.\n \t maxFractionDigits: number, // Maximum fraction of digits.\n \t prefix: string, // Input prefix.\n \t suffix: string, // Input suffix.\n \t locale: string, // Locale.\n \t localeMatcher: string, // Locale matcher.\n \t currency: boolean, // Enables currency input.\n \t currencyDisplay: boolean, // Display of the currency input.\n \t useGrouping: boolean, // Defines if filter grouping will be enabled.\n \t showButtons: boolean, // Defines the visibility of buttons.\n }" + } + ], "description": "Custom filter template." }, { @@ -23150,7 +23396,7 @@ "optional": false, "readonly": false, "type": "string", - "default": "640px", + "default": "960px", "description": "The breakpoint to define the maximum width boundary when using stack responsive layout." }, { @@ -23527,209 +23773,6 @@ } ] } - }, - "ColumnFilter": { - "description": "Column Filter element of Table.", - "props": { - "description": "Defines the input properties of the component.", - "values": [ - { - "name": "field", - "optional": false, - "readonly": false, - "type": "string", - "description": "Property represented by the column." - }, - { - "name": "type", - "optional": false, - "readonly": false, - "type": "string", - "default": "text", - "description": "Type of the input." - }, - { - "name": "display", - "optional": false, - "readonly": false, - "type": "string", - "default": "row", - "description": "Filter display." - }, - { - "name": "showMenu", - "optional": false, - "readonly": false, - "type": "boolean", - "default": "true", - "description": "Decides whether to display filter menu popup." - }, - { - "name": "matchMode", - "optional": false, - "readonly": false, - "type": "string", - "description": "Filter match mode." - }, - { - "name": "operator", - "optional": false, - "readonly": false, - "type": "string", - "default": "FilterOperator.AND", - "description": "Filter operator." - }, - { - "name": "showOperator", - "optional": false, - "readonly": false, - "type": "boolean", - "default": "true", - "description": "Decides whether to display filter operator." - }, - { - "name": "showClearButton", - "optional": false, - "readonly": false, - "type": "boolean", - "default": "true", - "description": "Decides whether to display clear filter button." - }, - { - "name": "showApplyButton", - "optional": false, - "readonly": false, - "type": "boolean", - "default": "true", - "description": "Decides whether to display apply filter button." - }, - { - "name": "showMatchModes", - "optional": false, - "readonly": false, - "type": "boolean", - "default": "true", - "description": "Decides whether to display filter match modes." - }, - { - "name": "showAddButton", - "optional": false, - "readonly": false, - "type": "boolean", - "default": "true", - "description": "Decides whether to display add filter button." - }, - { - "name": "hideOnClear", - "optional": false, - "readonly": false, - "type": "boolean", - "default": "false", - "description": "Decides whether to close popup on clear button click." - }, - { - "name": "placeholder", - "optional": false, - "readonly": false, - "type": "string", - "description": "Filter placeholder." - }, - { - "name": "matchModeOptions", - "optional": false, - "readonly": false, - "type": "SelectItem[]", - "description": "Filter match mode options." - }, - { - "name": "maxConstraints", - "optional": false, - "readonly": false, - "type": "number", - "default": "2", - "description": "Defines maximum amount of constraints." - }, - { - "name": "minFractionDigits", - "optional": false, - "readonly": false, - "type": "number", - "description": "Defines minimum fraction of digits." - }, - { - "name": "maxFractionDigits", - "optional": false, - "readonly": false, - "type": "number", - "description": "Defines maximum fraction of digits." - }, - { - "name": "prefix", - "optional": false, - "readonly": false, - "type": "string", - "description": "Defines prefix of the filter." - }, - { - "name": "suffix", - "optional": false, - "readonly": false, - "type": "string", - "description": "Defines suffix of the filter." - }, - { - "name": "locale", - "optional": false, - "readonly": false, - "type": "string", - "description": "Defines filter locale." - }, - { - "name": "localeMatcher", - "optional": false, - "readonly": false, - "type": "string", - "description": "Defines filter locale matcher." - }, - { - "name": "currency", - "optional": false, - "readonly": false, - "type": "string", - "description": "Enables currency input." - }, - { - "name": "currencyDisplay", - "optional": false, - "readonly": false, - "type": "string", - "description": "Defines the display of the currency input." - }, - { - "name": "useGrouping", - "optional": false, - "readonly": false, - "type": "boolean", - "default": "true", - "description": "Defines if filter grouping will be enabled." - }, - { - "name": "showButtons", - "optional": false, - "readonly": false, - "type": "boolean", - "default": "true", - "description": "Defines the visibility of buttons." - }, - { - "name": "ariaLabel", - "optional": false, - "readonly": false, - "type": "string", - "description": "Defines the aria-label of the form element." - } - ] - } } }, "interfaces": { diff --git a/src/app/showcase/doc/icons/listdoc.ts b/src/app/showcase/doc/icons/listdoc.ts index b7320fdd727..d3662298b22 100644 --- a/src/app/showcase/doc/icons/listdoc.ts +++ b/src/app/showcase/doc/icons/listdoc.ts @@ -1,5 +1,5 @@ -import { ChangeDetectorRef, Component } from '@angular/core'; -import { IconService } from '../../service/iconservice'; +import { Component } from '@angular/core'; +import { default as IconData } from 'src/assets/showcase/data/icons.json'; @Component({ selector: 'list-doc', @@ -21,31 +21,19 @@ import { IconService } from '../../service/iconservice'; ` }) export class ListDoc { - icons: any[]; + icons: any; filteredIcons: any[]; selectedIcon: any; - constructor(private iconService: IconService, private cd: ChangeDetectorRef) {} - ngOnInit() { - this.iconService.getIcons().subscribe((data) => { - data = data.filter((value) => { - return value.icon.tags.indexOf('deprecate') === -1; - }); - - let icons = data; - icons.sort((icon1, icon2) => { - if (icon1.properties.name < icon2.properties.name) return -1; - else if (icon1.properties.name < icon2.properties.name) return 1; - else return 0; - }); - - this.icons = icons; - this.filteredIcons = data; - this.cd.markForCheck(); + this.icons = IconData.icons.sort((icon1, icon2) => { + if (icon1.properties.name < icon2.properties.name) return -1; + else if (icon1.properties.name < icon2.properties.name) return 1; + else return 0; }); + this.filteredIcons = IconData.icons; } onFilter(event: KeyboardEvent): void { diff --git a/src/app/showcase/doc/keyfilter/regexdoc.ts b/src/app/showcase/doc/keyfilter/regexdoc.ts index 79d4ba028f5..138dd5d5a18 100644 --- a/src/app/showcase/doc/keyfilter/regexdoc.ts +++ b/src/app/showcase/doc/keyfilter/regexdoc.ts @@ -21,8 +21,7 @@ import { Code } from '../../domain/code'; ` }) export class RegexDoc { - blockSpace: RegExp = /[^\s]/; - + blockSpace: RegExp = /^[^\s]+$/; blockChars: RegExp = /^[^<>*!]+$/; code: Code = { @@ -49,8 +48,8 @@ import { Component } from '@angular/core'; templateUrl: './key-filter-reg-exp-demo.html' }) export class KeyFilterRegExpDemo { - blockSpace: RegExp = /[^\s]/; - + blockSpace: RegExp = /[^\s]/; + blockChars: RegExp = /^[^<>*!]+$/; }` }; diff --git a/src/app/showcase/doc/multiselect/virtualscrolldoc.ts b/src/app/showcase/doc/multiselect/virtualscrolldoc.ts index 56ef5821fbe..f624aafef33 100644 --- a/src/app/showcase/doc/multiselect/virtualscrolldoc.ts +++ b/src/app/showcase/doc/multiselect/virtualscrolldoc.ts @@ -1,5 +1,6 @@ -import { Component } from '@angular/core'; +import { Component, ViewChild } from '@angular/core'; import { Code } from '../../domain/code'; +import { MultiSelect } from 'primeng/multiselect'; @Component({ selector: 'virtual-scroll-doc', @@ -23,13 +24,20 @@ import { Code } from '../../domain/code'; class="multiselect-custom-virtual-scroll" placeholder="Select Cities" (onSelectAllChange)="onSelectAllChange($event)" - (onChange)="onChange($event)" - > + #ms + > + + + + +
` }) export class VirtualScrollDoc { + @ViewChild('ms') ms: MultiSelect; + items = Array.from({ length: 100000 }, (_, i) => ({ label: `Item #${i}`, value: i })); selectedItems!: any[]; @@ -37,15 +45,10 @@ export class VirtualScrollDoc { selectAll: boolean = false; onSelectAllChange(event) { - this.selectedItems = event.checked ? [...this.items] : []; + this.selectedItems = event.checked ? [...this.ms.visibleOptions()] : []; this.selectAll = event.checked; } - onChange(event) { - const { value } = event; - if (value) this.selectAll = value.length === this.items.length; - } - code: Code = { basic: ``, + #ms +> + + + + +`, html: `
@@ -76,34 +84,37 @@ export class VirtualScrollDoc { class="multiselect-custom-virtual-scroll" placeholder="Select Cities" (onSelectAllChange)="onSelectAllChange($event)" - (onChange)="onChange($event)" - > + #ms + > + + + + +
`, typescript: ` -import { Component } from '@angular/core'; +import { Component, ViewChild } from '@angular/core'; +import { MultiSelect } from 'primeng/multiselect'; @Component({ selector: 'multi-select-virtual-scroll-demo', templateUrl: './multi-select-virtual-scroll-demo.html' }) export class MultiSelectVirtualScrollDemo { + @ViewChild('ms') ms: MultiSelect; + items = Array.from({ length: 100000 }, (_, i) => ({ label: \`Item #\${i}\`, value: i })) selectedItems!: any[]; - selectAll = false; + selectAll: boolean = false; onSelectAllChange(event) { - this.selectedItems = event.checked ? [...this.items] : []; + this.selectedItems = event.checked ? [...this.ms.visibleOptions()] : []; this.selectAll = event.checked; } - onChange(event) { - const { originalEvent, value } = event - if(value) this.selectAll = value.length === this.items.length; - } - }` }; } diff --git a/src/app/showcase/layout/app.component.ts b/src/app/showcase/layout/app.component.ts index 0bd454b220c..e1a9b2b4d64 100644 --- a/src/app/showcase/layout/app.component.ts +++ b/src/app/showcase/layout/app.component.ts @@ -1,4 +1,4 @@ -import { DOCUMENT } from '@angular/common'; +import { DOCUMENT, IMAGE_CONFIG } from '@angular/common'; import { HttpClientModule } from '@angular/common/http'; import { Component, Inject, OnInit, PLATFORM_ID, Renderer2, afterNextRender } from '@angular/core'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; @@ -10,7 +10,6 @@ import { CarService } from '../service/carservice'; import { CountryService } from '../service/countryservice'; import { CustomerService } from '../service/customerservice'; import { EventService } from '../service/eventservice'; -import { IconService } from '../service/iconservice'; import { NodeService } from '../service/nodeservice'; import { PhotoService } from '../service/photoservice'; import { ProductService } from '../service/productservice'; @@ -25,7 +24,23 @@ import { AppTopBarComponent } from './topbar/app.topbar.component'; templateUrl: './app.component.html', standalone: true, imports: [RouterOutlet, FormsModule, ReactiveFormsModule, HttpClientModule, AppMainComponent, LandingComponent, AppNewsComponent, AppConfigComponent, AppTopBarComponent, AppMenuComponent], - providers: [CarService, CountryService, EventService, NodeService, IconService, CustomerService, PhotoService, AppConfigService, ProductService] + providers: [ + CarService, + CountryService, + EventService, + NodeService, + CustomerService, + PhotoService, + AppConfigService, + ProductService, + { + provide: IMAGE_CONFIG, + useValue: { + disableImageSizeWarning: true, + disableImageLazyLoadWarning: true + } + } + ] }) export class AppComponent implements OnInit { constructor(@Inject(DOCUMENT) private document: Document, private renderer: Renderer2, private primeng: PrimeNGConfig, private configService: AppConfigService, private router: Router, @Inject(PLATFORM_ID) private platformId: any) { diff --git a/src/app/showcase/layout/app.main.component.ts b/src/app/showcase/layout/app.main.component.ts index 36387dd142b..4d3ea671fb6 100644 --- a/src/app/showcase/layout/app.main.component.ts +++ b/src/app/showcase/layout/app.main.component.ts @@ -1,4 +1,4 @@ -import { CommonModule, DOCUMENT } from '@angular/common'; +import { CommonModule, DOCUMENT, IMAGE_CONFIG } from '@angular/common'; import { Component, Inject } from '@angular/core'; import { RouterOutlet } from '@angular/router'; import { DomHandler } from 'primeng/dom'; diff --git a/src/app/showcase/layout/doc/app.docapisection.component.ts b/src/app/showcase/layout/doc/app.docapisection.component.ts index ed62f296589..d747452e951 100644 --- a/src/app/showcase/layout/doc/app.docapisection.component.ts +++ b/src/app/showcase/layout/doc/app.docapisection.component.ts @@ -3,6 +3,7 @@ import { Location } from '@angular/common'; import { Router } from '@angular/router'; import APIDoc from 'src/app/showcase/doc/apidoc/index.json'; import { AppDocApiTable } from './app.docapitable.component'; +import { ObjectUtils } from 'primeng/utils'; @Component({ selector: 'app-docapisection', @@ -62,7 +63,14 @@ export class AppDocApiSection { }; if (module) { - let props = module.components && module.components[docName] ? module.components[docName].props : module.props ? module.props : undefined; + let props = + module.components && module.components[docName] + ? module.components[docName].props + : module.props + ? module.props + : module.interfaces && ObjectUtils.isNotEmpty(module.interfaces.components) + ? module.interfaces.components[`${docName}Props`].props + : undefined; let emits = module.components && module.components[docName] ? module.components[docName].emits : module.emits ? module.emits : undefined; let templates = module.interfaces ? module.interfaces.templates : undefined; let events = module.interfaces ? module.interfaces.events : undefined; diff --git a/src/app/showcase/layout/doc/codeeditor/templates.ts b/src/app/showcase/layout/doc/codeeditor/templates.ts index 048e2c304c7..bbcd55065a7 100644 --- a/src/app/showcase/layout/doc/codeeditor/templates.ts +++ b/src/app/showcase/layout/doc/codeeditor/templates.ts @@ -15,7 +15,7 @@ export interface Props { const app_dependencies = pkg ? pkg.devDependencies : {}; const PrimeNG = { - version: '17.14.1', + version: '17.15.0', description: 'PrimeNG is an open source UI library for Angular featuring a rich set of 80+ components, a theme designer, various theme alternatives such as Material, Bootstrap, Tailwind, premium templates and professional support. In addition, it integrates with PrimeBlock, which has 370+ ready to use UI blocks to build spectacular applications in no time.' }; @@ -529,6 +529,7 @@ import { DynamicDialogModule } from 'primeng/dynamicdialog'; import { EditorModule } from 'primeng/editor'; import { FieldsetModule } from 'primeng/fieldset'; import { FileUploadModule } from 'primeng/fileupload'; +import { FloatLabelModule } from 'primeng/floatlabel'; import { GalleriaModule } from 'primeng/galleria'; import { InplaceModule } from 'primeng/inplace'; import { InputMaskModule } from 'primeng/inputmask'; @@ -539,6 +540,8 @@ import { InputTextareaModule } from 'primeng/inputtextarea'; import { InputGroupAddonModule } from 'primeng/inputgroupaddon'; import { InputGroupModule } from 'primeng/inputgroup' import { InputOtpModule } from 'primeng/inputotp' +import { IconFieldModule } from 'primeng/iconfield'; +import { InputIconModule } from 'primeng/inputicon'; import { ImageModule } from 'primeng/image'; import { KnobModule } from 'primeng/knob'; import { ListboxModule } from 'primeng/listbox'; @@ -596,6 +599,7 @@ import { ProgressSpinnerModule } from 'primeng/progressspinner'; import { RippleModule } from 'primeng/ripple'; import { StyleClassModule } from 'primeng/styleclass'; import { MessageService } from 'primeng/api'; + ${serviceImports} @NgModule({ @@ -635,6 +639,7 @@ ${serviceImports} EditorModule, FieldsetModule, FileUploadModule, + FloatLabelModule, GalleriaModule, InplaceModule, InputMaskModule, @@ -645,6 +650,8 @@ ${serviceImports} InputGroupModule, InputGroupAddonModule, InputOtpModule, + IconFieldModule, + InputIconModule, ImageModule, KnobModule, ListboxModule, diff --git a/src/app/showcase/layout/templates/templatefeaturesanimation/templatefeaturesanimation.ts b/src/app/showcase/layout/templates/templatefeaturesanimation/templatefeaturesanimation.ts index 2d70cdb19f2..5c42920b35e 100644 --- a/src/app/showcase/layout/templates/templatefeaturesanimation/templatefeaturesanimation.ts +++ b/src/app/showcase/layout/templates/templatefeaturesanimation/templatefeaturesanimation.ts @@ -46,7 +46,7 @@ import { TemplateFeaturesAnimationInlineModule } from './templatefeaturesanimati > - Animation Feature Image + Animation Feature Image
diff --git a/src/app/showcase/layout/templates/templatehero/templatehero.ts b/src/app/showcase/layout/templates/templatehero/templatehero.ts index df03d4c12ee..8d76031bdec 100755 --- a/src/app/showcase/layout/templates/templatehero/templatehero.ts +++ b/src/app/showcase/layout/templates/templatehero/templatehero.ts @@ -9,7 +9,7 @@ import { TemplateHeroRectangleModule } from './templateherorectangle'; template: `
- Template Hero Pattern + Template Hero Pattern @@ -38,10 +38,10 @@ import { TemplateHeroRectangleModule } from './templateherorectangle';
- Template Dashboard Image 1 + Template Dashboard Image 1 - Template Dashboard Image 2 + Template Dashboard Image 2
`, diff --git a/src/app/showcase/layout/templates/templatelicense.ts b/src/app/showcase/layout/templates/templatelicense.ts index 4743c38c71f..552c7c3636d 100644 --- a/src/app/showcase/layout/templates/templatelicense.ts +++ b/src/app/showcase/layout/templates/templatelicense.ts @@ -11,7 +11,10 @@ import { SharedModule } from 'primeng/api';
{{ licenseData?.title }} -

{{ licenseData?.price }}

+
+

{{ licenseData?.price }}

+

{{ licenseData?.discount_price }}

+

{{ txt }}

diff --git a/src/app/showcase/pages/lts/lts.component.html b/src/app/showcase/pages/lts/lts.component.html index 36b6ad88de4..f5469245f38 100755 --- a/src/app/showcase/pages/lts/lts.component.html +++ b/src/app/showcase/pages/lts/lts.component.html @@ -134,7 +134,8 @@
- $249 + $249 + $149

@@ -174,7 +175,8 @@
- $999 + $990 + $490

diff --git a/src/app/showcase/pages/support/support.component.html b/src/app/showcase/pages/support/support.component.html index 8934855d4d6..12b21acd71f 100755 --- a/src/app/showcase/pages/support/support.component.html +++ b/src/app/showcase/pages/support/support.component.html @@ -72,10 +72,6 @@ PrimeBlocks - Enterprise License -
  • - - Theme Designer - Extended License -
  • Figma UI Kit - Enterprise License @@ -84,12 +80,12 @@ 1 Premium Template - Extended License
  • - -
    • Maintenance for Any Version
    • +
    +
    • Basic LTS License diff --git a/src/app/showcase/pages/table/tabledemo.html b/src/app/showcase/pages/table/tabledemo.html index fd8e23c96da..84bbe9ecec1 100755 --- a/src/app/showcase/pages/table/tabledemo.html +++ b/src/app/showcase/pages/table/tabledemo.html @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/src/app/showcase/pages/templates/apollo/apollo.ts b/src/app/showcase/pages/templates/apollo/apollo.ts index eb2013e36c1..3be9a5325a4 100644 --- a/src/app/showcase/pages/templates/apollo/apollo.ts +++ b/src/app/showcase/pages/templates/apollo/apollo.ts @@ -260,11 +260,13 @@ export class ApolloPage { { title: 'Basic License', price: '$59', + discount_price: '$39', included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', 'Lifetime Support', 'Unlimited Updates'] }, { title: 'Extended License', price: '$590', + discount_price: '$390', included: ['Commercial Usage', 'Multiple End Products', 'Lifetime Support', 'Unlimited Updates'] } ] diff --git a/src/app/showcase/pages/templates/atlantis/atlantis.ts b/src/app/showcase/pages/templates/atlantis/atlantis.ts index 71159a9d188..e1d28743cd2 100644 --- a/src/app/showcase/pages/templates/atlantis/atlantis.ts +++ b/src/app/showcase/pages/templates/atlantis/atlantis.ts @@ -201,11 +201,13 @@ export class AtlantisPage { { title: 'Basic License', price: '$59', + discount_price: '$39', included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', 'Lifetime Support', 'Unlimited Updates'] }, { title: 'Extended License', price: '$590', + discount_price: '$390', included: ['Commercial Usage', 'Multiple End Products', 'Lifetime Support', 'Unlimited Updates'] } ] diff --git a/src/app/showcase/pages/templates/avalon/avalon.ts b/src/app/showcase/pages/templates/avalon/avalon.ts index 79691d4aa05..e3ba3205709 100644 --- a/src/app/showcase/pages/templates/avalon/avalon.ts +++ b/src/app/showcase/pages/templates/avalon/avalon.ts @@ -226,11 +226,13 @@ export class AvalonPage { { title: 'Basic License', price: '$49', + discount_price: '$29', included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', 'Lifetime Support', 'Unlimited Updates'] }, { title: 'Extended License', price: '$490', + discount_price: '$290', included: ['Commercial Usage', 'Multiple End Products', 'Lifetime Support', 'Unlimited Updates'] } ] diff --git a/src/app/showcase/pages/templates/diamond/diamond.ts b/src/app/showcase/pages/templates/diamond/diamond.ts index 8133dee110b..5b880372c64 100644 --- a/src/app/showcase/pages/templates/diamond/diamond.ts +++ b/src/app/showcase/pages/templates/diamond/diamond.ts @@ -225,11 +225,13 @@ export class DiamondPage { { title: 'Basic License', price: '$59', + discount_price: '$39', included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', 'Lifetime Support', 'Unlimited Updates'] }, { title: 'Extended License', price: '$590', + discount_price: '$390', included: ['Commercial Usage', 'Multiple End Products', 'Lifetime Support', 'Unlimited Updates'] } ] diff --git a/src/app/showcase/pages/templates/freya/freya.ts b/src/app/showcase/pages/templates/freya/freya.ts index 4e15206bc0f..028c78f92c7 100644 --- a/src/app/showcase/pages/templates/freya/freya.ts +++ b/src/app/showcase/pages/templates/freya/freya.ts @@ -218,11 +218,13 @@ export class FreyaPage { { title: 'Basic License', price: '$59', + discount_price: '$39', included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', 'Lifetime Support', 'Unlimited Updates'] }, { title: 'Extended License', price: '$590', + discount_price: '$390', included: ['Commercial Usage', 'Multiple End Products', 'Lifetime Support', 'Unlimited Updates'] } ] diff --git a/src/app/showcase/pages/templates/learnmore/learnmore.scss b/src/app/showcase/pages/templates/learnmore/learnmore.scss index 092863eee92..6b2df3fddcd 100644 --- a/src/app/showcase/pages/templates/learnmore/learnmore.scss +++ b/src/app/showcase/pages/templates/learnmore/learnmore.scss @@ -20,6 +20,7 @@ font-size: 3rem; font-weight: 600; color: var(--surface-900); + @media (max-width: 900px) { font-size: 1.5rem; } @@ -50,6 +51,7 @@ color: var(--surface-900); width: 45rem; margin: 1.25rem auto 0; + @media (max-width: 900px) { font-size: 0.875rem; line-height: 1.25rem; @@ -409,6 +411,7 @@ background: var(--surface-0, #fff); padding: 1.25rem; display: flex; + img { width: 18.625rem; height: auto; @@ -793,6 +796,7 @@ background-color: var(--surface-100); display: flex; overflow: hidden; + img { width: 100%; height: auto; @@ -894,6 +898,7 @@ &-right { flex: 0.6; + &-inline { &-image { width: 92%; @@ -1354,6 +1359,13 @@ background: var(--surface-card, #fff); } + &-price { + .discount { + color: var(--text-color-secondary); + text-decoration: line-through; + } + } + &-cards { display: flex; flex-wrap: wrap; @@ -1368,6 +1380,7 @@ border-radius: 1rem; border: 1px solid var(--surface-200); background-color: var(--surface-card); + span { color: var(--surface-900); font-weight: 600; @@ -1463,18 +1476,21 @@ padding: 2.5rem 1.25rem; border-radius: 1.25rem; } + &-description { max-width: 36.5rem; } } } } + @media only screen and (max-width: 721px) { .template { &-license { &-card { width: 80%; } + &-description { max-width: 32rem; } @@ -1540,6 +1556,7 @@ left: -7rem; z-index: 6; } + &-dashboard1, &-dashboard2 { border-radius: 1.12rem; @@ -1587,13 +1604,16 @@ left: -3.06; z-index: 6; } + &-rectangle { opacity: 0.5; } + &-light { opacity: 0.75; } } + &-separator { &-icon { width: 7rem; @@ -1603,6 +1623,7 @@ } } } + @media only screen and (max-width: 1200px) { .avalon { .template { @@ -1617,6 +1638,7 @@ } } } + @media only screen and (max-width: 768px) { .avalon { .template { @@ -1643,6 +1665,7 @@ left: -15rem; z-index: 6; } + &-dashboard1, &-dashboard2 { width: 40rem; @@ -1650,6 +1673,7 @@ } } } + @media only screen and (max-width: 1200px) { .babylon { .template { @@ -1664,6 +1688,7 @@ } } } + @media only screen and (max-width: 768px) { .babylon { .template { @@ -1690,6 +1715,7 @@ left: -8.65rem; z-index: 6; } + &-dashboard1, &-dashboard2 { width: 40rem; @@ -1697,6 +1723,7 @@ } } } + @media only screen and (max-width: 1200px) { .california { .template { @@ -1711,6 +1738,7 @@ } } } + @media only screen and (max-width: 768px) { .california { .template { @@ -1740,6 +1768,7 @@ } } } + @media only screen and (max-width: 1200px) { .diamond { .template { @@ -1754,6 +1783,7 @@ } } } + @media only screen and (max-width: 768px) { .diamond { .template { @@ -1810,6 +1840,7 @@ left: -26rem; z-index: 6; } + &-dashboard1, &-dashboard2 { width: 45rem; @@ -1817,6 +1848,7 @@ } } } + @media only screen and (max-width: 1200px) { .poseidon { .template { @@ -1830,6 +1862,7 @@ } } } + @media only screen and (max-width: 768px) { .poseidon { .template { @@ -1855,16 +1888,19 @@ left: -4.06rem; z-index: 6; } + &-dashboard1, &-dashboard2 { width: 42rem; } } + &-separator { &-icon { width: 6rem; height: 2.5rem; border-radius: 99px; + svg { width: 4.2rem; height: 4.2rem; @@ -1873,6 +1909,7 @@ } } } + @media only screen and (max-width: 1200px) { .roma { .template { @@ -1887,6 +1924,7 @@ } } } + @media only screen and (max-width: 768px) { .roma { .template { @@ -1913,11 +1951,13 @@ left: -1rem; z-index: 6; } + &-dashboard1, &-dashboard2 { width: 42rem; } } + &-features-horizontal-card { width: 30rem; } @@ -2030,4 +2070,4 @@ } } } -} +} \ No newline at end of file diff --git a/src/app/showcase/pages/templates/poseidon/poseidon.ts b/src/app/showcase/pages/templates/poseidon/poseidon.ts index 5bb817891fd..ae2d445d6db 100644 --- a/src/app/showcase/pages/templates/poseidon/poseidon.ts +++ b/src/app/showcase/pages/templates/poseidon/poseidon.ts @@ -175,11 +175,13 @@ export class PoseidonPage { { title: 'Basic License', price: '$59', + discount_price: '$39', included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', 'Lifetime Support', 'Unlimited Updates'] }, { title: 'Extended License', price: '$590', + discount_price: '$390', included: ['Commercial Usage', 'Multiple End Products', 'Lifetime Support', 'Unlimited Updates'] } ] diff --git a/src/app/showcase/pages/templates/ultima/ultima.ts b/src/app/showcase/pages/templates/ultima/ultima.ts index cbf85320dcf..444c7d6f7be 100644 --- a/src/app/showcase/pages/templates/ultima/ultima.ts +++ b/src/app/showcase/pages/templates/ultima/ultima.ts @@ -220,11 +220,13 @@ export class UltimaPage { { title: 'Basic License', price: '$59', + discount_price: '$39', included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', 'Lifetime Support', 'Unlimited Updates'] }, { title: 'Extended License', price: '$590', + discount_price: '$390', included: ['Commercial Usage', 'Multiple End Products', 'Lifetime Support', 'Unlimited Updates'] } ] diff --git a/src/app/showcase/pages/templates/verona/verona.ts b/src/app/showcase/pages/templates/verona/verona.ts index 506212a9859..e442491635d 100644 --- a/src/app/showcase/pages/templates/verona/verona.ts +++ b/src/app/showcase/pages/templates/verona/verona.ts @@ -210,11 +210,13 @@ export class VeronaPage { { title: 'Basic License', price: '$49', + discount_price: '$29', included: ['Non Commercial Usage', 'Single End Product, No Multi-Use', 'Lifetime Support', 'Unlimited Updates'] }, { title: 'Extended License', price: '$490', + discount_price: '$290', included: ['Commercial Usage', 'Multiple End Products', 'Lifetime Support', 'Unlimited Updates'] } ] diff --git a/src/app/showcase/pages/uikit/uikit.component.html b/src/app/showcase/pages/uikit/uikit.component.html index 26045d48fb5..85d423d9095 100755 --- a/src/app/showcase/pages/uikit/uikit.component.html +++ b/src/app/showcase/pages/uikit/uikit.component.html @@ -150,7 +150,8 @@
      For individual designers

      - $99 + $99 + $49

        @@ -193,7 +194,8 @@
        - $249 + $249 + $149

        diff --git a/src/app/showcase/service/iconservice.ts b/src/app/showcase/service/iconservice.ts deleted file mode 100755 index 8ac282f12c5..00000000000 --- a/src/app/showcase/service/iconservice.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Injectable, Inject } from '@angular/core'; -import { HttpClient, HttpHeaders } from '@angular/common/http'; -import { map } from 'rxjs/operators'; -import { DOCUMENT } from '@angular/common'; - -@Injectable() -export class IconService { - constructor(private http: HttpClient, @Inject(DOCUMENT) private document: Document) {} - - icons: any[]; - - selectedIcon: any; - - apiUrl = 'assets/showcase/data/icons.json'; - - getBaseUrl() { - return `${this.document.location.protocol}//${this.document.location.host}/`; - } - - getIcons() { - const apiUrl = this.getBaseUrl() + this.apiUrl; - - return this.http.get(apiUrl).pipe( - map((response: any) => { - this.icons = response.icons; - return this.icons; - }) - ); - } -} diff --git a/src/assets/showcase/styles/layout/layout.css b/src/assets/showcase/styles/layout/layout.css index 71f7d853a1b..377521f0845 100644 --- a/src/assets/showcase/styles/layout/layout.css +++ b/src/assets/showcase/styles/layout/layout.css @@ -107,22 +107,26 @@ } .layout-light { + --primary-color-default:var(--primary-600); + --primary-color-inverse-default:var(--surface-0); --topbar-sticky-bg:rgba(255,255,255,.7); --card-border: 1px solid var(--surface-border); --card-bg: var(--surface-card); - --glow-image: url(https://www.primefaces.org/cdn/primeng/images/layout/pattern.png), radial-gradient(50% 50% at center top, var(--primary-100) 0%, #ffffff 100%); + --glow-image: url(https://www.primefaces.org/cdn/primeng/images/layout/pattern.png); --glow-blend: hard-light, multiply; --topbar-border: rgba(0,0,0,.05); --mobile-menu-bg: var(--surface-overlay); - --demo-code-bg: var(--surface-700); + --demo-code-bg: var(--surface-800); --demo-code-button-color: var(--surface-300); --demo-code-button-hover-bg: rgba(255,255,255,.1); --demo-code-button-hover-color: var(--surface-100); - --doc-highlight-text-bg: var(--primary-100); - --doc-highlight-text-color: var(--primary-900); + --doc-highlight-text-bg: var(--surface-200); + --doc-highlight-text-color: var(--surface-700); } .layout-dark { + --primary-color-default:var(--primary-400); + --primary-color-inverse-default:var(--gray-900); --topbar-sticky-bg:rgba(0,0,0,.3); --card-border: 0 none; --card-bg: var(--surface-card); @@ -134,8 +138,8 @@ --demo-code-button-color: var(--surface-500); --demo-code-button-hover-bg: rgba(255,255,255,.1); --demo-code-button-hover-color: var(--surface-700); - --doc-highlight-text-bg: var(--highlight-bg); - --doc-highlight-text-color: var(--highlight-text-color); + --doc-highlight-text-bg: var(--surface-50); + --doc-highlight-text-color: var(--surface-500); } html { @@ -350,6 +354,7 @@ button { color: var(--surface-900); font-weight: 600; transition: all 0.2s; + position: relative; border-radius: var(--border-radius); } .layout-sidebar .layout-menu > li > button .menu-icon, @@ -363,6 +368,8 @@ button { align-items: center; justify-content: center; transition: all 0.2s; + position: relative; + background-color: transparent; } .layout-sidebar .layout-menu > li > button .menu-icon i, .layout-sidebar .layout-menu > li > a .menu-icon i { @@ -374,9 +381,13 @@ button { color: var(--surface-700); margin-left: auto; } +.layout-sidebar .layout-menu > li > button:hover .menu-icon, +.layout-sidebar .layout-menu > li > a:hover .menu-icon { + background-color: var(--surface-card); +} .layout-sidebar .layout-menu > li > button:hover .menu-icon i, .layout-sidebar .layout-menu > li > a:hover .menu-icon i { - color: var(--primary-color); + color: var(--primary-color-default); } .layout-sidebar .layout-menu > li > button:hover .menu-toggle-icon, .layout-sidebar .layout-menu > li > a:hover .menu-toggle-icon { @@ -384,11 +395,11 @@ button { } .layout-sidebar .layout-menu > li > button.router-link-active, .layout-sidebar .layout-menu > li > a.router-link-active { - color: var(--primary-color); + color: var(--primary-color-default); } .layout-sidebar .layout-menu > li > button.router-link-active > .menu-icon i, .layout-sidebar .layout-menu > li > a.router-link-active > .menu-icon i { - color: var(--primary-color); + color: var(--primary-color-default); } .layout-sidebar .layout-menu > li > button:focus-visible, .layout-sidebar .layout-menu > li > a:focus-visible { @@ -407,9 +418,11 @@ button { transition: all 0.2s; font-weight: 450; display: flex; + align-items: center; padding: 0.5rem 0.5rem 0.5rem 1rem; color: var(--surface-700); transition: all 0.2s; + position: relative; } .layout-sidebar .layout-menu > li > div ol li a:focus-visible { outline: 0 none; @@ -420,8 +433,8 @@ button { border-left-color: var(--surface-500); } .layout-sidebar .layout-menu > li > div ol li a.router-link-active { - color: var(--primary-color); - border-left-color: var(--primary-color); + color: var(--primary-color-default); + border-left-color: var(--primary-color-default); } .layout-sidebar .layout-menu > li > div ol li ol { margin: 0; @@ -433,6 +446,15 @@ button { .layout-sidebar .layout-menu > li > div ol li:has(.menu-child-category):first-child { margin-top: 0rem; } +.layout-sidebar .layout-menu .p-tag { + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); +} +.layout-sidebar .layout-menu .p-tag .p-tag-value { + line-height: 1; +} .layout-sidebar .layout-menu .menu-child-category { display: flex; padding: 0.5rem 0.5rem 0.5rem 0; @@ -576,12 +598,12 @@ button { padding: 0.5rem 1rem; } .layout-config .p-selectbutton .p-button:first-child { - border-top-left-radius: 30px; - border-bottom-left-radius: 30px; + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; } .layout-config .p-selectbutton .p-button:last-child { - border-top-right-radius: 30px; - border-bottom-right-radius: 30px; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; } .layout-config button:focus-visible { outline: 0 none; @@ -1225,8 +1247,9 @@ pre[class*=language-] code { max-width: 1728px; margin: 0 auto; } + .layout-topbar-inner, - .layout-footer { +.layout-footer { max-width: 1728px; margin: 0 auto; } @@ -1256,9 +1279,10 @@ pre[class*=language-] code { height: 1rem; } .layout-topbar-inner .DocSearch-Button .DocSearch-Button-Placeholder, - .layout-topbar-inner .DocSearch-Button .DocSearch-Button-Keys { +.layout-topbar-inner .DocSearch-Button .DocSearch-Button-Keys { display: none; } + .layout-sidebar { top: 0; left: 0; @@ -1278,9 +1302,11 @@ pre[class*=language-] code { opacity: 1; transform: translateX(0); } + .layout-news-active .layout-sidebar { top: 0; } + .layout-mask { background-color: rgba(0, 0, 0, 0.1); } @@ -1294,9 +1320,11 @@ pre[class*=language-] code { background-color: rgba(0, 0, 0, 0.4); transition: background-color 0.5s; } + .doc-section-nav { display: none; } + .video-container { position: relative; width: 100%; @@ -1310,14 +1338,17 @@ pre[class*=language-] code { width: 100%; height: 100%; } + .layout-content { padding-left: 2rem; padding-right: 2rem; } + .layout-footer { padding-left: 2rem; padding-right: 2rem; } + .blocked-scroll { overflow: hidden; padding-right: var(--scrollbar-width); @@ -1339,14 +1370,17 @@ pre[class*=language-] code { .layout-topbar-inner .layout-topbar-icon { display: inline-flex; } + .layout-content { padding-left: 1rem; padding-right: 1rem; } + .layout-footer { padding-left: 1rem; padding-right: 1rem; } + .doc-tabmenu li { flex: 1 1 0; } @@ -1354,6 +1388,7 @@ pre[class*=language-] code { width: 100%; min-width: auto; } + .layout-news { padding-left: 1rem; padding-right: 1rem; diff --git a/src/assets/showcase/styles/layout/variables/main/_light.scss b/src/assets/showcase/styles/layout/variables/main/_light.scss index 73d1768bb07..d2e7ed39478 100644 --- a/src/assets/showcase/styles/layout/variables/main/_light.scss +++ b/src/assets/showcase/styles/layout/variables/main/_light.scss @@ -4,7 +4,7 @@ --topbar-sticky-bg:rgba(255,255,255,.7); --card-border: 1px solid var(--surface-border); --card-bg: var(--surface-card); - --glow-image: url(https://www.primefaces.org/cdn/primeng/images/layout/pattern.png), radial-gradient(50% 50% at center top, var(--primary-100) 0%, #ffffff 100%); + --glow-image: url(https://www.primefaces.org/cdn/primeng/images/layout/pattern.png); --glow-blend: hard-light, multiply; --topbar-border: rgba(0,0,0,.05); --mobile-menu-bg: var(--surface-overlay); diff --git a/vercel.json b/vercel.json deleted file mode 100644 index bc666d9d0ba..00000000000 --- a/vercel.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "version": 2, - "public": true, - "name": "primeng", - "rewrites": [ - { - "source": "/(.*)", - "destination": "/api" - } - ], - "functions": { - "api/index.js": { - "includeFiles": "./dist/primeng/browser/**" - } - } -} \ No newline at end of file