forked from valor-software/ngx-bootstrap
-
Notifications
You must be signed in to change notification settings - Fork 0
Merge upstream v20.0.2 into support-bs-3 (Angular 20 support) [ACE-7218] #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
64471ee
fix(discover): fix broken logos for companies on Discover page (#6745)
daniloff200 4cea047
feat(tabs): add tabOrder property for dynamic tab ordering
valorkin 0a37ec9
fix(e2e): improve reliability of Playwright tests (#6753)
valorkin 0220889
fix: package.json types reference (#6743)
joshvanallen bdac5d0
19.0.5
valorkin 17b4330
Angular 20 upgrade (#6757)
dezsiszabi 6908bb6
bump: Alex chore release 20.0.0 (#6759)
lexasq 0be2799
fix(ci): fixed nx cloud run (#6761)
lexasq 39d6967
chore(ci): use tsx instead of ts-node (#6762)
WikiRik e89ca9e
fix(tabset): fixed tabset active input (#6768)
lexasq f34b773
fix(typeahead): change highlight logic (#6764)
sudhirjadhav18 cff6af6
20.0.2
lexasq ca67d2a
Alex chore v20.0.2 (#6772)
lexasq 0357a3a
fix(datepicker): share PositioningService instance (#6775)
dd3e1c0
Merge branch 'development' of github.com:valor-software/ngx-bootstrap…
lexasq 3138ec4
Merge tag 'v20.0.2' into support-bs-3
davidIce File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,3 @@ | ||
| { | ||
| "version": "19.0.3" | ||
| "version": "20.0.2" | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,209 @@ | ||
| import { test, expect } from '@playwright/test'; | ||
|
|
||
| test.describe('Issue #823: Tab ordering with ngIf/dynamic directives', () => { | ||
| test.beforeEach(async ({ page }) => { | ||
| await page.goto('/'); | ||
| await page.click('text=Tabs'); | ||
| }); | ||
|
|
||
| test('should display tabs in correct order regardless of creation order', async ({ page }) => { | ||
| // Wait for tabs to load | ||
| await page.waitForSelector('.nav-tabs'); | ||
|
|
||
| // Check that tabs exist and are in some order | ||
| const tabs = page.locator('.nav-item'); | ||
| const tabCount = await tabs.count(); | ||
|
|
||
| if (tabCount > 0) { | ||
| // Tabs should be visible and clickable | ||
| expect(await tabs.first().isVisible()).toBe(true); | ||
|
|
||
| // Should be able to click on tabs | ||
| await tabs.first().click(); | ||
|
|
||
| // Active tab should have active class | ||
| const activeTab = page.locator('.nav-item.active, .nav-link.active'); | ||
| expect(await activeTab.count()).toBeGreaterThan(0); | ||
| } | ||
| }); | ||
|
|
||
| test('should maintain tab functionality with ordered tabs', async ({ page }) => { | ||
| // Test that tab ordering doesn't break basic functionality | ||
| await page.waitForSelector('.nav-tabs'); | ||
|
|
||
| const tabs = page.locator('.nav-link'); | ||
| const tabCount = await tabs.count(); | ||
|
|
||
| if (tabCount >= 2) { | ||
| // Click first tab | ||
| await tabs.first().click(); | ||
| expect(await tabs.first().getAttribute('class')).toContain('active'); | ||
|
|
||
| // Click second tab | ||
| await tabs.nth(1).click(); | ||
| expect(await tabs.nth(1).getAttribute('class')).toContain('active'); | ||
|
|
||
| // First tab should no longer be active | ||
| expect(await tabs.first().getAttribute('class')).not.toContain('active'); | ||
| } | ||
| }); | ||
|
|
||
| test('should handle dynamic tab addition and removal', async ({ page }) => { | ||
| // Test dynamic behavior that tabOrder should help with | ||
| await page.waitForSelector('.nav-tabs'); | ||
|
|
||
| const initialTabCount = await page.locator('.nav-item').count(); | ||
|
|
||
| // Look for any buttons that might add/remove tabs dynamically | ||
| const addButtons = page.locator('button:has-text("Add"), button:has-text("New Tab")'); | ||
| const removeButtons = page.locator('button:has-text("Remove"), .bs-remove-tab'); | ||
|
|
||
| // If there are dynamic controls, test them | ||
| if (await addButtons.count() > 0) { | ||
| await addButtons.first().click(); | ||
|
|
||
| // Tab count might change | ||
| const newTabCount = await page.locator('.nav-item').count(); | ||
| expect(newTabCount).toBeGreaterThanOrEqual(initialTabCount); | ||
| } | ||
|
|
||
| // Test removable tabs if they exist | ||
| if (await removeButtons.count() > 0) { | ||
| expect(await removeButtons.first().isVisible()).toBe(true); | ||
| } | ||
| }); | ||
|
|
||
| test('should preserve tab content when ordering changes', async ({ page }) => { | ||
| // Ensure tab content is preserved with ordering | ||
| await page.waitForSelector('.nav-tabs'); | ||
|
|
||
| const tabs = page.locator('.nav-link'); | ||
| const tabContent = page.locator('.tab-content, .tab-pane'); | ||
|
|
||
| if (await tabs.count() > 0 && await tabContent.count() > 0) { | ||
| // Click on different tabs and verify content shows | ||
| for (let i = 0; i < Math.min(await tabs.count(), 3); i++) { | ||
| await tabs.nth(i).click(); | ||
|
|
||
| // Content should be visible | ||
| expect(await tabContent.first().isVisible()).toBe(true); | ||
| } | ||
| } | ||
| }); | ||
|
|
||
| test('should handle conditional tabs with ngIf-like behavior', async ({ page }) => { | ||
| // Simulate the ngIf scenario from the issue | ||
| await page.waitForSelector('.nav-tabs'); | ||
|
|
||
| // Check if there are any conditional/dynamic elements | ||
| const conditionalElements = page.locator('[*ngIf], [ng-if], .conditional-tab'); | ||
|
|
||
| // Basic functionality should work even with conditional rendering | ||
| const tabs = page.locator('.nav-link'); | ||
| if (await tabs.count() > 0) { | ||
| // Should be able to navigate between tabs | ||
| await tabs.first().click(); | ||
|
|
||
| // Tab should become active | ||
| const activeClass = await tabs.first().getAttribute('class'); | ||
| expect(activeClass).toContain('active'); | ||
| } | ||
| }); | ||
|
|
||
| test('should maintain accessibility with ordered tabs', async ({ page }) => { | ||
| // Test that tab ordering doesn't break accessibility | ||
| await page.waitForSelector('.nav-tabs'); | ||
|
|
||
| const tabs = page.locator('.nav-link'); | ||
|
|
||
| if (await tabs.count() > 0) { | ||
| // Check for proper ARIA attributes | ||
| const firstTab = tabs.first(); | ||
|
|
||
| // Should have proper role | ||
| const role = await firstTab.getAttribute('role'); | ||
| expect(role).toBe('tab'); | ||
|
|
||
| // Should have aria-selected | ||
| const ariaSelected = await firstTab.getAttribute('aria-selected'); | ||
| expect(ariaSelected).toBeTruthy(); | ||
|
|
||
| // Should be focusable | ||
| await firstTab.focus(); | ||
| const focusedElement = page.locator(':focus'); | ||
| expect(await focusedElement.count()).toBe(1); | ||
| } | ||
| }); | ||
|
|
||
| test('should handle keyboard navigation with ordered tabs', async ({ page }) => { | ||
| // Test keyboard navigation works with tab ordering | ||
| await page.waitForSelector('.nav-tabs'); | ||
|
|
||
| const tabs = page.locator('.nav-link'); | ||
|
|
||
| if (await tabs.count() >= 2) { | ||
| // Focus first tab | ||
| await tabs.first().focus(); | ||
|
|
||
| // Use arrow keys to navigate | ||
| await page.keyboard.press('ArrowRight'); | ||
|
|
||
| // Should move focus (implementation may vary) | ||
| const focusedElement = page.locator(':focus'); | ||
| expect(await focusedElement.count()).toBe(1); | ||
|
|
||
| // Test Tab key navigation | ||
| await page.keyboard.press('Tab'); | ||
|
|
||
| // Focus should move to next element | ||
| expect(await focusedElement.count()).toBe(1); | ||
| } | ||
| }); | ||
|
|
||
| test('should handle edge cases for tab ordering', async ({ page }) => { | ||
| // Test edge cases that might occur with tab ordering | ||
| await page.waitForSelector('.nav-tabs'); | ||
|
|
||
| const tabs = page.locator('.nav-item'); | ||
| const initialCount = await tabs.count(); | ||
|
|
||
| // Rapid clicking shouldn't break ordering | ||
| if (initialCount >= 2) { | ||
| await tabs.first().click(); | ||
| await tabs.nth(1).click(); | ||
| await tabs.first().click(); | ||
|
|
||
| // Should still work correctly | ||
| expect(await tabs.count()).toBe(initialCount); | ||
| } | ||
|
|
||
| // Page refresh should maintain consistent ordering | ||
| await page.reload(); | ||
| await page.waitForSelector('.nav-tabs'); | ||
|
|
||
| const tabsAfterReload = page.locator('.nav-item'); | ||
| expect(await tabsAfterReload.count()).toBe(initialCount); | ||
| }); | ||
|
|
||
| test('should support tab ordering in different layouts', async ({ page }) => { | ||
| // Test that tab ordering works in different tab layouts | ||
| await page.waitForSelector('.nav-tabs'); | ||
|
|
||
| // Look for different tab styles/layouts | ||
| const verticalTabs = page.locator('.nav-tabs.flex-column, .nav-pills.flex-column'); | ||
| const justifiedTabs = page.locator('.nav-justified'); | ||
| const pillTabs = page.locator('.nav-pills'); | ||
|
|
||
| // Test basic functionality regardless of layout | ||
| const anyTabs = page.locator('.nav-link'); | ||
|
|
||
| if (await anyTabs.count() > 0) { | ||
| // Should work in any layout | ||
| await anyTabs.first().click(); | ||
|
|
||
| // Should have active state | ||
| const activeTab = page.locator('.nav-link.active'); | ||
| expect(await activeTab.count()).toBe(1); | ||
| } | ||
| }); | ||
|
davidIce marked this conversation as resolved.
|
||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.