Delete Tabs and Experimental Tabs (#3356)
* Delete TabsV1 code * Remove Tabs package * Update yarn.lock * Change files * Remove e2e tests * Change files * Remove tabs test exports * Remove dead link to Tabs package * Add tablist to core library
This commit is contained in:
Родитель
5e85050d5b
Коммит
4eb131d61e
|
@ -1,24 +0,0 @@
|
||||||
export const HOMEPAGE_TABS_BUTTON = 'Homepage_Tabs_Button';
|
|
||||||
export const TABS_TESTPAGE = 'Tabs_TestPage';
|
|
||||||
|
|
||||||
/* E2E Testing Tabs 1. This Tabs group has THREE Tab Items, all listed below. */
|
|
||||||
export const TABS_TEST_COMPONENT = 'Tabs_Test_Component';
|
|
||||||
export const TABS_ACCESSIBILITY_LABEL = 'E2E testing Tabs accessibility label';
|
|
||||||
|
|
||||||
/* E2E Testing TabItem 1 (1 of 3) */
|
|
||||||
export const FIRST_TABS_ITEM = 'First_Tabs_Item';
|
|
||||||
export const FIRST_TABS_ITEM_ACCESSIBILITY_LABEL = 'E2E testing TabItem accessibility label';
|
|
||||||
export const FIRST_TABS_ITEM_CONTENT = 'Tabs #1 content'; // Content to be shown when TabItem is clicked
|
|
||||||
|
|
||||||
/* E2E Testing TabItem 2 (2 of 3) */
|
|
||||||
export const SECOND_TABS_ITEM = 'Second_Tabs_Item';
|
|
||||||
export const SECOND_TABS_ITEM_CONTENT = 'Tabs #2 content'; // Content to be shown when TabItem is clicked
|
|
||||||
|
|
||||||
/* E2E Testing TabItem 3 (3 of 3) This is used to test the case of not setting accessibilityLabel */
|
|
||||||
export const THIRD_TABS_ITEM = 'Third_Tabs_Item';
|
|
||||||
export const THIRD_TABS_ITEM_LABEL = 'Test TabItem2 - No Accessibility Label';
|
|
||||||
export const THIRD_TABS_ITEM_CONTENT = 'Tabs #3 content'; // Content to be shown when TabItem is clicked
|
|
||||||
|
|
||||||
/* E2E Testing Tabs 2 */
|
|
||||||
export const TABS_NO_A11Y_LABEL_COMPONENT = 'Tabs_No_A11y_label_Component';
|
|
||||||
export const TABS_TEST_COMPONENT_LABEL = 'Test Tabs2 - No Accessibility Label'; // A component on each specific test page
|
|
|
@ -1,73 +0,0 @@
|
||||||
import { BasePage, By } from '../../common/BasePage';
|
|
||||||
import {
|
|
||||||
TABS_TESTPAGE,
|
|
||||||
TABS_TEST_COMPONENT,
|
|
||||||
HOMEPAGE_TABS_BUTTON,
|
|
||||||
FIRST_TABS_ITEM,
|
|
||||||
SECOND_TABS_ITEM,
|
|
||||||
THIRD_TABS_ITEM,
|
|
||||||
FIRST_TABS_ITEM_CONTENT,
|
|
||||||
SECOND_TABS_ITEM_CONTENT,
|
|
||||||
THIRD_TABS_ITEM_CONTENT,
|
|
||||||
} from '../consts';
|
|
||||||
|
|
||||||
/* This enum gives the spec file an EASY way to interact with SPECIFIC UI elements on the page.
|
|
||||||
* The spec file should import this enum and use it when wanting to interact with different elements on the page.
|
|
||||||
* The main Tab group we are testing has THREE tab items. The spec file will
|
|
||||||
* import this enum to easily write tests using these 3 tab items */
|
|
||||||
type TabItem =
|
|
||||||
| 'First' // this._firstTabItem
|
|
||||||
| 'Second' // this._secondTabItem
|
|
||||||
| 'Third'; // this._thirdTabItem
|
|
||||||
|
|
||||||
class TabsLegacyPageObject extends BasePage {
|
|
||||||
/******************************************************************/
|
|
||||||
/**************** UI Element Interaction Methods ******************/
|
|
||||||
/******************************************************************/
|
|
||||||
|
|
||||||
async waitForTabItemContentToLoad(tabItemSelector: TabItem, errorMsg: string): Promise<boolean | void> {
|
|
||||||
const content = await this.getTabItemContent(tabItemSelector);
|
|
||||||
return await this.waitForCondition(async () => await content.isDisplayed(), errorMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the correct WebDriverIO element from the TabItem Selector */
|
|
||||||
async getTabItem(tabItemSelector: TabItem): Promise<WebdriverIO.Element> {
|
|
||||||
switch (tabItemSelector) {
|
|
||||||
case 'First':
|
|
||||||
return await By(FIRST_TABS_ITEM);
|
|
||||||
case 'Second':
|
|
||||||
return await By(SECOND_TABS_ITEM);
|
|
||||||
case 'Third':
|
|
||||||
return await By(THIRD_TABS_ITEM);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Returns the correct WebDriverIO element from the TabItem Selector */
|
|
||||||
async getTabItemContent(tabItemSelector: TabItem): Promise<WebdriverIO.Element> {
|
|
||||||
switch (tabItemSelector) {
|
|
||||||
case 'First':
|
|
||||||
return await By(FIRST_TABS_ITEM_CONTENT);
|
|
||||||
case 'Second':
|
|
||||||
return await By(SECOND_TABS_ITEM_CONTENT);
|
|
||||||
case 'Third':
|
|
||||||
return await By(THIRD_TABS_ITEM_CONTENT);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************/
|
|
||||||
/**************** Getters ****************/
|
|
||||||
/*****************************************/
|
|
||||||
get _pageName() {
|
|
||||||
return TABS_TESTPAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
get _primaryComponentName() {
|
|
||||||
return TABS_TEST_COMPONENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
get _pageButtonName() {
|
|
||||||
return HOMEPAGE_TABS_BUTTON;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new TabsLegacyPageObject();
|
|
|
@ -1,12 +0,0 @@
|
||||||
import TabsLegacyPageObject from '../pages/TabsLegacyPageObject';
|
|
||||||
|
|
||||||
// Before testing begins, allow up to 60 seconds for app to open
|
|
||||||
describe('Tabs Legacy Testing Initialization', () => {
|
|
||||||
it('Wait for app load', async () => {
|
|
||||||
expect(await TabsLegacyPageObject.waitForInitialPageToDisplay()).toBeTrue();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Click and navigate to Tabs Legacy test page', async () => {
|
|
||||||
expect(await TabsLegacyPageObject.navigateToPageAndLoadTests()).toBeTrue();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,108 +0,0 @@
|
||||||
import { TAB_A11Y_ROLE, TABITEM_A11Y_ROLE, Keys, Attribute } from '../../common/consts';
|
|
||||||
import TabsLegacyPageObject from '../pages/TabsLegacyPageObject';
|
|
||||||
|
|
||||||
// Before testing begins, allow up to 60 seconds for app to open
|
|
||||||
describe('Tabs Legacy Testing Initialization', () => {
|
|
||||||
it('Wait for app load', async () => {
|
|
||||||
expect(await TabsLegacyPageObject.waitForInitialPageToDisplay()).toBeTrue();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Click and navigate to Tabs Legacy test page', async () => {
|
|
||||||
expect(await TabsLegacyPageObject.navigateToPageAndLoadTests()).toBeTrue();
|
|
||||||
|
|
||||||
/* Expand E2E section */
|
|
||||||
expect(await TabsLegacyPageObject.enableE2ETesterMode()).toBeTrue();
|
|
||||||
|
|
||||||
expect(await TabsLegacyPageObject.didAssertPopup())
|
|
||||||
.withContext(TabsLegacyPageObject.ERRORMESSAGE_ASSERT)
|
|
||||||
.toBeFalsy(); // Ensure no asserts popped up
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Tabs Legacy Accessibility Testing', () => {
|
|
||||||
/* Scrolls and waits for the Tabs to be visible on the Test Page */
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TabsLegacyPageObject.scrollToTestElement();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Validate Tab\'s "accessibilityRole" defaults to "ControlType.Tab".', async () => {
|
|
||||||
expect(
|
|
||||||
await TabsLegacyPageObject.compareAttribute(TabsLegacyPageObject._primaryComponent, Attribute.AccessibilityRole, TAB_A11Y_ROLE),
|
|
||||||
).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Validate TabItem\'s "accessibilityRole" defaults to "ControlType.TabItem".', async () => {
|
|
||||||
expect(
|
|
||||||
await TabsLegacyPageObject.compareAttribute(TabsLegacyPageObject.getTabItem('First'), Attribute.AccessibilityRole, TABITEM_A11Y_ROLE),
|
|
||||||
).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Tabs Legacy Functional Tests', () => {
|
|
||||||
/* Scrolls and waits for the Tabs to be visible on the Test Page */
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TabsLegacyPageObject.scrollToTestElement();
|
|
||||||
|
|
||||||
// Reset the TabGroup by putting focus on First tab item
|
|
||||||
await TabsLegacyPageObject.click(TabsLegacyPageObject.getTabItem('First'));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Click on the second tab header. Validate the second TabItem content is shown.', async () => {
|
|
||||||
await TabsLegacyPageObject.click(TabsLegacyPageObject.getTabItem('Second'));
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await TabsLegacyPageObject.waitForTabItemContentToLoad(
|
|
||||||
'Second',
|
|
||||||
"Expected the second tab item's content to show by clicking the second tab item.",
|
|
||||||
),
|
|
||||||
).toBeTruthy();
|
|
||||||
expect(await TabsLegacyPageObject.didAssertPopup())
|
|
||||||
.withContext(TabsLegacyPageObject.ERRORMESSAGE_ASSERT)
|
|
||||||
.toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Input the following arrow keys on the tabs: Right -> Down -> Left -> Up. Validate the correct TabItem content gets shown.', async () => {
|
|
||||||
/* At First tab element, press Right Arrow to navigate to the Second tab element */
|
|
||||||
await TabsLegacyPageObject.sendKeys(TabsLegacyPageObject.getTabItem('First'), [Keys.ARROW_RIGHT]);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await TabsLegacyPageObject.waitForTabItemContentToLoad(
|
|
||||||
'Second',
|
|
||||||
'Expected the second tab item\'s content to show by pressing "Right Arrow" on the first tab item.',
|
|
||||||
),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
/* At Second tab element, press Down Arrow to navigate to the Third tab element */
|
|
||||||
await TabsLegacyPageObject.sendKeys(TabsLegacyPageObject.getTabItem('Second'), [Keys.ARROW_DOWN]);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await TabsLegacyPageObject.waitForTabItemContentToLoad(
|
|
||||||
'Third',
|
|
||||||
'Expected the third tab item\'s content to show by pressing "Down Arrow" on the second tab item.',
|
|
||||||
),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
/* At Third tab element, press Left Arrow to navigate to the Second tab element */
|
|
||||||
await TabsLegacyPageObject.sendKeys(TabsLegacyPageObject.getTabItem('Third'), [Keys.ARROW_LEFT]);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await TabsLegacyPageObject.waitForTabItemContentToLoad(
|
|
||||||
'Second',
|
|
||||||
'Expected the second tab item\'s content to show by pressing "Left Arrow" on the third tab item.',
|
|
||||||
),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
/* At Second tab element, press Up Arrow to navigate to the First tab element */
|
|
||||||
await TabsLegacyPageObject.sendKeys(TabsLegacyPageObject.getTabItem('Second'), [Keys.ARROW_UP]);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await TabsLegacyPageObject.waitForTabItemContentToLoad(
|
|
||||||
'First',
|
|
||||||
'Expected the first tab item\'s content to show by pressing "Up Arrow" on the first tab item.',
|
|
||||||
),
|
|
||||||
).toBeTruthy();
|
|
||||||
expect(await TabsLegacyPageObject.didAssertPopup())
|
|
||||||
.withContext(TabsLegacyPageObject.ERRORMESSAGE_ASSERT)
|
|
||||||
.toBeFalsy();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,90 +0,0 @@
|
||||||
import { TABITEM_A11Y_ROLE, TAB_A11Y_ROLE, Attribute } from '../../common/consts';
|
|
||||||
import TabsLegacyPageObject from '../pages/TabsLegacyPageObject';
|
|
||||||
|
|
||||||
// Before testing begins, allow up to 60 seconds for app to open
|
|
||||||
describe('Tabs Legacy Testing Initialization', () => {
|
|
||||||
it('Wait for app load', async () => {
|
|
||||||
expect(await TabsLegacyPageObject.waitForInitialPageToDisplay()).toBeTrue();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Click and navigate to Tabs Legacy test page', async () => {
|
|
||||||
expect(await TabsLegacyPageObject.navigateToPageAndLoadTests()).toBeTrue();
|
|
||||||
|
|
||||||
/* Expand E2E section */
|
|
||||||
expect(await TabsLegacyPageObject.enableE2ETesterMode()).toBeTrue();
|
|
||||||
|
|
||||||
expect(await TabsLegacyPageObject.didAssertPopup())
|
|
||||||
.withContext(TabsLegacyPageObject.ERRORMESSAGE_ASSERT)
|
|
||||||
.toBeFalsy(); // Ensure no asserts popped up
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Tabs Legacy Accessibility Testing', () => {
|
|
||||||
/* Scrolls and waits for the Tabs to be visible on the Test Page */
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TabsLegacyPageObject.scrollToTestElement();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Validate Tab\'s "accessibilityRole" defaults to "ControlType.Tab".', async () => {
|
|
||||||
expect(
|
|
||||||
await TabsLegacyPageObject.compareAttribute(TabsLegacyPageObject._primaryComponent, Attribute.AccessibilityRole, TAB_A11Y_ROLE),
|
|
||||||
).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Validate TabItem\'s "accessibilityRole" defaults to "ControlType.TabItem".', async () => {
|
|
||||||
expect(
|
|
||||||
await TabsLegacyPageObject.compareAttribute(TabsLegacyPageObject.getTabItem('First'), Attribute.AccessibilityRole, TABITEM_A11Y_ROLE),
|
|
||||||
).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Tabs Legacy Functional Tests', () => {
|
|
||||||
/* Scrolls and waits for the Tabs to be visible on the Test Page */
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TabsLegacyPageObject.scrollToTestElement();
|
|
||||||
|
|
||||||
// Reset the TabGroup by putting focus on First tab item
|
|
||||||
await TabsLegacyPageObject.click(TabsLegacyPageObject.getTabItem('First'));
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Click on the second tab header. Validate the second TabItem content is shown.', async () => {
|
|
||||||
await TabsLegacyPageObject.click(TabsLegacyPageObject.getTabItem('Second'));
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await TabsLegacyPageObject.waitForTabItemContentToLoad(
|
|
||||||
'Second',
|
|
||||||
"Expected the second tab item's content to show by clicking the second tab item.",
|
|
||||||
),
|
|
||||||
).toBeTruthy();
|
|
||||||
expect(await TabsLegacyPageObject.didAssertPopup())
|
|
||||||
.withContext(TabsLegacyPageObject.ERRORMESSAGE_ASSERT)
|
|
||||||
.toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
// Keyboarding is currently not integrated for UWP tabs - Task #5758598
|
|
||||||
// it('Keyboarding: Arrow Navigation: Right -> Down -> Left -> Up -> Validate the correct TabItem content is shown', () => {
|
|
||||||
// /* At First tab element, press Right Arrow to navigate to the Second tab element */
|
|
||||||
// TabsPageObject.sendKey(Keys.Right_Arrow, 'First');
|
|
||||||
// TabsPageObject.waitForTabsItemsToOpen('Second', PAGE_TIMEOUT);
|
|
||||||
|
|
||||||
// expect(TabsPageObject.didTabItemContentLoad('Second')).toBeTruthy();
|
|
||||||
|
|
||||||
// /* At Second tab element, press Down Arrow to navigate to the Third tab element */
|
|
||||||
// TabsPageObject.sendKey(Keys.Down_Arrow, 'Second');
|
|
||||||
// TabsPageObject.waitForTabsItemsToOpen('Third', PAGE_TIMEOUT);
|
|
||||||
|
|
||||||
// expect(TabsPageObject.didTabItemContentLoad('Third')).toBeTruthy();
|
|
||||||
|
|
||||||
// /* At Third tab element, press Left Arrow to navigate to the Second tab element */
|
|
||||||
// TabsPageObject.sendKey(Keys.Left_Arrow, 'Third');
|
|
||||||
// TabsPageObject.waitForTabsItemsToOpen('Second', PAGE_TIMEOUT);
|
|
||||||
|
|
||||||
// expect(TabsPageObject.didTabItemContentLoad('Second')).toBeTruthy();
|
|
||||||
|
|
||||||
// /* At Second tab element, press Up Arrow to navigate to the First tab element */
|
|
||||||
// TabsPageObject.sendKey(Keys.Up_Arrow, 'Second');
|
|
||||||
// TabsPageObject.waitForTabsItemsToOpen('First', PAGE_TIMEOUT);
|
|
||||||
|
|
||||||
// expect(TabsPageObject.didTabItemContentLoad('First')).toBeTruthy();
|
|
||||||
// });
|
|
||||||
});
|
|
|
@ -1,25 +0,0 @@
|
||||||
export const HOMEPAGE_TABSV1_BUTTON = 'Homepage_TabsV1_Button';
|
|
||||||
export const TABSV1_TESTPAGE = 'TabsV1_TestPage';
|
|
||||||
|
|
||||||
/* E2E Testing TabsV1 1 */
|
|
||||||
export const TABSV1_TEST_COMPONENT = 'TabsV1_Test_Component'; // A component on each specific test page
|
|
||||||
export const TABSV1_ACCESSIBILITY_LABEL = 'E2E testing TabsV1 accessibility label';
|
|
||||||
|
|
||||||
/* E2E Testing TabsV1 2 */
|
|
||||||
export const TABSV1_NO_A11Y_LABEL_COMPONENT = 'TabsV1_No_A11y_label_Component';
|
|
||||||
export const TABSV1_TEST_COMPONENT_LABEL = 'Test TabsV1 2 - No Accessibility Label'; // A component on each specific test page
|
|
||||||
|
|
||||||
/* E2E Testing TabsItemV1 1 */
|
|
||||||
export const TABSITEMV1_ITEM_1_ACCESSIBILITY_LABEL = 'E2E testing TabItemV1 accessibility label';
|
|
||||||
|
|
||||||
export const TABSITEMV1_ITEM_1 = 'TabItemV1_Item_1'; // A component on each specific test page
|
|
||||||
export const TABSITEMV1_ITEM_2 = 'TabItemV1_Item_2';
|
|
||||||
export const TABSITEMV1_ITEM_3 = 'TabItemV1_Item_3';
|
|
||||||
|
|
||||||
export const TABSITEMV1_CONTENT_1 = 'TabsItemV1_Content_1';
|
|
||||||
export const TABSITEMV1_CONTENT_2 = 'TabsItemV1_Content_2';
|
|
||||||
export const TABSITEMV1_CONTENT_3 = 'TabsItemV1_Content_3';
|
|
||||||
|
|
||||||
/* E2E Testing TabsItemV1 2 */
|
|
||||||
export const TABSITEMV1_NO_A11Y_LABEL_COMPONENT = 'TabItemV1_No_A11y_label_Component';
|
|
||||||
export const TABSITEMV1_TEST_COMPONENT_LABEL = 'Test TabItemV1 2 - No Accessibility Label'; // A component on each specific test page
|
|
|
@ -1,65 +0,0 @@
|
||||||
import { BasePage, By } from '../../common/BasePage';
|
|
||||||
import {
|
|
||||||
TABSV1_TESTPAGE,
|
|
||||||
TABSV1_TEST_COMPONENT,
|
|
||||||
HOMEPAGE_TABSV1_BUTTON,
|
|
||||||
TABSITEMV1_ITEM_1,
|
|
||||||
TABSITEMV1_ITEM_2,
|
|
||||||
TABSITEMV1_ITEM_3,
|
|
||||||
TABSITEMV1_CONTENT_1,
|
|
||||||
TABSITEMV1_CONTENT_2,
|
|
||||||
TABSITEMV1_CONTENT_3,
|
|
||||||
} from '../consts';
|
|
||||||
|
|
||||||
export type TabItem = 'First' | 'Second' | 'Third';
|
|
||||||
|
|
||||||
class TabsV1PageObject extends BasePage {
|
|
||||||
async resetListSelection(): Promise<void> {
|
|
||||||
(await this.getTabItem('First')).click();
|
|
||||||
await this.waitForTabItemContentToLoad('First', 'Reset TabList, first tab should be selected');
|
|
||||||
}
|
|
||||||
|
|
||||||
async waitForTabItemContentToLoad(selector: TabItem, errorMsg: string): Promise<boolean | void> {
|
|
||||||
const content = await this.getTabItemContent(selector);
|
|
||||||
return await this.waitForCondition(async () => await content.isDisplayed(), errorMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTabItem(selector: TabItem): Promise<WebdriverIO.Element> {
|
|
||||||
switch (selector) {
|
|
||||||
case 'First':
|
|
||||||
return await By(TABSITEMV1_ITEM_1);
|
|
||||||
case 'Second':
|
|
||||||
return await By(TABSITEMV1_ITEM_2);
|
|
||||||
case 'Third':
|
|
||||||
return await By(TABSITEMV1_ITEM_3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async getTabItemContent(selector: TabItem): Promise<WebdriverIO.Element> {
|
|
||||||
switch (selector) {
|
|
||||||
case 'First':
|
|
||||||
return await By(TABSITEMV1_CONTENT_1);
|
|
||||||
case 'Second':
|
|
||||||
return await By(TABSITEMV1_CONTENT_2);
|
|
||||||
case 'Third':
|
|
||||||
return await By(TABSITEMV1_CONTENT_3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*****************************************/
|
|
||||||
/**************** Getters ****************/
|
|
||||||
/*****************************************/
|
|
||||||
get _pageName() {
|
|
||||||
return TABSV1_TESTPAGE;
|
|
||||||
}
|
|
||||||
|
|
||||||
get _primaryComponentName() {
|
|
||||||
return TABSV1_TEST_COMPONENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
get _pageButtonName() {
|
|
||||||
return HOMEPAGE_TABSV1_BUTTON;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default new TabsV1PageObject();
|
|
|
@ -1,12 +0,0 @@
|
||||||
import TabsV1PageObject from '../pages/TabsV1PageObject';
|
|
||||||
|
|
||||||
// Before testing begins, allow up to 60 seconds for app to open
|
|
||||||
describe('TabsV1 Testing Initialization', () => {
|
|
||||||
it('Wait for app load', async () => {
|
|
||||||
expect(await TabsV1PageObject.waitForInitialPageToDisplay()).toBeTrue();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Click and navigate to TabsV1 test page', async () => {
|
|
||||||
expect(await TabsV1PageObject.navigateToPageAndLoadTests()).toBeTrue();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -1,104 +0,0 @@
|
||||||
import { Attribute, Keys, TAB_A11Y_ROLE, TABITEM_A11Y_ROLE } from '../../common/consts';
|
|
||||||
import TabsV1PageObject from '../pages/TabsV1PageObject';
|
|
||||||
|
|
||||||
// Before testing begins, allow up to 60 seconds for app to open
|
|
||||||
describe('TabsV1 Testing Initialization', () => {
|
|
||||||
it('Wait for app load', async () => {
|
|
||||||
expect(await TabsV1PageObject.waitForInitialPageToDisplay()).toBeTrue();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Click and navigate to TabsV1 test page', async () => {
|
|
||||||
expect(await TabsV1PageObject.navigateToPageAndLoadTests()).toBeTrue();
|
|
||||||
|
|
||||||
/* Expand E2E section */
|
|
||||||
expect(await TabsV1PageObject.enableE2ETesterMode()).toBeTrue();
|
|
||||||
|
|
||||||
expect(await TabsV1PageObject.didAssertPopup())
|
|
||||||
.withContext(TabsV1PageObject.ERRORMESSAGE_ASSERT)
|
|
||||||
.toBeFalsy(); // Ensure no asserts popped up
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('TabsV1 Accessibility Testing', () => {
|
|
||||||
it('Validate Tab\'s "accessibilityRole" defaults to "ControlType.Tab".', async () => {
|
|
||||||
expect(
|
|
||||||
await TabsV1PageObject.compareAttribute(TabsV1PageObject._primaryComponent, Attribute.AccessibilityRole, TAB_A11Y_ROLE),
|
|
||||||
).toBeTruthy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Validate TabItem\'s "accessibilityRole" defaults to "ControlType.TabItem".', async () => {
|
|
||||||
expect(
|
|
||||||
await TabsV1PageObject.compareAttribute(TabsV1PageObject.getTabItem('First'), Attribute.AccessibilityRole, TABITEM_A11Y_ROLE),
|
|
||||||
).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('TabsV1 Functional Tests', () => {
|
|
||||||
/* Scrolls and waits for the Tabs to be visible on the Test Page */
|
|
||||||
beforeEach(async () => {
|
|
||||||
await TabsV1PageObject.scrollToTestElement();
|
|
||||||
|
|
||||||
// Reset the TabGroup by putting focus on First tab item
|
|
||||||
await TabsV1PageObject.resetListSelection();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Click on the second tab header. Validate the second TabItem content is shown.', async () => {
|
|
||||||
await TabsV1PageObject.click(TabsV1PageObject.getTabItem('Second'));
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await TabsV1PageObject.waitForTabItemContentToLoad(
|
|
||||||
'Second',
|
|
||||||
"Expected the second tab item's content to show by clicking the second tab item.",
|
|
||||||
),
|
|
||||||
).toBeTruthy();
|
|
||||||
expect(await TabsV1PageObject.didAssertPopup())
|
|
||||||
.withContext(TabsV1PageObject.ERRORMESSAGE_ASSERT)
|
|
||||||
.toBeFalsy();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Input the following arrow keys on the tabs: Right -> Down -> Left -> Up. Validate the correct TabItem content gets shown.', async () => {
|
|
||||||
/* At First tab element, press Right Arrow to navigate to the Second tab element */
|
|
||||||
await TabsV1PageObject.sendKeys(TabsV1PageObject.getTabItem('First'), [Keys.ARROW_RIGHT]);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await TabsV1PageObject.waitForTabItemContentToLoad(
|
|
||||||
'Second',
|
|
||||||
'Expected the second tab item\'s content to show by pressing "Right Arrow" on the first tab item.',
|
|
||||||
),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
/* At Second tab element, press Down Arrow to navigate to the Third tab element */
|
|
||||||
await TabsV1PageObject.sendKeys(TabsV1PageObject.getTabItem('Second'), [Keys.ARROW_DOWN]);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await TabsV1PageObject.waitForTabItemContentToLoad(
|
|
||||||
'Third',
|
|
||||||
'Expected the third tab item\'s content to show by pressing "Down Arrow" on the second tab item.',
|
|
||||||
),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
/* At Third tab element, press Left Arrow to navigate to the Second tab element */
|
|
||||||
await TabsV1PageObject.sendKeys(TabsV1PageObject.getTabItem('Third'), [Keys.ARROW_LEFT]);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await TabsV1PageObject.waitForTabItemContentToLoad(
|
|
||||||
'Second',
|
|
||||||
'Expected the second tab item\'s content to show by pressing "Left Arrow" on the third tab item.',
|
|
||||||
),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
/* At Second tab element, press Up Arrow to navigate to the First tab element */
|
|
||||||
await TabsV1PageObject.sendKeys(TabsV1PageObject.getTabItem('Second'), [Keys.ARROW_UP]);
|
|
||||||
|
|
||||||
expect(
|
|
||||||
await TabsV1PageObject.waitForTabItemContentToLoad(
|
|
||||||
'First',
|
|
||||||
'Expected the first tab item\'s content to show by pressing "Up Arrow" on the first tab item.',
|
|
||||||
),
|
|
||||||
).toBeTruthy();
|
|
||||||
|
|
||||||
expect(await TabsV1PageObject.didAssertPopup())
|
|
||||||
.withContext(TabsV1PageObject.ERRORMESSAGE_ASSERT)
|
|
||||||
.toBeFalsy();
|
|
||||||
});
|
|
||||||
});
|
|
|
@ -35,8 +35,6 @@ export * from './StrokeWidthTokens/consts';
|
||||||
export * from './Svg/consts';
|
export * from './Svg/consts';
|
||||||
export * from './Switch/consts';
|
export * from './Switch/consts';
|
||||||
export * from './TabList/consts';
|
export * from './TabList/consts';
|
||||||
export * from './TabsLegacy/consts';
|
|
||||||
export * from './TabsV1/consts';
|
|
||||||
export * from './TextLegacy/consts';
|
export * from './TextLegacy/consts';
|
||||||
export * from './TextV1/consts';
|
export * from './TextV1/consts';
|
||||||
export * from './Theme/consts';
|
export * from './Theme/consts';
|
||||||
|
|
|
@ -56,7 +56,6 @@
|
||||||
"@fluentui-react-native/experimental-native-date-picker": ">=0.10.0 <1.0.0",
|
"@fluentui-react-native/experimental-native-date-picker": ">=0.10.0 <1.0.0",
|
||||||
"@fluentui-react-native/experimental-shadow": "0.5.6",
|
"@fluentui-react-native/experimental-shadow": "0.5.6",
|
||||||
"@fluentui-react-native/experimental-shimmer": "0.12.8",
|
"@fluentui-react-native/experimental-shimmer": "0.12.8",
|
||||||
"@fluentui-react-native/experimental-tabs": "0.10.7",
|
|
||||||
"@fluentui-react-native/experimental-text": ">=0.14.6 <1.0.0",
|
"@fluentui-react-native/experimental-text": ">=0.14.6 <1.0.0",
|
||||||
"@fluentui-react-native/framework": ">=0.13.5 <1.0.0",
|
"@fluentui-react-native/framework": ">=0.13.5 <1.0.0",
|
||||||
"@fluentui-react-native/icon": "0.20.7",
|
"@fluentui-react-native/icon": "0.20.7",
|
||||||
|
|
|
@ -1,94 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import { View } from 'react-native';
|
|
||||||
|
|
||||||
import { Tabs, TabsItem, Text } from '@fluentui/react-native';
|
|
||||||
|
|
||||||
import {
|
|
||||||
TABS_TEST_COMPONENT,
|
|
||||||
TABS_ACCESSIBILITY_LABEL,
|
|
||||||
TABS_TEST_COMPONENT_LABEL,
|
|
||||||
TABS_NO_A11Y_LABEL_COMPONENT,
|
|
||||||
SECOND_TABS_ITEM_CONTENT,
|
|
||||||
FIRST_TABS_ITEM,
|
|
||||||
SECOND_TABS_ITEM,
|
|
||||||
THIRD_TABS_ITEM,
|
|
||||||
FIRST_TABS_ITEM_ACCESSIBILITY_LABEL,
|
|
||||||
THIRD_TABS_ITEM_LABEL,
|
|
||||||
THIRD_TABS_ITEM_CONTENT,
|
|
||||||
FIRST_TABS_ITEM_CONTENT,
|
|
||||||
} from '../../../../E2E/src/TabsLegacy/consts';
|
|
||||||
import { stackStyle } from '../Common/styles';
|
|
||||||
import { testProps } from '../Common/TestProps';
|
|
||||||
|
|
||||||
export const TabsLegacyE2ETest: React.FunctionComponent = () => {
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs
|
|
||||||
label="Tabs"
|
|
||||||
accessibilityLabel={TABS_ACCESSIBILITY_LABEL}
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(TABS_TEST_COMPONENT)}
|
|
||||||
>
|
|
||||||
<TabsItem
|
|
||||||
headerText="Home"
|
|
||||||
itemKey="A"
|
|
||||||
accessibilityLabel={FIRST_TABS_ITEM_ACCESSIBILITY_LABEL}
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(FIRST_TABS_ITEM)}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(FIRST_TABS_ITEM_CONTENT)}
|
|
||||||
>
|
|
||||||
Tabs #1
|
|
||||||
</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem
|
|
||||||
headerText="Files"
|
|
||||||
itemKey="B"
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(SECOND_TABS_ITEM)}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(SECOND_TABS_ITEM_CONTENT)}
|
|
||||||
>
|
|
||||||
Tabs #2
|
|
||||||
</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem
|
|
||||||
headerText={THIRD_TABS_ITEM_LABEL}
|
|
||||||
itemKey="C"
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(THIRD_TABS_ITEM)}
|
|
||||||
>
|
|
||||||
<Text
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(THIRD_TABS_ITEM_CONTENT)}
|
|
||||||
>
|
|
||||||
Tabs #3
|
|
||||||
</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs
|
|
||||||
label={TABS_TEST_COMPONENT_LABEL}
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(TABS_NO_A11Y_LABEL_COMPONENT)}
|
|
||||||
>
|
|
||||||
<TabsItem headerText="Home" itemKey="A">
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Files" itemKey="B">
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Settings" itemKey="C">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,302 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import { Platform, View } from 'react-native';
|
|
||||||
|
|
||||||
import { Tabs, TabsItem, Text, Button } from '@fluentui/react-native';
|
|
||||||
|
|
||||||
import { TabsLegacyE2ETest } from './TabsLegacyE2ETest';
|
|
||||||
import { TABS_TESTPAGE } from '../../../../E2E/src/TabsLegacy/consts';
|
|
||||||
import { svgProps } from '../Common/iconExamples';
|
|
||||||
import { stackStyle } from '../Common/styles';
|
|
||||||
import type { TestSection, PlatformStatus } from '../Test';
|
|
||||||
import { Test } from '../Test';
|
|
||||||
|
|
||||||
const TabsMainTest: React.FunctionComponent = () => {
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs label="Tabs">
|
|
||||||
<TabsItem headerText="Home" itemKey="A">
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Files" itemKey="B">
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Settings" itemKey="C">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const DisabledTabs: React.FunctionComponent = () => {
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs label="Tabs">
|
|
||||||
<TabsItem headerText="Home" itemKey="A">
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Files" itemKey="B" disabled={true}>
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Settings" itemKey="C">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsCountIcon: React.FunctionComponent = () => {
|
|
||||||
const svgExample = {
|
|
||||||
svgSource: svgProps,
|
|
||||||
width: 20,
|
|
||||||
height: 20,
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs label="Tabs">
|
|
||||||
<TabsItem headerText="Home" itemKey="A" icon={svgExample} itemCount={23}>
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem itemKey="B" icon={svgExample} itemCount={0}>
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem itemKey="C" icon={svgExample}>
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsClickEventTest: React.FunctionComponent = () => {
|
|
||||||
const [selectedKey, setSelectedKey] = React.useState('home_key');
|
|
||||||
|
|
||||||
const onTabsClick = (key: string) => {
|
|
||||||
setSelectedKey(key);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Text>Last onTabsClick from: {selectedKey}</Text>
|
|
||||||
<Tabs label="Tabs" onTabsClick={onTabsClick} selectedKey={selectedKey}>
|
|
||||||
<TabsItem headerText="Home" itemKey="home_key">
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Files" itemKey="files_key">
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Settings" itemKey="settings_key">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsChangingViews: React.FunctionComponent = () => {
|
|
||||||
// If user wants to control what gets rendered example.
|
|
||||||
const [selectedKey, setSelectedKey] = React.useState('Tabs #1');
|
|
||||||
|
|
||||||
const onTabsClick = (key: string) => {
|
|
||||||
setSelectedKey(key);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs label="Tabs" onTabsClick={onTabsClick} headersOnly={true} selectedKey={selectedKey}>
|
|
||||||
<TabsItem headerText="Home" itemKey="Tabs #1" />
|
|
||||||
<TabsItem headerText="File" itemKey="Tabs #2" />
|
|
||||||
<TabsItem headerText="Settings" itemKey="Tabs #3" />
|
|
||||||
</Tabs>
|
|
||||||
<View style={{ marginVertical: 1 }}>
|
|
||||||
<Text>{selectedKey}</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsRenderSeparately: React.FunctionComponent = () => {
|
|
||||||
const [selectedKey, setSelectedKey] = React.useState('rectangleRed');
|
|
||||||
|
|
||||||
const onTabsClick = (key: string) => {
|
|
||||||
setSelectedKey(key);
|
|
||||||
};
|
|
||||||
|
|
||||||
const getTabId = (key: string) => {
|
|
||||||
return `ShapeColorTabs_${key}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<View
|
|
||||||
accessible={true}
|
|
||||||
focusable={true}
|
|
||||||
accessibilityLabel={getTabId(selectedKey)}
|
|
||||||
style={{
|
|
||||||
width: 100,
|
|
||||||
height: selectedKey === 'squareRed' ? 100 : 200,
|
|
||||||
backgroundColor: selectedKey === 'rectangleGreen' ? 'green' : 'red',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Tabs label="Tabs" onTabsClick={onTabsClick} getTabId={getTabId} headersOnly={true} selectedKey={selectedKey}>
|
|
||||||
<TabsItem headerText="Rectangle Red" itemKey="rectangleRed" />
|
|
||||||
<TabsItem headerText="Square Red" itemKey="squareRed" />
|
|
||||||
<TabsItem headerText="Rectangle Green" itemKey="rectangleGreen" />
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsSettingSelectedKey: React.FunctionComponent = () => {
|
|
||||||
// If user wants to programmatically set the tab's selectedKey with a button example.
|
|
||||||
const [selectedKey, setSelectedKey] = React.useState('home');
|
|
||||||
const [currTabItemIndex, setCurrTabItemIndex] = React.useState(0);
|
|
||||||
const tabItems = ['home', 'file', 'setting'];
|
|
||||||
|
|
||||||
const goToNextTab = () => {
|
|
||||||
const newCurrTabItemIndex = (currTabItemIndex + 1) % 3;
|
|
||||||
setCurrTabItemIndex(newCurrTabItemIndex);
|
|
||||||
setSelectedKey(tabItems[newCurrTabItemIndex]);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs label="Tabs" selectedKey={selectedKey} isCircularNavigation={true}>
|
|
||||||
<TabsItem headerText="Home" itemKey="home">
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="File" itemKey="file">
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Setting" itemKey="setting">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
<Button content="View Next Tab" onClick={goToNextTab} />
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsShowHideItem: React.FunctionComponent = () => {
|
|
||||||
const [showFirstItem, setshowFirstItem] = React.useState(true);
|
|
||||||
|
|
||||||
const toggleShowFirstItem = React.useCallback(() => {
|
|
||||||
setshowFirstItem(!showFirstItem);
|
|
||||||
}, [showFirstItem]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs label="Tabs">
|
|
||||||
{showFirstItem && (
|
|
||||||
<TabsItem headerText="Home" itemKey="home">
|
|
||||||
<Text>Click the button below to show/hide this tabs item.</Text>
|
|
||||||
<Text>The selected item will not change when the number of tabs items changes.</Text>
|
|
||||||
<Text>If the selected item was removed, the new first item will be selected.</Text>
|
|
||||||
</TabsItem>
|
|
||||||
)}
|
|
||||||
<TabsItem headerText="File" itemKey="file">
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Setting" itemKey="setting">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
<Button content={`${showFirstItem ? 'Hide' : 'Show'} First Tabs Item`} onClick={toggleShowFirstItem} />
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsWithFlexibility: React.FunctionComponent = () => {
|
|
||||||
const [selectedKey, setSelectedKey] = React.useState('home');
|
|
||||||
|
|
||||||
const goHomeTab = () => {
|
|
||||||
setSelectedKey('home');
|
|
||||||
};
|
|
||||||
|
|
||||||
const onTabsClick = (key: string) => {
|
|
||||||
setSelectedKey(key);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs selectedKey={selectedKey} onTabsClick={onTabsClick} isCircularNavigation={true}>
|
|
||||||
<TabsItem headerText="Home" itemKey="home">
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="File" itemKey="file">
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Setting" itemKey="setting">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
<Button content="View Home Tab" onClick={goHomeTab} />
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const tabsSections: TestSection[] = [
|
|
||||||
{
|
|
||||||
name: 'Default Tabs',
|
|
||||||
testID: TABS_TESTPAGE,
|
|
||||||
component: TabsMainTest,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Tabs with disabled',
|
|
||||||
component: DisabledTabs,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Trigger onTabsClick event',
|
|
||||||
component: TabsClickEventTest,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'User Custom Render',
|
|
||||||
component: TabsChangingViews,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Render Content Separately',
|
|
||||||
component: TabsRenderSeparately,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Override Selected Key',
|
|
||||||
component: TabsSettingSelectedKey,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Show/Hide Tabs item',
|
|
||||||
component: TabsShowHideItem,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'More Flexibility',
|
|
||||||
component: TabsWithFlexibility,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
const e2eSections: TestSection[] = [
|
|
||||||
{
|
|
||||||
name: 'E2E Tabs Test',
|
|
||||||
component: TabsLegacyE2ETest,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
if (Platform.OS !== 'windows') {
|
|
||||||
tabsSections.push({
|
|
||||||
name: 'Count and Icon',
|
|
||||||
component: TabsCountIcon,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const TabsLegacyTest: React.FunctionComponent = () => {
|
|
||||||
const status: PlatformStatus = {
|
|
||||||
win32Status: 'Experimental',
|
|
||||||
uwpStatus: 'Experimental',
|
|
||||||
iosStatus: 'Backlog',
|
|
||||||
macosStatus: 'Experimental',
|
|
||||||
androidStatus: 'Backlog',
|
|
||||||
};
|
|
||||||
|
|
||||||
const description = 'With Tabs, users can navigate to another view.';
|
|
||||||
|
|
||||||
return <Test name="Tabs Legacy Test" description={description} sections={tabsSections} status={status} e2eSections={e2eSections} />;
|
|
||||||
};
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './TabsLegacyTest';
|
|
|
@ -1,76 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import { View } from 'react-native';
|
|
||||||
|
|
||||||
import { Tabs, TabsItem } from '@fluentui-react-native/experimental-tabs';
|
|
||||||
import { TextV1 as Text } from '@fluentui-react-native/text';
|
|
||||||
|
|
||||||
import {
|
|
||||||
TABSV1_TEST_COMPONENT,
|
|
||||||
TABSV1_ACCESSIBILITY_LABEL,
|
|
||||||
TABSV1_NO_A11Y_LABEL_COMPONENT,
|
|
||||||
TABSV1_TEST_COMPONENT_LABEL,
|
|
||||||
TABSITEMV1_ITEM_1,
|
|
||||||
TABSITEMV1_ITEM_2,
|
|
||||||
TABSITEMV1_ITEM_3,
|
|
||||||
TABSITEMV1_CONTENT_1,
|
|
||||||
TABSITEMV1_CONTENT_2,
|
|
||||||
TABSITEMV1_CONTENT_3,
|
|
||||||
TABSITEMV1_ITEM_1_ACCESSIBILITY_LABEL,
|
|
||||||
TABSITEMV1_NO_A11Y_LABEL_COMPONENT,
|
|
||||||
TABSITEMV1_TEST_COMPONENT_LABEL,
|
|
||||||
} from '../../../../E2E/src/TabsV1/consts';
|
|
||||||
import { stackStyle } from '../Common/styles';
|
|
||||||
import { testProps } from '../Common/TestProps';
|
|
||||||
|
|
||||||
export const TabsV1E2ETest: React.FunctionComponent = () => {
|
|
||||||
return (
|
|
||||||
<View>
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs
|
|
||||||
label="Tabs"
|
|
||||||
accessibilityLabel={TABSV1_ACCESSIBILITY_LABEL}
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(TABSV1_TEST_COMPONENT)}
|
|
||||||
>
|
|
||||||
<TabsItem
|
|
||||||
headerText="Home"
|
|
||||||
itemKey="A"
|
|
||||||
accessibilityLabel={TABSITEMV1_ITEM_1_ACCESSIBILITY_LABEL}
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(TABSITEMV1_ITEM_1)}
|
|
||||||
>
|
|
||||||
<Text {...testProps(TABSITEMV1_CONTENT_1)}>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Files" itemKey="B" {...testProps(TABSITEMV1_ITEM_2)}>
|
|
||||||
<Text {...testProps(TABSITEMV1_CONTENT_2)}>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Settings" itemKey="C" {...testProps(TABSITEMV1_ITEM_3)}>
|
|
||||||
<Text {...testProps(TABSITEMV1_CONTENT_3)}>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs
|
|
||||||
label={TABSV1_TEST_COMPONENT_LABEL}
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(TABSV1_NO_A11Y_LABEL_COMPONENT)}
|
|
||||||
>
|
|
||||||
<TabsItem
|
|
||||||
headerText={TABSITEMV1_TEST_COMPONENT_LABEL}
|
|
||||||
itemKey="A"
|
|
||||||
/* For Android E2E testing purposes, testProps must be passed in after accessibilityLabel. */
|
|
||||||
{...testProps(TABSITEMV1_NO_A11Y_LABEL_COMPONENT)}
|
|
||||||
>
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Files" itemKey="B">
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Settings" itemKey="C">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
|
@ -1,279 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import { View, Platform } from 'react-native';
|
|
||||||
|
|
||||||
import { ButtonV1 as Button } from '@fluentui-react-native/button';
|
|
||||||
import { Tabs, TabsItem } from '@fluentui-react-native/experimental-tabs';
|
|
||||||
import { TextV1 as Text } from '@fluentui-react-native/text';
|
|
||||||
|
|
||||||
import { TabsV1E2ETest } from './TabsV1E2ETest';
|
|
||||||
import { TABSV1_TESTPAGE } from '../../../../E2E/src/TabsV1/consts';
|
|
||||||
import { svgProps } from '../Common/iconExamples';
|
|
||||||
import { stackStyle } from '../Common/styles';
|
|
||||||
import type { TestSection, PlatformStatus } from '../Test';
|
|
||||||
import { Test } from '../Test';
|
|
||||||
|
|
||||||
const TabsMainTest: React.FunctionComponent = () => {
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs label="Tabs">
|
|
||||||
<TabsItem headerText="Home" itemKey="A">
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Files" itemKey="B">
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Settings" itemKey="C">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const DisabledTabs: React.FunctionComponent = () => {
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs label="Tabs">
|
|
||||||
<TabsItem headerText="Home" itemKey="A">
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Files" itemKey="B" disabled={true}>
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Settings" itemKey="C">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsCountIcon: React.FunctionComponent = () => {
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs label="Tabs">
|
|
||||||
<TabsItem headerText="Home" itemKey="A" icon={{ svgSource: svgProps, width: 20, height: 20, style: { margin: 5 } }} itemCount={23}>
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem itemKey="B" icon={{ svgSource: svgProps, width: 20, height: 20 }} itemCount={0}>
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem itemKey="C" icon={{ svgSource: svgProps, width: 20, height: 20 }}>
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsClickEventTest: React.FunctionComponent = () => {
|
|
||||||
const [selectedKey, setSelectedKey] = React.useState('home_key');
|
|
||||||
|
|
||||||
const onTabsClick = React.useCallback(
|
|
||||||
(key: string) => {
|
|
||||||
setSelectedKey(key);
|
|
||||||
},
|
|
||||||
[setSelectedKey],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Text>{'Last onTabsClick from: ' + selectedKey}</Text>
|
|
||||||
<Tabs label="Tabs" onTabsClick={onTabsClick} selectedKey={selectedKey}>
|
|
||||||
<TabsItem headerText="Home" itemKey="home_key">
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Files" itemKey="files_key">
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Settings" itemKey="settings_key">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsChangingViews: React.FunctionComponent = () => {
|
|
||||||
// If User wants to control what gets rendered example
|
|
||||||
const [selectedKey, setSelectedKey] = React.useState('home');
|
|
||||||
|
|
||||||
const onTabsClick = React.useCallback(
|
|
||||||
(key: string) => {
|
|
||||||
setSelectedKey(key);
|
|
||||||
},
|
|
||||||
[setSelectedKey],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs label="Tabs" onTabsClick={onTabsClick} headersOnly={true} selectedKey={selectedKey}>
|
|
||||||
<TabsItem headerText="Home" itemKey="home" />
|
|
||||||
<TabsItem headerText="File" itemKey="file" />
|
|
||||||
<TabsItem headerText="Settings" itemKey="settings" />
|
|
||||||
</Tabs>
|
|
||||||
<View style={{ marginVertical: 1 }}>
|
|
||||||
{selectedKey == 'home' && <Text>Tabs #1</Text>}
|
|
||||||
{selectedKey == 'file' && <Text>Tabs #2</Text>}
|
|
||||||
{selectedKey == 'settings' && <Text>Tabs #3</Text>}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsRenderSeparately: React.FunctionComponent = () => {
|
|
||||||
const [selectedKey, setSelectedKey] = React.useState('rectangleRed');
|
|
||||||
|
|
||||||
const onTabsClick = React.useCallback(
|
|
||||||
(key: string) => {
|
|
||||||
setSelectedKey(key);
|
|
||||||
},
|
|
||||||
[setSelectedKey],
|
|
||||||
);
|
|
||||||
|
|
||||||
const getTabId = (key: string) => {
|
|
||||||
return `ShapeColorPivot_${key}`;
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<View
|
|
||||||
accessible={true}
|
|
||||||
focusable={true}
|
|
||||||
accessibilityLabel={getTabId(selectedKey)}
|
|
||||||
style={{
|
|
||||||
width: 100,
|
|
||||||
height: selectedKey === 'squareRed' ? 100 : 200,
|
|
||||||
backgroundColor: selectedKey === 'rectangleGreen' ? 'green' : 'red',
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
<Tabs label="Tabs" onTabsClick={onTabsClick} getTabId={getTabId} headersOnly={true} selectedKey={selectedKey}>
|
|
||||||
<TabsItem headerText="Rectangle Red" itemKey="rectangleRed" />
|
|
||||||
<TabsItem headerText="Square Red" itemKey="squareRed" />
|
|
||||||
<TabsItem headerText="Rectangle Green" itemKey="rectangleGreen" />
|
|
||||||
</Tabs>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsSettingSelectedKey: React.FunctionComponent = () => {
|
|
||||||
// If user wants to programmatically set the selectedKey to control the view
|
|
||||||
const [selectedKey, setSelectedKey] = React.useState('home');
|
|
||||||
const [currTabItemIndex, setCurrTabItemIndex] = React.useState(0);
|
|
||||||
const tabItems = ['home', 'file', 'setting'];
|
|
||||||
|
|
||||||
const goToNextTab = React.useCallback(() => {
|
|
||||||
const newCurrTabItemIndex = (currTabItemIndex + 1) % 3;
|
|
||||||
setCurrTabItemIndex(newCurrTabItemIndex);
|
|
||||||
setSelectedKey(tabItems[newCurrTabItemIndex]);
|
|
||||||
}, [currTabItemIndex]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs label="Tabs" selectedKey={selectedKey} isCircularNavigation={true}>
|
|
||||||
<TabsItem headerText="Home" itemKey="home">
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="File" itemKey="file">
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Setting" itemKey="setting">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
<Button onClick={goToNextTab}>View Next Tab</Button>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const TabsWithFlexibility: React.FunctionComponent = () => {
|
|
||||||
const [selectedKey, setSelectedKey] = React.useState('home');
|
|
||||||
|
|
||||||
const goHomeTab = React.useCallback(() => {
|
|
||||||
setSelectedKey('home');
|
|
||||||
}, [setSelectedKey]);
|
|
||||||
|
|
||||||
const onTabsClick = React.useCallback(
|
|
||||||
(key: string) => {
|
|
||||||
setSelectedKey(key);
|
|
||||||
},
|
|
||||||
[setSelectedKey],
|
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<View style={stackStyle}>
|
|
||||||
<Tabs selectedKey={selectedKey} onTabsClick={onTabsClick} isCircularNavigation={true}>
|
|
||||||
<TabsItem headerText="Home" itemKey="home">
|
|
||||||
<Text>Tabs #1</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="File" itemKey="file">
|
|
||||||
<Text>Tabs #2</Text>
|
|
||||||
</TabsItem>
|
|
||||||
<TabsItem headerText="Setting" itemKey="setting">
|
|
||||||
<Text>Tabs #3</Text>
|
|
||||||
</TabsItem>
|
|
||||||
</Tabs>
|
|
||||||
<Button onClick={goHomeTab}>View Home Tab</Button>
|
|
||||||
</View>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
const tabsSections: TestSection[] = [
|
|
||||||
{
|
|
||||||
name: 'Default Tabs',
|
|
||||||
testID: TABSV1_TESTPAGE,
|
|
||||||
component: TabsMainTest,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Tabs with disabled',
|
|
||||||
component: DisabledTabs,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Trigger onTabsClick event',
|
|
||||||
component: TabsClickEventTest,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'User Custom Render',
|
|
||||||
component: TabsChangingViews,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Render Content Separately',
|
|
||||||
component: TabsRenderSeparately,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Override Selected Key',
|
|
||||||
component: TabsSettingSelectedKey,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'More Flexibility',
|
|
||||||
component: TabsWithFlexibility,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
if (Platform.OS !== 'windows') {
|
|
||||||
tabsSections.push({
|
|
||||||
name: 'Count and Icon',
|
|
||||||
component: TabsCountIcon,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const e2eSections: TestSection[] = [
|
|
||||||
{
|
|
||||||
name: 'E2E Testing TabsV1',
|
|
||||||
component: TabsV1E2ETest,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
export const TabsV1Test: React.FunctionComponent = () => {
|
|
||||||
const status: PlatformStatus = {
|
|
||||||
win32Status: 'Production',
|
|
||||||
uwpStatus: 'Experimental',
|
|
||||||
iosStatus: 'Backlog',
|
|
||||||
macosStatus: 'Experimental',
|
|
||||||
androidStatus: 'Backlog',
|
|
||||||
};
|
|
||||||
|
|
||||||
const description = 'With Tabs, users can navigate to another view.';
|
|
||||||
|
|
||||||
return <Test name="TabsV1 Test" description={description} sections={tabsSections} status={status} e2eSections={e2eSections} />;
|
|
||||||
};
|
|
|
@ -1 +0,0 @@
|
||||||
export * from './TabsV1Test';
|
|
|
@ -39,8 +39,6 @@ import { StrokeWidthTest } from './TestComponents/StrokeWidth';
|
||||||
import { SvgTest, RNSVGIconsTest } from './TestComponents/Svg';
|
import { SvgTest, RNSVGIconsTest } from './TestComponents/Svg';
|
||||||
import { SwitchTest } from './TestComponents/Switch';
|
import { SwitchTest } from './TestComponents/Switch';
|
||||||
import { TabListTest } from './TestComponents/TabList/TabListTest';
|
import { TabListTest } from './TestComponents/TabList/TabListTest';
|
||||||
import { TabsLegacyTest } from './TestComponents/TabsLegacy';
|
|
||||||
import { TabsV1Test } from './TestComponents/TabsV1';
|
|
||||||
import { TextLegacyTest } from './TestComponents/TextLegacy';
|
import { TextLegacyTest } from './TestComponents/TextLegacy';
|
||||||
import { TextV1Test } from './TestComponents/TextV1';
|
import { TextV1Test } from './TestComponents/TextV1';
|
||||||
import { ThemeTest } from './TestComponents/Theme';
|
import { ThemeTest } from './TestComponents/Theme';
|
||||||
|
@ -302,18 +300,6 @@ export const tests: TestDescription[] = [
|
||||||
testPageButton: Constants.HOMEPAGE_TABLIST_BUTTON,
|
testPageButton: Constants.HOMEPAGE_TABLIST_BUTTON,
|
||||||
platforms: ['macos', 'win32', 'windows'],
|
platforms: ['macos', 'win32', 'windows'],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'Tabs Legacy',
|
|
||||||
component: TabsLegacyTest,
|
|
||||||
testPageButton: Constants.HOMEPAGE_TABS_BUTTON,
|
|
||||||
platforms: ['macos', 'win32', 'windows'],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Tabs V1',
|
|
||||||
component: TabsV1Test,
|
|
||||||
testPageButton: Constants.HOMEPAGE_TABSV1_BUTTON,
|
|
||||||
platforms: ['macos', 'win32', 'windows'],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
name: 'Text Legacy',
|
name: 'Text Legacy',
|
||||||
component: TextLegacyTest,
|
component: TextLegacyTest,
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"type": "minor",
|
||||||
|
"comment": "Remove Tabs and Experimental Tabs packages",
|
||||||
|
"packageName": "@fluentui/react-native",
|
||||||
|
"email": "winlarry@microsoft.com",
|
||||||
|
"dependentChangeType": "patch"
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"type": "minor",
|
||||||
|
"comment": "Remove Tabs and Experimental Tabs packages",
|
||||||
|
"packageName": "@fluentui-react-native/dependency-profiles",
|
||||||
|
"email": "winlarry@microsoft.com",
|
||||||
|
"dependentChangeType": "patch"
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"type": "patch",
|
||||||
|
"comment": "Remove Tabs and Experimental Tabs E2E tests",
|
||||||
|
"packageName": "@fluentui-react-native/e2e-testing",
|
||||||
|
"email": "winlarry@microsoft.com",
|
||||||
|
"dependentChangeType": "patch"
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"type": "minor",
|
||||||
|
"comment": "Remove Tabs and Experimental Tabs test pages",
|
||||||
|
"packageName": "@fluentui-react-native/tester",
|
||||||
|
"email": "winlarry@microsoft.com",
|
||||||
|
"dependentChangeType": "patch"
|
||||||
|
}
|
|
@ -18,7 +18,7 @@ export const tokens: TokenSettings<TTokens, Theme> = (t: Theme) =>
|
||||||
color: t.colors.neutralStrokeAccessible,
|
color: t.colors.neutralStrokeAccessible,
|
||||||
} as TTokens);
|
} as TTokens);
|
||||||
|
|
||||||
export const Foo = compose<TabItemType>({
|
export const Foo = compose<FooType>({
|
||||||
displayName: fooName,
|
displayName: fooName,
|
||||||
tokens: tokens,
|
tokens: tokens,
|
||||||
slots: {
|
slots: {
|
||||||
|
@ -50,7 +50,7 @@ export const Foo = compose<TabItemType>({
|
||||||
export default Foo;
|
export default Foo;
|
||||||
```
|
```
|
||||||
|
|
||||||
Our [Tab control](../../../../packages/experimental/Tabs/src/TabsItemTokens.ts) uses this system to integrate alias tokens.
|
Our [Radio control](../../../../packages/components/RadioGroup/src/Radio/RadioTokens.ts) uses this system to integrate alias tokens.
|
||||||
|
|
||||||
## Using useTokens hook
|
## Using useTokens hook
|
||||||
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: ['@fluentui-react-native/eslint-config-rules'],
|
|
||||||
};
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1 +0,0 @@
|
||||||
module.exports = require('@fluentui-react-native/scripts/babel.config');
|
|
|
@ -1,2 +0,0 @@
|
||||||
const { configureReactNativeJest } = require('@fluentui-react-native/scripts');
|
|
||||||
module.exports = configureReactNativeJest('win32');
|
|
|
@ -1,3 +0,0 @@
|
||||||
const { preset } = require('@fluentui-react-native/scripts');
|
|
||||||
|
|
||||||
preset();
|
|
|
@ -1,73 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@fluentui-react-native/tabs",
|
|
||||||
"version": "0.14.7",
|
|
||||||
"description": "A cross-platform Tabs component using the Fluent Design System",
|
|
||||||
"main": "src/index.ts",
|
|
||||||
"module": "src/index.ts",
|
|
||||||
"typings": "lib/index.d.ts",
|
|
||||||
"onPublish": {
|
|
||||||
"main": "lib-commonjs/index.js",
|
|
||||||
"module": "lib/index.js"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "fluentui-scripts build",
|
|
||||||
"clean": "fluentui-scripts clean",
|
|
||||||
"depcheck": "fluentui-scripts depcheck",
|
|
||||||
"just": "fluentui-scripts",
|
|
||||||
"lint": "fluentui-scripts eslint",
|
|
||||||
"test": "fluentui-scripts jest",
|
|
||||||
"update-snapshots": "fluentui-scripts jest -u",
|
|
||||||
"verify-api": "fluentui-scripts verify-api-extractor",
|
|
||||||
"update-api": "fluentui-scripts update-api-extractor",
|
|
||||||
"prettier": "fluentui-scripts prettier",
|
|
||||||
"prettier-fix": "fluentui-scripts prettier --fix true"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/microsoft/fluentui-react-native.git",
|
|
||||||
"directory": "packages/components/Tabs"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@fluentui-react-native/adapters": ">=0.12.0 <1.0.0",
|
|
||||||
"@fluentui-react-native/focus-zone": ">=0.16.6 <1.0.0",
|
|
||||||
"@fluentui-react-native/icon": "0.20.7",
|
|
||||||
"@fluentui-react-native/interactive-hooks": ">=0.25.6 <1.0.0",
|
|
||||||
"@fluentui-react-native/text": ">=0.22.6 <1.0.0",
|
|
||||||
"@fluentui-react-native/tokens": ">=0.22.5 <1.0.0",
|
|
||||||
"@uifabricshared/foundation-composable": ">=0.12.3 <1.0.0",
|
|
||||||
"@uifabricshared/foundation-compose": "^1.14.19",
|
|
||||||
"@uifabricshared/foundation-settings": ">=0.14.0 <1.0.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@fluentui-react-native/eslint-config-rules": "^0.1.1",
|
|
||||||
"@fluentui-react-native/scripts": "^0.1.1",
|
|
||||||
"@fluentui-react-native/test-tools": ">=0.1.1 <1.0.0",
|
|
||||||
"@office-iss/react-native-win32": "^0.72.0",
|
|
||||||
"@react-native/metro-config": "^0.72.0",
|
|
||||||
"react": "18.2.0",
|
|
||||||
"react-native": "^0.72.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "18.2.0",
|
|
||||||
"react-native": "^0.72.0"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "MIT",
|
|
||||||
"rnx-kit": {
|
|
||||||
"kitType": "library",
|
|
||||||
"alignDeps": {
|
|
||||||
"presets": [
|
|
||||||
"microsoft/react-native"
|
|
||||||
],
|
|
||||||
"requirements": [
|
|
||||||
"react-native@0.72"
|
|
||||||
],
|
|
||||||
"capabilities": [
|
|
||||||
"core",
|
|
||||||
"core-android",
|
|
||||||
"core-ios",
|
|
||||||
"react"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,33 +0,0 @@
|
||||||
/*
|
|
||||||
Disclaimer: these styles do not follow a specific figma design, but are
|
|
||||||
meant to be placeholders until new designs are developed
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type { IComposeSettings } from '@uifabricshared/foundation-compose';
|
|
||||||
|
|
||||||
import type { TabsType } from './Tabs.types';
|
|
||||||
import { tabsName } from './Tabs.types';
|
|
||||||
|
|
||||||
export const settings: IComposeSettings<TabsType> = [
|
|
||||||
{
|
|
||||||
tokens: {
|
|
||||||
color: 'menuItemText',
|
|
||||||
variant: 'bodySemibold',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
fontSize: 14,
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
accessible: true,
|
|
||||||
style: {
|
|
||||||
marginLeft: 4,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
stack: {
|
|
||||||
style: {
|
|
||||||
marginTop: 6,
|
|
||||||
flexDirection: 'row',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tabsName,
|
|
||||||
];
|
|
|
@ -1,25 +0,0 @@
|
||||||
import type { IComposeSettings } from '@uifabricshared/foundation-compose';
|
|
||||||
|
|
||||||
import type { TabsType } from './Tabs.types';
|
|
||||||
import { tabsName } from './Tabs.types';
|
|
||||||
|
|
||||||
export const settings: IComposeSettings<TabsType> = [
|
|
||||||
{
|
|
||||||
tokens: {
|
|
||||||
color: 'menuItemText',
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
accessible: true,
|
|
||||||
accessibilityRole: 'tablist',
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
variant: 'subheaderSemibold',
|
|
||||||
},
|
|
||||||
stack: {
|
|
||||||
style: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tabsName,
|
|
||||||
];
|
|
|
@ -1,31 +0,0 @@
|
||||||
import type { IComposeSettings } from '@uifabricshared/foundation-compose';
|
|
||||||
|
|
||||||
import type { TabsType } from './Tabs.types';
|
|
||||||
import { tabsName } from './Tabs.types';
|
|
||||||
|
|
||||||
export const settings: IComposeSettings<TabsType> = [
|
|
||||||
{
|
|
||||||
tokens: {
|
|
||||||
color: 'menuItemText',
|
|
||||||
variant: 'bodySemibold',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
fontSize: 14,
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
accessible: true,
|
|
||||||
accessibilityRole: 'tablist',
|
|
||||||
},
|
|
||||||
stack: {
|
|
||||||
style: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
marginTop: 6,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
label: {
|
|
||||||
style: {
|
|
||||||
marginStart: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tabsName,
|
|
||||||
];
|
|
|
@ -1,172 +0,0 @@
|
||||||
/** @jsxRuntime classic */
|
|
||||||
/** @jsx withSlots */
|
|
||||||
import * as React from 'react';
|
|
||||||
import { Pressable, View } from 'react-native';
|
|
||||||
|
|
||||||
import { filterViewProps } from '@fluentui-react-native/adapters';
|
|
||||||
import { FocusZone } from '@fluentui-react-native/focus-zone';
|
|
||||||
import { useSelectedKey } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
import { Text } from '@fluentui-react-native/text';
|
|
||||||
import { foregroundColorTokens, textTokens, backgroundColorTokens } from '@fluentui-react-native/tokens';
|
|
||||||
import type { ISlots } from '@uifabricshared/foundation-composable';
|
|
||||||
import { withSlots } from '@uifabricshared/foundation-composable';
|
|
||||||
import type { IUseComposeStyling } from '@uifabricshared/foundation-compose';
|
|
||||||
import { compose } from '@uifabricshared/foundation-compose';
|
|
||||||
import { mergeSettings } from '@uifabricshared/foundation-settings';
|
|
||||||
|
|
||||||
import { settings } from './Tabs.settings';
|
|
||||||
import type { TabsType, TabsProps, TabsState, TabsSlotProps, TabsRenderData, TabsContextData } from './Tabs.types';
|
|
||||||
import { tabsName } from './Tabs.types';
|
|
||||||
|
|
||||||
export const TabsContext = React.createContext<TabsContextData>({
|
|
||||||
selectedKey: null,
|
|
||||||
onTabsClick: (/* key: string */) => {
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
getTabId: (/* key:string, index: number*/) => {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
updateSelectedTabsItemRef: (/* ref: React.RefObject<any>*/) => {
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
tabsItemKeys: [],
|
|
||||||
views: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Tabs = compose<TabsType>({
|
|
||||||
displayName: tabsName,
|
|
||||||
|
|
||||||
usePrepareProps: (userProps: TabsProps, useStyling: IUseComposeStyling<TabsType>) => {
|
|
||||||
const defaultComponentRef = React.useRef(null);
|
|
||||||
const {
|
|
||||||
label,
|
|
||||||
accessibilityLabel = userProps.label,
|
|
||||||
selectedKey,
|
|
||||||
headersOnly,
|
|
||||||
defaultSelectedKey,
|
|
||||||
getTabId,
|
|
||||||
componentRef = defaultComponentRef,
|
|
||||||
isCircularNavigation,
|
|
||||||
...rest
|
|
||||||
} = userProps;
|
|
||||||
|
|
||||||
/* The useSelectedKey hook is called after a TabsItem is pressed to update the Tab and TabsItem
|
|
||||||
selected property and call the Tab and TabsItem onTabsClick callback. */
|
|
||||||
const data = useSelectedKey(selectedKey || defaultSelectedKey || null, userProps.onTabsClick);
|
|
||||||
|
|
||||||
const [selectedTabsItemRef, setSelectedTabsItemRef] = React.useState(React.useRef<View>(null));
|
|
||||||
|
|
||||||
const onSelectTabsItemRef = React.useCallback(
|
|
||||||
(ref: React.RefObject<View>) => {
|
|
||||||
setSelectedTabsItemRef(ref);
|
|
||||||
},
|
|
||||||
[setSelectedTabsItemRef],
|
|
||||||
);
|
|
||||||
|
|
||||||
const findTabId = React.useCallback(
|
|
||||||
(key: string, index: number) => {
|
|
||||||
if (getTabId) {
|
|
||||||
return getTabId(key, index);
|
|
||||||
}
|
|
||||||
return `${key}-Tab${index}`;
|
|
||||||
},
|
|
||||||
[getTabId],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Stores views to be displayed.
|
|
||||||
const map = new Map<string, React.ReactNode[]>();
|
|
||||||
|
|
||||||
const state: TabsState = {
|
|
||||||
context: {
|
|
||||||
selectedKey: selectedKey ?? data.selectedKey,
|
|
||||||
onTabsClick: data.onKeySelect,
|
|
||||||
getTabId: findTabId,
|
|
||||||
updateSelectedTabsItemRef: onSelectTabsItemRef,
|
|
||||||
views: map,
|
|
||||||
},
|
|
||||||
info: {
|
|
||||||
headersOnly: headersOnly ?? false,
|
|
||||||
label: !!label,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const styleProps = useStyling(userProps, (override: string) => state[override] || userProps[override]);
|
|
||||||
|
|
||||||
const slotProps = mergeSettings<TabsSlotProps>(styleProps, {
|
|
||||||
root: { ref: componentRef, accessibilityLabel: accessibilityLabel, accessibilityRole: 'tablist', ...rest },
|
|
||||||
label: { children: label },
|
|
||||||
container: { isCircularNavigation: isCircularNavigation, defaultTabbableElement: selectedTabsItemRef },
|
|
||||||
});
|
|
||||||
|
|
||||||
return { slotProps, state };
|
|
||||||
},
|
|
||||||
|
|
||||||
render: (Slots: ISlots<TabsSlotProps>, renderData: TabsRenderData, ...children: React.ReactNode[]) => {
|
|
||||||
if (!renderData.state) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate the tabsItemKeys array.
|
|
||||||
if (children) {
|
|
||||||
const enabledKeys = [];
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
// Generates array of keys and enabled keys.
|
|
||||||
renderData.state.context.tabsItemKeys = React.Children.map(children, (child: React.ReactChild) => {
|
|
||||||
if (React.isValidElement(child)) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
if (!child.props.disabled) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
enabledKeys.push(child.props.itemKey);
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
return child.props.itemKey;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* Sets the default selected TabsItem if a TabsItem is hidden.
|
|
||||||
The default selected Tabsitem is the first enabled TabsItem. */
|
|
||||||
if (!enabledKeys.includes(renderData.state.context.selectedKey)) {
|
|
||||||
renderData.state.context.selectedKey = enabledKeys[0] ?? null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TabsContext.Provider
|
|
||||||
// Passes in the selected key and a hook function to update the newly selected tabsItem and call the client's onTabsClick callback.
|
|
||||||
value={renderData.state?.context}
|
|
||||||
>
|
|
||||||
<Slots.root>
|
|
||||||
{renderData.state?.info?.label && <Slots.label />}
|
|
||||||
<Slots.container>
|
|
||||||
<Slots.stack>{children}</Slots.stack>
|
|
||||||
</Slots.container>
|
|
||||||
<Slots.tabPanel>
|
|
||||||
<TabsContext.Consumer>
|
|
||||||
{(context) => !renderData.state.info.headersOnly && context.views.get(context.selectedKey)}
|
|
||||||
</TabsContext.Consumer>
|
|
||||||
</Slots.tabPanel>
|
|
||||||
</Slots.root>
|
|
||||||
</TabsContext.Provider>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
settings,
|
|
||||||
slots: {
|
|
||||||
root: Pressable,
|
|
||||||
label: Text,
|
|
||||||
container: FocusZone,
|
|
||||||
stack: { slotType: View, filter: filterViewProps },
|
|
||||||
tabPanel: { slotType: View, filter: filterViewProps },
|
|
||||||
},
|
|
||||||
styles: {
|
|
||||||
root: [],
|
|
||||||
label: [foregroundColorTokens, textTokens],
|
|
||||||
stack: [backgroundColorTokens],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Tabs;
|
|
|
@ -1,131 +0,0 @@
|
||||||
import type * as React from 'react';
|
|
||||||
import type { View, ViewProps } from 'react-native';
|
|
||||||
|
|
||||||
import type { FocusZoneProps } from '@fluentui-react-native/focus-zone';
|
|
||||||
import type { PressablePropsExtended } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
import type { ITextProps } from '@fluentui-react-native/text';
|
|
||||||
import type { IForegroundColorTokens, FontTokens, IBackgroundColorTokens } from '@fluentui-react-native/tokens';
|
|
||||||
import type { IRenderData } from '@uifabricshared/foundation-composable';
|
|
||||||
|
|
||||||
export const tabsName = 'Tabs';
|
|
||||||
|
|
||||||
export interface TabsContextData {
|
|
||||||
/**
|
|
||||||
* The currently selected TabsItem's key.
|
|
||||||
*/
|
|
||||||
selectedKey: string | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the index of the currently selected key.
|
|
||||||
*/
|
|
||||||
getTabId?: (key: string, index: number) => string | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the selected tabsItem and calls the client’s onTabsClick callback.
|
|
||||||
*/
|
|
||||||
onTabsClick?: (key: string) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the selected tabsItem's ref to set as the default tabbable element.
|
|
||||||
*/
|
|
||||||
updateSelectedTabsItemRef?: (ref: React.RefObject<any>) => void | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of tabsItem keys in the group.
|
|
||||||
*/
|
|
||||||
tabsItemKeys?: string[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Map to store the corresponding view of each TabsItem.
|
|
||||||
*/
|
|
||||||
views?: Map<string, React.ReactNode[]> | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* GH #964, Reference to the Focus Container as there is no FocusZone on windows.
|
|
||||||
* Windows-Specific Prop.
|
|
||||||
*/
|
|
||||||
focusZoneRef?: React.RefObject<any> | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsInfo {
|
|
||||||
headersOnly?: boolean;
|
|
||||||
label?: boolean;
|
|
||||||
/**
|
|
||||||
* Array of enabled keys in the group
|
|
||||||
* Windows-Specific Prop.
|
|
||||||
*/
|
|
||||||
enabledKeys?: string[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsState {
|
|
||||||
context: TabsContextData;
|
|
||||||
info: TabsInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TabsProps = React.PropsWithChildren<
|
|
||||||
Pick<FocusZoneProps, 'isCircularNavigation'> & {
|
|
||||||
/**
|
|
||||||
* Descriptive label for the Tabs. This will be displayed as the title of the Tabs to the user.
|
|
||||||
*/
|
|
||||||
label?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The key of the TabsItem that will initially be selected.
|
|
||||||
*/
|
|
||||||
defaultSelectedKey?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An accessibility label for screen readers. If not provided, it will be set to the label of the Tabs.
|
|
||||||
*/
|
|
||||||
accessibilityLabel?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The key of the selected option. If you provide this, you must maintain selection state by observing
|
|
||||||
* onTabsClick events and passing a new value in when changed. This overrides defaultSelectedKey
|
|
||||||
* and makes the Tabs a controlled component. This prop is mutually exclusive to defaultSelectedKey.
|
|
||||||
*/
|
|
||||||
selectedKey?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for receiving a notification when the choice has been changed.
|
|
||||||
*/
|
|
||||||
onTabsClick?: (key: string) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback to customize how IDs are generated for each tab header.
|
|
||||||
* Useful if you're rendering content outside and need to connect accessibility-labelledby.
|
|
||||||
*/
|
|
||||||
getTabId?: (key: string, index: number) => string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether to only render the header.
|
|
||||||
*/
|
|
||||||
headersOnly?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A RefObject to access Tabs.
|
|
||||||
*/
|
|
||||||
componentRef?: React.RefObject<View>;
|
|
||||||
|
|
||||||
testID?: string;
|
|
||||||
}
|
|
||||||
>;
|
|
||||||
|
|
||||||
export interface TabsTokens extends IForegroundColorTokens, FontTokens, IBackgroundColorTokens {}
|
|
||||||
|
|
||||||
export interface TabsSlotProps {
|
|
||||||
root: React.PropsWithRef<PressablePropsExtended>;
|
|
||||||
label: ITextProps;
|
|
||||||
container: FocusZoneProps;
|
|
||||||
stack: ViewProps;
|
|
||||||
tabPanel: ViewProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TabsRenderData = IRenderData<TabsSlotProps, TabsState>;
|
|
||||||
|
|
||||||
export interface TabsType {
|
|
||||||
props: TabsProps;
|
|
||||||
tokens: TabsTokens;
|
|
||||||
slotProps: TabsSlotProps;
|
|
||||||
state: TabsState;
|
|
||||||
}
|
|
|
@ -1,189 +0,0 @@
|
||||||
/** @jsxRuntime classic */
|
|
||||||
/** @jsx withSlots */
|
|
||||||
import * as React from 'react';
|
|
||||||
import { Pressable, View } from 'react-native';
|
|
||||||
|
|
||||||
import { filterViewProps } from '@fluentui-react-native/adapters';
|
|
||||||
import { useSelectedKey, usePressableState } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
import { Text } from '@fluentui-react-native/text';
|
|
||||||
import { foregroundColorTokens, textTokens, backgroundColorTokens } from '@fluentui-react-native/tokens';
|
|
||||||
import type { ISlots } from '@uifabricshared/foundation-composable';
|
|
||||||
import { withSlots } from '@uifabricshared/foundation-composable';
|
|
||||||
import type { IUseComposeStyling } from '@uifabricshared/foundation-compose';
|
|
||||||
import { compose } from '@uifabricshared/foundation-compose';
|
|
||||||
import { mergeSettings } from '@uifabricshared/foundation-settings';
|
|
||||||
|
|
||||||
import { settings } from './Tabs.settings';
|
|
||||||
import type { TabsType, TabsProps, TabsState, TabsSlotProps, TabsRenderData, TabsContextData } from './Tabs.types';
|
|
||||||
import { tabsName } from './Tabs.types';
|
|
||||||
|
|
||||||
export const TabsContext = React.createContext<TabsContextData>({
|
|
||||||
selectedKey: null,
|
|
||||||
onTabsClick: (/* key: string */) => {
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
getTabId: (/* key:string, index: number*/) => {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
updateSelectedTabsItemRef: (/* ref: React.RefObject<any>*/) => {
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
tabsItemKeys: [],
|
|
||||||
views: null,
|
|
||||||
focusZoneRef: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Tabs = compose<TabsType>({
|
|
||||||
displayName: tabsName,
|
|
||||||
|
|
||||||
usePrepareProps: (userProps: TabsProps, useStyling: IUseComposeStyling<TabsType>) => {
|
|
||||||
const focusZoneRef = React.useRef(null);
|
|
||||||
const defaultComponentRef = React.useRef(null);
|
|
||||||
const {
|
|
||||||
label,
|
|
||||||
accessibilityLabel = userProps.label,
|
|
||||||
selectedKey,
|
|
||||||
headersOnly,
|
|
||||||
defaultSelectedKey,
|
|
||||||
getTabId,
|
|
||||||
componentRef = defaultComponentRef,
|
|
||||||
isCircularNavigation,
|
|
||||||
...rest
|
|
||||||
} = userProps;
|
|
||||||
|
|
||||||
// This hook updates the Selected TabsItem and calls the customer's onTabsClick function. This gets called after a TabsItem is pressed.
|
|
||||||
const data = useSelectedKey(selectedKey || defaultSelectedKey || null, userProps.onTabsClick);
|
|
||||||
|
|
||||||
const findTabId = React.useCallback(
|
|
||||||
(key: string, index: number) => {
|
|
||||||
if (getTabId) {
|
|
||||||
return getTabId(key, index);
|
|
||||||
}
|
|
||||||
return `${key}-Tab${index}`;
|
|
||||||
},
|
|
||||||
[getTabId],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Stores views to be displayed
|
|
||||||
const map = new Map<string, React.ReactNode[]>();
|
|
||||||
|
|
||||||
const state: TabsState = {
|
|
||||||
context: {
|
|
||||||
selectedKey: selectedKey ?? data.selectedKey,
|
|
||||||
onTabsClick: data.onKeySelect,
|
|
||||||
getTabId: findTabId,
|
|
||||||
views: map,
|
|
||||||
focusZoneRef: focusZoneRef,
|
|
||||||
},
|
|
||||||
info: {
|
|
||||||
headersOnly: headersOnly ?? false,
|
|
||||||
label: !!label,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const styleProps = useStyling(userProps, (override: string) => state[override] || userProps[override]);
|
|
||||||
|
|
||||||
const pressable = usePressableState({ ...rest });
|
|
||||||
|
|
||||||
const onKeyDown = (ev: any) => {
|
|
||||||
if (ev.nativeEvent.key === 'ArrowRight' || ev.nativeEvent.key === 'ArrowLeft') {
|
|
||||||
const length = state.info.enabledKeys.length;
|
|
||||||
const currTabItemIndex = state.info.enabledKeys.findIndex((x) => x == state.context.selectedKey);
|
|
||||||
let newCurrTabItemIndex;
|
|
||||||
if (ev.nativeEvent.key === 'ArrowRight') {
|
|
||||||
if (isCircularNavigation || !(currTabItemIndex + 1 == length)) {
|
|
||||||
newCurrTabItemIndex = (currTabItemIndex + 1) % length;
|
|
||||||
state.context.selectedKey = state.info.enabledKeys[newCurrTabItemIndex];
|
|
||||||
data.onKeySelect(state.context.selectedKey);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (isCircularNavigation || !(currTabItemIndex == 0)) {
|
|
||||||
newCurrTabItemIndex = (currTabItemIndex - 1 + length) % length;
|
|
||||||
state.context.selectedKey = state.info.enabledKeys[newCurrTabItemIndex];
|
|
||||||
data.onKeySelect(state.context.selectedKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* GH #964, Extra props are needed because FocusZone is not implemented on windows.
|
|
||||||
The ref focusZoneRef is used to set focus on Tabs when selecting a TabsItem and onKeyDown manages keyboarding */
|
|
||||||
const slotProps = mergeSettings<TabsSlotProps>(styleProps, {
|
|
||||||
root: { ref: componentRef, accessibilityLabel: accessibilityLabel, accessibilityRole: 'tablist', ...pressable.props, ...rest },
|
|
||||||
label: { children: label },
|
|
||||||
stack: { focusable: true, ref: focusZoneRef, onKeyDown: onKeyDown },
|
|
||||||
});
|
|
||||||
|
|
||||||
return { slotProps, state };
|
|
||||||
},
|
|
||||||
|
|
||||||
render: (Slots: ISlots<TabsSlotProps>, renderData: TabsRenderData, ...children: React.ReactNode[]) => {
|
|
||||||
if (!renderData.state) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate the tabsItemKeys array
|
|
||||||
if (children) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
renderData.state.context.tabsItemKeys = React.Children.map(children, (child: React.ReactChild) => {
|
|
||||||
if (React.isValidElement(child)) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
return child.props.itemKey;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
renderData.state.info.enabledKeys = React.Children.map(children, (child: React.ReactChild) => {
|
|
||||||
if (React.isValidElement(child)) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
if (!child.props.disabled) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
return child.props.itemKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* Sets the default selected TabsItem if a TabsItem is hidden.
|
|
||||||
The default selected Tabsitem is the first enabled TabsItem. */
|
|
||||||
if (!renderData.state.info.enabledKeys.includes(renderData.state.context.selectedKey)) {
|
|
||||||
renderData.state.context.selectedKey = renderData.state.info.enabledKeys[0] ?? null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TabsContext.Provider
|
|
||||||
// Passes in the selected key and a hook function to update the newly selected tabsItem and call the client's onTabsClick callback
|
|
||||||
value={renderData.state?.context}
|
|
||||||
>
|
|
||||||
<Slots.root>
|
|
||||||
{renderData.state?.info?.label && <Slots.label />}
|
|
||||||
<Slots.stack>{children}</Slots.stack>
|
|
||||||
<Slots.tabPanel>
|
|
||||||
<TabsContext.Consumer>
|
|
||||||
{(context) => !renderData.state.info.headersOnly && context.views.get(context.selectedKey)}
|
|
||||||
</TabsContext.Consumer>
|
|
||||||
</Slots.tabPanel>
|
|
||||||
</Slots.root>
|
|
||||||
</TabsContext.Provider>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
settings,
|
|
||||||
slots: {
|
|
||||||
root: Pressable,
|
|
||||||
label: Text,
|
|
||||||
stack: View,
|
|
||||||
tabPanel: { slotType: View, filter: filterViewProps },
|
|
||||||
},
|
|
||||||
styles: {
|
|
||||||
root: [],
|
|
||||||
label: [foregroundColorTokens, textTokens],
|
|
||||||
stack: [backgroundColorTokens],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Tabs;
|
|
|
@ -1,86 +0,0 @@
|
||||||
/*
|
|
||||||
Disclaimer: these styles do not follow a specific figma design, but are
|
|
||||||
meant to be placeholders until new designs are developed
|
|
||||||
*/
|
|
||||||
|
|
||||||
import type { IViewProps } from '@fluentui-react-native/adapters';
|
|
||||||
import type { IComposeSettings } from '@uifabricshared/foundation-compose';
|
|
||||||
|
|
||||||
import type { TabsItemType } from './TabsItem.types';
|
|
||||||
import { tabsItemName } from './TabsItem.types';
|
|
||||||
|
|
||||||
export const tabsItemSelectActionLabel = 'Select a TabsItem';
|
|
||||||
|
|
||||||
export const settings: IComposeSettings<TabsItemType> = [
|
|
||||||
{
|
|
||||||
tokens: {
|
|
||||||
color: 'bodyText',
|
|
||||||
variant: 'bodyStandard',
|
|
||||||
indicatorColor: 'transparent',
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
accessible: true,
|
|
||||||
focusable: true,
|
|
||||||
accessibilityRole: 'tab',
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
} as IViewProps,
|
|
||||||
indicator: {
|
|
||||||
style: {
|
|
||||||
minHeight: 2,
|
|
||||||
borderRadius: 2,
|
|
||||||
marginBottom: 2,
|
|
||||||
alignSelf: 'stretch',
|
|
||||||
marginHorizontal: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
stack: {
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
marginHorizontal: 10,
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
minHeight: 32,
|
|
||||||
minWidth: 32,
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_precedence: ['hovered', 'selected', 'disabled'],
|
|
||||||
_overrides: {
|
|
||||||
disabled: {
|
|
||||||
tokens: {
|
|
||||||
color: 'buttonTextDisabled',
|
|
||||||
indicatorColor: 'transparent',
|
|
||||||
fontWeight: 'normal',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hovered: {
|
|
||||||
tokens: {
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
_overrides: {
|
|
||||||
selected: {
|
|
||||||
indicator: {
|
|
||||||
style: {
|
|
||||||
marginHorizontal: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
selected: {
|
|
||||||
tokens: {
|
|
||||||
indicatorColor: 'accentButtonBackground',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tabsItemName,
|
|
||||||
];
|
|
|
@ -1,105 +0,0 @@
|
||||||
import type { PressablePropsExtended } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
import type { IComposeSettings } from '@uifabricshared/foundation-compose';
|
|
||||||
|
|
||||||
import type { TabsItemType } from './TabsItem.types';
|
|
||||||
import { tabsItemName } from './TabsItem.types';
|
|
||||||
|
|
||||||
export const tabsItemSelectActionLabel = 'Select a TabsItem';
|
|
||||||
|
|
||||||
export const settings: IComposeSettings<TabsItemType> = [
|
|
||||||
{
|
|
||||||
tokens: {
|
|
||||||
color: 'neutralStrokeAccessible',
|
|
||||||
variant: 'bodyStandard',
|
|
||||||
borderWidth: 2,
|
|
||||||
borderColor: 'transparent',
|
|
||||||
borderRadius: 4,
|
|
||||||
indicatorColor: 'transparent',
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
accessible: true,
|
|
||||||
focusable: true,
|
|
||||||
accessibilityRole: 'tab',
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
} as PressablePropsExtended,
|
|
||||||
indicator: {
|
|
||||||
style: {
|
|
||||||
minHeight: 2,
|
|
||||||
borderRadius: 2,
|
|
||||||
marginBottom: 2,
|
|
||||||
alignSelf: 'stretch',
|
|
||||||
marginHorizontal: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
stack: {
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
marginHorizontal: 10,
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
minHeight: 32,
|
|
||||||
minWidth: 32,
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_precedence: ['hovered', 'selected', 'focused', 'disabled', 'pressed'],
|
|
||||||
_overrides: {
|
|
||||||
disabled: {
|
|
||||||
tokens: {
|
|
||||||
color: 'neutralForegroundDisabled',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hovered: {
|
|
||||||
tokens: {
|
|
||||||
color: 'neutralForeground1',
|
|
||||||
indicatorColor: 'neutralStroke1',
|
|
||||||
},
|
|
||||||
_overrides: {
|
|
||||||
selected: {
|
|
||||||
indicator: {
|
|
||||||
style: {
|
|
||||||
marginHorizontal: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
selected: {
|
|
||||||
tokens: {
|
|
||||||
color: 'neutralForeground1',
|
|
||||||
variant: 'bodySemibold',
|
|
||||||
indicatorColor: 'brandStroke1',
|
|
||||||
},
|
|
||||||
_overrides: {
|
|
||||||
pressed: {
|
|
||||||
tokens: {
|
|
||||||
indicatorColor: 'neutralStroke1',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
pressed: {
|
|
||||||
tokens: {
|
|
||||||
color: 'neutralForeground1',
|
|
||||||
indicatorColor: 'brandStroke1',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
focused: {
|
|
||||||
tokens: {
|
|
||||||
color: 'neutralForeground1',
|
|
||||||
borderColor: 'neutralForeground1',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tabsItemName,
|
|
||||||
];
|
|
|
@ -1,81 +0,0 @@
|
||||||
import type { PressablePropsExtended } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
import type { IComposeSettings } from '@uifabricshared/foundation-compose';
|
|
||||||
|
|
||||||
import type { TabsItemType } from './TabsItem.types';
|
|
||||||
import { tabsItemName } from './TabsItem.types';
|
|
||||||
|
|
||||||
export const settings: IComposeSettings<TabsItemType> = [
|
|
||||||
{
|
|
||||||
tokens: {
|
|
||||||
color: 'buttonText',
|
|
||||||
variant: 'heroStandard',
|
|
||||||
fontSize: 20,
|
|
||||||
borderWidth: 2,
|
|
||||||
borderColor: 'transparent',
|
|
||||||
borderRadius: 4,
|
|
||||||
indicatorColor: 'transparent',
|
|
||||||
},
|
|
||||||
root: {
|
|
||||||
accessible: true,
|
|
||||||
focusable: false,
|
|
||||||
accessibilityRole: 'tab',
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
justifyContent: 'center',
|
|
||||||
},
|
|
||||||
} as PressablePropsExtended,
|
|
||||||
indicator: {
|
|
||||||
style: {
|
|
||||||
minHeight: 2,
|
|
||||||
borderRadius: 2,
|
|
||||||
marginBottom: 2,
|
|
||||||
alignSelf: 'stretch',
|
|
||||||
marginHorizontal: 10,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
stack: {
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
marginHorizontal: 10,
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
minHeight: 32,
|
|
||||||
minWidth: 32,
|
|
||||||
justifyContent: 'center',
|
|
||||||
opacity: 0.6,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_precedence: ['selected', 'hovered', 'disabled'],
|
|
||||||
_overrides: {
|
|
||||||
disabled: {
|
|
||||||
stack: {
|
|
||||||
style: {
|
|
||||||
opacity: 0.2,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
hovered: {
|
|
||||||
stack: {
|
|
||||||
style: {
|
|
||||||
opacity: 0.8,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
selected: {
|
|
||||||
tokens: {
|
|
||||||
indicatorColor: 'brandStroke1',
|
|
||||||
},
|
|
||||||
stack: {
|
|
||||||
style: {
|
|
||||||
opacity: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
tabsItemName,
|
|
||||||
];
|
|
|
@ -1,169 +0,0 @@
|
||||||
/** @jsxRuntime classic */
|
|
||||||
/** @jsx withSlots */
|
|
||||||
import * as React from 'react';
|
|
||||||
import { Platform, Pressable, View } from 'react-native';
|
|
||||||
|
|
||||||
import { filterViewProps } from '@fluentui-react-native/adapters';
|
|
||||||
import { Icon, createIconProps } from '@fluentui-react-native/icon';
|
|
||||||
import { usePressableState, useViewCommandFocus } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
import { Text } from '@fluentui-react-native/text';
|
|
||||||
import { backgroundColorTokens, borderTokens, textTokens, foregroundColorTokens, getPaletteFromTheme } from '@fluentui-react-native/tokens';
|
|
||||||
import type { ISlots } from '@uifabricshared/foundation-composable';
|
|
||||||
import { withSlots } from '@uifabricshared/foundation-composable';
|
|
||||||
import type { IUseComposeStyling } from '@uifabricshared/foundation-compose';
|
|
||||||
import { compose } from '@uifabricshared/foundation-compose';
|
|
||||||
import { mergeSettings } from '@uifabricshared/foundation-settings';
|
|
||||||
|
|
||||||
import { TabsContext } from './Tabs';
|
|
||||||
import { settings, tabsItemSelectActionLabel } from './TabsItem.settings';
|
|
||||||
import type { TabsItemType, TabsItemProps, TabsItemSlotProps, TabsItemRenderData, TabsItemState } from './TabsItem.types';
|
|
||||||
import { tabsItemName } from './TabsItem.types';
|
|
||||||
|
|
||||||
export const TabsItem = compose<TabsItemType>({
|
|
||||||
displayName: tabsItemName,
|
|
||||||
|
|
||||||
usePrepareProps: (userProps: TabsItemProps, useStyling: IUseComposeStyling<TabsItemType>) => {
|
|
||||||
const defaultComponentRef = React.useRef(null);
|
|
||||||
const {
|
|
||||||
icon,
|
|
||||||
headerText = '',
|
|
||||||
accessibilityLabel = userProps.headerText,
|
|
||||||
componentRef = defaultComponentRef,
|
|
||||||
itemKey,
|
|
||||||
itemCount,
|
|
||||||
accessibilityPositionInSet,
|
|
||||||
accessibilitySetSize,
|
|
||||||
...rest
|
|
||||||
} = userProps;
|
|
||||||
|
|
||||||
// Grabs the context information from Tabs (currently selected TabsItem and client's onTabsClick callback).
|
|
||||||
const info = React.useContext(TabsContext);
|
|
||||||
|
|
||||||
const [focusState, setFocusState] = React.useState({
|
|
||||||
focused: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
const changeSelection = React.useCallback(() => {
|
|
||||||
componentRef?.current?.focus();
|
|
||||||
}, [componentRef]);
|
|
||||||
|
|
||||||
const changeSelectionWithFocus = React.useCallback(() => {
|
|
||||||
setFocusState({ focused: true });
|
|
||||||
if (!focusState.focused) {
|
|
||||||
info.onTabsClick && info.onTabsClick(itemKey);
|
|
||||||
info.getTabId && info.getTabId(itemKey, info.tabsItemKeys.findIndex((x) => x == itemKey) + 1);
|
|
||||||
info.updateSelectedTabsItemRef && componentRef && info.updateSelectedTabsItemRef(componentRef);
|
|
||||||
}
|
|
||||||
}, [focusState, setFocusState, componentRef, info, itemKey]);
|
|
||||||
|
|
||||||
const removeFocus = React.useCallback(() => {
|
|
||||||
setFocusState({ focused: false });
|
|
||||||
}, [setFocusState]);
|
|
||||||
|
|
||||||
const pressable = usePressableState({
|
|
||||||
...rest,
|
|
||||||
onPress: changeSelection,
|
|
||||||
onFocus: changeSelectionWithFocus,
|
|
||||||
onBlur: removeFocus,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set up state.
|
|
||||||
const state: TabsItemState = {
|
|
||||||
info: {
|
|
||||||
...pressable.state,
|
|
||||||
selected: info.selectedKey === userProps.itemKey,
|
|
||||||
icon: !!icon,
|
|
||||||
key: itemKey,
|
|
||||||
headerText: !!headerText || itemCount !== undefined,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
const refWithFocus = useViewCommandFocus(componentRef);
|
|
||||||
const buttonRef = Platform.OS === 'macos' ? componentRef : refWithFocus;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We use the componentRef of the currently selected tabsItem to maintain the default tabbable
|
|
||||||
* element in Tabs. Since the componentRef isn't generated until after initial render,
|
|
||||||
* we must update it once here.
|
|
||||||
* Since this is meant to only be run once, surpressing lint error
|
|
||||||
*/
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (itemKey == info.selectedKey) {
|
|
||||||
info.updateSelectedTabsItemRef && componentRef && info.updateSelectedTabsItemRef(componentRef);
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Grab the styling information from the userProps, referencing the state as well as the props.
|
|
||||||
const styleProps = useStyling(userProps, (override: string) => state.info[override] || userProps[override]);
|
|
||||||
|
|
||||||
// Used when creating accessibility properties in mergeSettings below.
|
|
||||||
const onAccessibilityAction = React.useCallback(
|
|
||||||
(event: { nativeEvent: { actionName: any } }) => {
|
|
||||||
switch (event.nativeEvent.actionName) {
|
|
||||||
case 'Select':
|
|
||||||
changeSelection();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[changeSelection],
|
|
||||||
);
|
|
||||||
|
|
||||||
const countText = itemCount !== undefined ? ` (${itemCount})` : '';
|
|
||||||
|
|
||||||
const slotProps = mergeSettings<TabsItemSlotProps>(styleProps, {
|
|
||||||
root: {
|
|
||||||
...rest,
|
|
||||||
...pressable.props,
|
|
||||||
ref: buttonRef,
|
|
||||||
accessibilityRole: 'tab',
|
|
||||||
accessibilityLabel: accessibilityLabel,
|
|
||||||
accessibilityState: { disabled: userProps.disabled, selected: info.selectedKey === userProps.itemKey },
|
|
||||||
accessibilityActions: [{ name: 'Select', label: tabsItemSelectActionLabel }],
|
|
||||||
accessibilityPositionInSet: accessibilityPositionInSet ?? info.tabsItemKeys.findIndex((x) => x == itemKey) + 1,
|
|
||||||
accessibilitySetSize: accessibilitySetSize ?? info.tabsItemKeys.length,
|
|
||||||
onAccessibilityAction: onAccessibilityAction,
|
|
||||||
focusable: Platform.select({ default: true, macos: !userProps.disabled }),
|
|
||||||
},
|
|
||||||
content: { children: headerText + countText },
|
|
||||||
icon: createIconProps(icon),
|
|
||||||
});
|
|
||||||
|
|
||||||
return { slotProps, state };
|
|
||||||
},
|
|
||||||
|
|
||||||
render: (Slots: ISlots<TabsItemSlotProps>, renderData: TabsItemRenderData, ...children: React.ReactNode[]) => {
|
|
||||||
const info = renderData.state!.info;
|
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
||||||
const context = React.useContext(TabsContext);
|
|
||||||
// Sets the view that belongs to a TabItem.
|
|
||||||
context.views.set(info.key, children);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Slots.root>
|
|
||||||
<Slots.stack>
|
|
||||||
{info.icon && <Slots.icon />}
|
|
||||||
{info.headerText && <Slots.content />}
|
|
||||||
</Slots.stack>
|
|
||||||
<Slots.indicator />
|
|
||||||
</Slots.root>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
settings,
|
|
||||||
slots: {
|
|
||||||
root: Pressable,
|
|
||||||
stack: { slotType: View, filter: filterViewProps },
|
|
||||||
icon: { slotType: Icon as React.ComponentType },
|
|
||||||
content: Text,
|
|
||||||
indicator: { slotType: View, filter: filterViewProps },
|
|
||||||
},
|
|
||||||
styles: {
|
|
||||||
root: [backgroundColorTokens, borderTokens],
|
|
||||||
stack: [],
|
|
||||||
icon: [{ source: 'iconColor', lookup: getPaletteFromTheme, target: 'color' }],
|
|
||||||
content: [textTokens, foregroundColorTokens],
|
|
||||||
indicator: [{ source: 'indicatorColor', lookup: getPaletteFromTheme, target: 'backgroundColor' }],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default TabsItem;
|
|
|
@ -1,119 +0,0 @@
|
||||||
import type * as React from 'react';
|
|
||||||
import type { ViewProps } from 'react-native';
|
|
||||||
|
|
||||||
import type { IconProps, IconSourcesType } from '@fluentui-react-native/icon';
|
|
||||||
import type { IFocusable, PressableState, PressablePropsExtended } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
import type { ITextProps } from '@fluentui-react-native/text';
|
|
||||||
import type { FontTokens, IBackgroundColorTokens, IBorderTokens, IForegroundColorTokens } from '@fluentui-react-native/tokens';
|
|
||||||
import type { IRenderData } from '@uifabricshared/foundation-composable';
|
|
||||||
|
|
||||||
export const tabsItemName = 'TabsItem';
|
|
||||||
|
|
||||||
export interface TabsItemInfo extends PressableState {
|
|
||||||
/**
|
|
||||||
* TabsItem icon.
|
|
||||||
*/
|
|
||||||
icon?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TabsItem text.
|
|
||||||
*/
|
|
||||||
headerText?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates if TabsItem is selected.
|
|
||||||
*/
|
|
||||||
selected: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Key for tabItem.
|
|
||||||
*/
|
|
||||||
key: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsItemState {
|
|
||||||
info: TabsItemInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsItemProps extends PressablePropsExtended {
|
|
||||||
/**
|
|
||||||
* The text string for the option.
|
|
||||||
*/
|
|
||||||
headerText?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number for the TabsItem count.
|
|
||||||
*/
|
|
||||||
itemCount?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A unique key-identifier for each option.
|
|
||||||
*/
|
|
||||||
itemKey: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the tabs item is selectable.
|
|
||||||
*/
|
|
||||||
disabled?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A RefObject to access the IFocusable interface. Use this to access the public methods and properties of the component.
|
|
||||||
*/
|
|
||||||
componentRef?: React.RefObject<IFocusable>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Source URL or name of the icon to show on the TabsItem.
|
|
||||||
*/
|
|
||||||
icon?: IconSourcesType;
|
|
||||||
|
|
||||||
testID?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsItemTokens extends IForegroundColorTokens, FontTokens, IBackgroundColorTokens, IBorderTokens {
|
|
||||||
/**
|
|
||||||
* The indicator color.
|
|
||||||
*/
|
|
||||||
indicatorColor?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The icon color.
|
|
||||||
*/
|
|
||||||
iconColor?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Source URL or name of the icon to show on the TabsItem.
|
|
||||||
*/
|
|
||||||
icon?: IconSourcesType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Text to show on the TabsItem.
|
|
||||||
*/
|
|
||||||
headerText?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The amount of padding between the border and the headerText.
|
|
||||||
*/
|
|
||||||
headerTextPadding?: number | string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The amount of padding between the border and the headerText when the TabsItem has focus.
|
|
||||||
*/
|
|
||||||
headerTextPaddingFocused?: number | string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsItemSlotProps {
|
|
||||||
root: React.PropsWithRef<PressablePropsExtended>;
|
|
||||||
stack: ViewProps;
|
|
||||||
icon: IconProps;
|
|
||||||
content: ITextProps;
|
|
||||||
indicator: ViewProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TabsItemRenderData = IRenderData<TabsItemSlotProps, TabsItemState>;
|
|
||||||
|
|
||||||
export interface TabsItemType {
|
|
||||||
props: TabsItemProps;
|
|
||||||
tokens: TabsItemTokens;
|
|
||||||
slotProps: TabsItemSlotProps;
|
|
||||||
state: TabsItemState;
|
|
||||||
}
|
|
|
@ -1,153 +0,0 @@
|
||||||
/** @jsxRuntime classic */
|
|
||||||
/** @jsx withSlots */
|
|
||||||
import * as React from 'react';
|
|
||||||
import { Pressable, View } from 'react-native';
|
|
||||||
|
|
||||||
import { filterViewProps } from '@fluentui-react-native/adapters';
|
|
||||||
import { Icon, createIconProps } from '@fluentui-react-native/icon';
|
|
||||||
import { usePressableState, useViewCommandFocus } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
import { Text } from '@fluentui-react-native/text';
|
|
||||||
import { backgroundColorTokens, borderTokens, textTokens, foregroundColorTokens, getPaletteFromTheme } from '@fluentui-react-native/tokens';
|
|
||||||
import type { ISlots } from '@uifabricshared/foundation-composable';
|
|
||||||
import { withSlots } from '@uifabricshared/foundation-composable';
|
|
||||||
import type { IUseComposeStyling } from '@uifabricshared/foundation-compose';
|
|
||||||
import { compose } from '@uifabricshared/foundation-compose';
|
|
||||||
import { mergeSettings } from '@uifabricshared/foundation-settings';
|
|
||||||
|
|
||||||
import { TabsContext } from './Tabs';
|
|
||||||
import { settings, tabsItemSelectActionLabel } from './TabsItem.settings';
|
|
||||||
import type { TabsItemType, TabsItemProps, TabsItemSlotProps, TabsItemRenderData, TabsItemState } from './TabsItem.types';
|
|
||||||
import { tabsItemName } from './TabsItem.types';
|
|
||||||
|
|
||||||
export const TabsItem = compose<TabsItemType>({
|
|
||||||
displayName: tabsItemName,
|
|
||||||
|
|
||||||
usePrepareProps: (userProps: TabsItemProps, useStyling: IUseComposeStyling<TabsItemType>) => {
|
|
||||||
const defaultComponentRef = React.useRef(null);
|
|
||||||
const {
|
|
||||||
icon,
|
|
||||||
headerText = '',
|
|
||||||
accessibilityLabel = userProps.headerText,
|
|
||||||
componentRef = defaultComponentRef,
|
|
||||||
itemKey,
|
|
||||||
itemCount,
|
|
||||||
accessibilityPositionInSet,
|
|
||||||
accessibilitySetSize,
|
|
||||||
...rest
|
|
||||||
} = userProps;
|
|
||||||
|
|
||||||
// Grabs the context information from Tabs (currently selected TabsItem and client's onTabsClick callback).
|
|
||||||
const info = React.useContext(TabsContext);
|
|
||||||
|
|
||||||
const changeSelection = React.useCallback(() => {
|
|
||||||
info.focusZoneRef.current.focus(); // GH #964, FocusZone not implemented on windows.
|
|
||||||
info.onTabsClick && info.onTabsClick(itemKey);
|
|
||||||
info.getTabId && info.getTabId(itemKey, info.tabsItemKeys.findIndex((x) => x == itemKey) + 1);
|
|
||||||
info.updateSelectedTabsItemRef && componentRef && info.updateSelectedTabsItemRef(componentRef);
|
|
||||||
}, [componentRef, info, itemKey]);
|
|
||||||
|
|
||||||
const pressable = usePressableState({
|
|
||||||
...rest,
|
|
||||||
onPress: changeSelection,
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set up state.
|
|
||||||
const state: TabsItemState = {
|
|
||||||
info: {
|
|
||||||
...pressable.state,
|
|
||||||
selected: info.selectedKey === userProps.itemKey,
|
|
||||||
icon: false, // GH #935, Icons are on backlog for windows.
|
|
||||||
key: itemKey,
|
|
||||||
headerText: !!headerText || itemCount !== undefined,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
const buttonRef = useViewCommandFocus(componentRef);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We use the componentRef of the currently selected tabsItem to maintain the default tabbable
|
|
||||||
* element in Tabs. Since the componentRef isn't generated until after initial render,
|
|
||||||
* we must update it once here.
|
|
||||||
* Since this is meant to only be run once, surpressing lint error
|
|
||||||
*/
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (itemKey == info.selectedKey) {
|
|
||||||
info.updateSelectedTabsItemRef && componentRef && info.updateSelectedTabsItemRef(componentRef);
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
// Grab the styling information from the userProps, referencing the state as well as the props.
|
|
||||||
const styleProps = useStyling(userProps, (override: string) => state.info[override] || userProps[override]);
|
|
||||||
|
|
||||||
// Used when creating accessibility properties in mergeSettings below.
|
|
||||||
const onAccessibilityAction = React.useCallback(
|
|
||||||
(event: { nativeEvent: { actionName: any } }) => {
|
|
||||||
switch (event.nativeEvent.actionName) {
|
|
||||||
case 'Select':
|
|
||||||
changeSelection();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[changeSelection],
|
|
||||||
);
|
|
||||||
|
|
||||||
const countText = itemCount !== undefined ? ` (${itemCount})` : '';
|
|
||||||
|
|
||||||
const slotProps = mergeSettings<TabsItemSlotProps>(styleProps, {
|
|
||||||
root: {
|
|
||||||
...rest,
|
|
||||||
...pressable.props,
|
|
||||||
ref: buttonRef,
|
|
||||||
accessibilityRole: 'tab',
|
|
||||||
accessibilityLabel: accessibilityLabel,
|
|
||||||
accessibilityState: { disabled: userProps.disabled, selected: info.selectedKey === userProps.itemKey },
|
|
||||||
accessibilityActions: [{ name: 'Select', label: tabsItemSelectActionLabel }],
|
|
||||||
accessibilityPositionInSet: accessibilityPositionInSet ?? info.tabsItemKeys.findIndex((x) => x == itemKey) + 1,
|
|
||||||
accessibilitySetSize: accessibilitySetSize ?? info.tabsItemKeys.length,
|
|
||||||
onAccessibilityAction: onAccessibilityAction,
|
|
||||||
focusable: false,
|
|
||||||
},
|
|
||||||
content: { children: headerText + countText },
|
|
||||||
icon: createIconProps(icon),
|
|
||||||
});
|
|
||||||
|
|
||||||
return { slotProps, state };
|
|
||||||
},
|
|
||||||
|
|
||||||
render: (Slots: ISlots<TabsItemSlotProps>, renderData: TabsItemRenderData, ...children: React.ReactNode[]) => {
|
|
||||||
const info = renderData.state!.info;
|
|
||||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
||||||
const context = React.useContext(TabsContext);
|
|
||||||
// Sets the view that belongs to a TabItem.
|
|
||||||
context.views.set(info.key, children);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Slots.root>
|
|
||||||
<Slots.stack>
|
|
||||||
{info.icon && <Slots.icon />}
|
|
||||||
{info.headerText && <Slots.content />}
|
|
||||||
</Slots.stack>
|
|
||||||
<Slots.indicator />
|
|
||||||
</Slots.root>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
settings,
|
|
||||||
slots: {
|
|
||||||
root: Pressable,
|
|
||||||
stack: { slotType: View, filter: filterViewProps },
|
|
||||||
icon: { slotType: Icon as React.ComponentType },
|
|
||||||
content: Text,
|
|
||||||
indicator: { slotType: View, filter: filterViewProps },
|
|
||||||
},
|
|
||||||
styles: {
|
|
||||||
root: [backgroundColorTokens, borderTokens],
|
|
||||||
stack: [],
|
|
||||||
icon: [{ source: 'iconColor', lookup: getPaletteFromTheme, target: 'color' }],
|
|
||||||
content: [textTokens, foregroundColorTokens],
|
|
||||||
indicator: [{ source: 'indicatorColor', lookup: getPaletteFromTheme, target: 'backgroundColor' }],
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default TabsItem;
|
|
|
@ -1,83 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import * as renderer from 'react-test-renderer';
|
|
||||||
|
|
||||||
import { Tabs, TabsItem } from '..';
|
|
||||||
|
|
||||||
it('Tabs default props', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs>
|
|
||||||
<TabsItem itemKey="1" />
|
|
||||||
<TabsItem itemKey="2" />
|
|
||||||
<TabsItem itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Tabs disabled', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs>
|
|
||||||
<TabsItem itemKey="1" disabled={true} />
|
|
||||||
<TabsItem itemKey="2" disabled={true} />
|
|
||||||
<TabsItem itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Tabs header text and count', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs>
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={1} itemKey="1" />
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={0} itemKey="2" />
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={100} itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Tabs headers only', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs headersOnly={true}>
|
|
||||||
<TabsItem itemKey="1" />
|
|
||||||
<TabsItem itemKey="2" />
|
|
||||||
<TabsItem itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Tabs FocusZone props', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs defaultSelectedKey="2" isCircularNavigation={false}>
|
|
||||||
<TabsItem itemKey="1" />
|
|
||||||
<TabsItem itemKey="2" />
|
|
||||||
<TabsItem itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Tabs props', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs label="Tabs" defaultSelectedKey="2" isCircularNavigation={false} headersOnly={true}>
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={1} itemKey="1" disabled={true} />
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={0} itemKey="2" />
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={100} itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,14 +0,0 @@
|
||||||
export { Tabs, TabsContext } from './Tabs';
|
|
||||||
export { tabsName } from './Tabs.types';
|
|
||||||
export type { TabsContextData, TabsInfo, TabsProps, TabsRenderData, TabsSlotProps, TabsState, TabsTokens, TabsType } from './Tabs.types';
|
|
||||||
export { TabsItem } from './TabsItem';
|
|
||||||
export { tabsItemName } from './TabsItem.types';
|
|
||||||
export type {
|
|
||||||
TabsItemInfo,
|
|
||||||
TabsItemProps,
|
|
||||||
TabsItemRenderData,
|
|
||||||
TabsItemSlotProps,
|
|
||||||
TabsItemState,
|
|
||||||
TabsItemTokens,
|
|
||||||
TabsItemType,
|
|
||||||
} from './TabsItem.types';
|
|
|
@ -1,8 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "@fluentui-react-native/scripts/tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "lib",
|
|
||||||
"types": ["node", "jest"]
|
|
||||||
},
|
|
||||||
"include": ["src"]
|
|
||||||
}
|
|
|
@ -40,7 +40,6 @@
|
||||||
"@fluentui-react-native/experimental-shadow": "*",
|
"@fluentui-react-native/experimental-shadow": "*",
|
||||||
"@fluentui-react-native/experimental-shimmer": "*",
|
"@fluentui-react-native/experimental-shimmer": "*",
|
||||||
"@fluentui-react-native/experimental-stack": "*",
|
"@fluentui-react-native/experimental-stack": "*",
|
||||||
"@fluentui-react-native/experimental-tabs": "*",
|
|
||||||
"@fluentui-react-native/experimental-text": "*",
|
"@fluentui-react-native/experimental-text": "*",
|
||||||
"@fluentui-react-native/focus-trap-zone": "*",
|
"@fluentui-react-native/focus-trap-zone": "*",
|
||||||
"@fluentui-react-native/focus-zone": "*",
|
"@fluentui-react-native/focus-zone": "*",
|
||||||
|
@ -64,7 +63,6 @@
|
||||||
"@fluentui-react-native/stack": "*",
|
"@fluentui-react-native/stack": "*",
|
||||||
"@fluentui-react-native/styling-utils": "*",
|
"@fluentui-react-native/styling-utils": "*",
|
||||||
"@fluentui-react-native/switch": "*",
|
"@fluentui-react-native/switch": "*",
|
||||||
"@fluentui-react-native/tabs": "*",
|
|
||||||
"@fluentui-react-native/tester": "*",
|
"@fluentui-react-native/tester": "*",
|
||||||
"@fluentui-react-native/tester-win32": "*",
|
"@fluentui-react-native/tester-win32": "*",
|
||||||
"@fluentui-react-native/text": "*",
|
"@fluentui-react-native/text": "*",
|
||||||
|
|
|
@ -1,334 +1,326 @@
|
||||||
// This file was generated by 'update-profile.js'
|
// This file was generated by 'update-profile.js'
|
||||||
/* eslint-disable */
|
/* eslint-disable */
|
||||||
module.exports = {
|
module.exports = {
|
||||||
"0.71": {
|
0.71: {
|
||||||
"@fluentui-react-native/e2e-testing": {
|
'@fluentui-react-native/e2e-testing': {
|
||||||
"name": "@fluentui-react-native/e2e-testing",
|
name: '@fluentui-react-native/e2e-testing',
|
||||||
"version": "1.32.8"
|
version: '1.32.8',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/tester": {
|
'@fluentui-react-native/tester': {
|
||||||
"name": "@fluentui-react-native/tester",
|
name: '@fluentui-react-native/tester',
|
||||||
"version": "0.157.10"
|
version: '0.157.10',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/tester-win32": {
|
'@fluentui-react-native/tester-win32': {
|
||||||
"name": "@fluentui-react-native/tester-win32",
|
name: '@fluentui-react-native/tester-win32',
|
||||||
"version": "0.36.17"
|
version: '0.36.17',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/avatar": {
|
'@fluentui-react-native/avatar': {
|
||||||
"name": "@fluentui-react-native/avatar",
|
name: '@fluentui-react-native/avatar',
|
||||||
"version": "1.10.18"
|
version: '1.10.18',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/badge": {
|
'@fluentui-react-native/badge': {
|
||||||
"name": "@fluentui-react-native/badge",
|
name: '@fluentui-react-native/badge',
|
||||||
"version": "0.7.14"
|
version: '0.7.14',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/button": {
|
'@fluentui-react-native/button': {
|
||||||
"name": "@fluentui-react-native/button",
|
name: '@fluentui-react-native/button',
|
||||||
"version": "0.35.11"
|
version: '0.35.11',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/callout": {
|
'@fluentui-react-native/callout': {
|
||||||
"name": "@fluentui-react-native/callout",
|
name: '@fluentui-react-native/callout',
|
||||||
"version": "0.24.19"
|
version: '0.24.19',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/checkbox": {
|
'@fluentui-react-native/checkbox': {
|
||||||
"name": "@fluentui-react-native/checkbox",
|
name: '@fluentui-react-native/checkbox',
|
||||||
"version": "0.21.7"
|
version: '0.21.7',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/chip": {
|
'@fluentui-react-native/chip': {
|
||||||
"name": "@fluentui-react-native/chip",
|
name: '@fluentui-react-native/chip',
|
||||||
"version": "0.2.9"
|
version: '0.2.9',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/contextual-menu": {
|
'@fluentui-react-native/contextual-menu': {
|
||||||
"name": "@fluentui-react-native/contextual-menu",
|
name: '@fluentui-react-native/contextual-menu',
|
||||||
"version": "0.22.25"
|
version: '0.22.25',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/divider": {
|
'@fluentui-react-native/divider': {
|
||||||
"name": "@fluentui-react-native/divider",
|
name: '@fluentui-react-native/divider',
|
||||||
"version": "0.5.16"
|
version: '0.5.16',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/focus-trap-zone": {
|
'@fluentui-react-native/focus-trap-zone': {
|
||||||
"name": "@fluentui-react-native/focus-trap-zone",
|
name: '@fluentui-react-native/focus-trap-zone',
|
||||||
"version": "0.10.14"
|
version: '0.10.14',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/focus-zone": {
|
'@fluentui-react-native/focus-zone': {
|
||||||
"name": "@fluentui-react-native/focus-zone",
|
name: '@fluentui-react-native/focus-zone',
|
||||||
"version": "0.15.0"
|
version: '0.15.0',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/icon": {
|
'@fluentui-react-native/icon': {
|
||||||
"name": "@fluentui-react-native/icon",
|
name: '@fluentui-react-native/icon',
|
||||||
"version": "0.19.16"
|
version: '0.19.16',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/input": {
|
'@fluentui-react-native/input': {
|
||||||
"name": "@fluentui-react-native/input",
|
name: '@fluentui-react-native/input',
|
||||||
"version": "0.4.9"
|
version: '0.4.9',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/link": {
|
'@fluentui-react-native/link': {
|
||||||
"name": "@fluentui-react-native/link",
|
name: '@fluentui-react-native/link',
|
||||||
"version": "0.20.7"
|
version: '0.20.7',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/menu": {
|
'@fluentui-react-native/menu': {
|
||||||
"name": "@fluentui-react-native/menu",
|
name: '@fluentui-react-native/menu',
|
||||||
"version": "1.11.30"
|
version: '1.11.30',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/menu-button": {
|
'@fluentui-react-native/menu-button': {
|
||||||
"name": "@fluentui-react-native/menu-button",
|
name: '@fluentui-react-native/menu-button',
|
||||||
"version": "0.11.31"
|
version: '0.11.31',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/notification": {
|
'@fluentui-react-native/notification': {
|
||||||
"name": "@fluentui-react-native/notification",
|
name: '@fluentui-react-native/notification',
|
||||||
"version": "0.23.22"
|
version: '0.23.22',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/persona": {
|
'@fluentui-react-native/persona': {
|
||||||
"name": "@fluentui-react-native/persona",
|
name: '@fluentui-react-native/persona',
|
||||||
"version": "0.14.12"
|
version: '0.14.12',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/persona-coin": {
|
'@fluentui-react-native/persona-coin': {
|
||||||
"name": "@fluentui-react-native/persona-coin",
|
name: '@fluentui-react-native/persona-coin',
|
||||||
"version": "0.13.12"
|
version: '0.13.12',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/pressable": {
|
'@fluentui-react-native/pressable': {
|
||||||
"name": "@fluentui-react-native/pressable",
|
name: '@fluentui-react-native/pressable',
|
||||||
"version": "0.10.13"
|
version: '0.10.13',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/radio-group": {
|
'@fluentui-react-native/radio-group': {
|
||||||
"name": "@fluentui-react-native/radio-group",
|
name: '@fluentui-react-native/radio-group',
|
||||||
"version": "0.19.9"
|
version: '0.19.9',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/separator": {
|
'@fluentui-react-native/separator': {
|
||||||
"name": "@fluentui-react-native/separator",
|
name: '@fluentui-react-native/separator',
|
||||||
"version": "0.16.10"
|
version: '0.16.10',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/stack": {
|
'@fluentui-react-native/stack': {
|
||||||
"name": "@fluentui-react-native/stack",
|
name: '@fluentui-react-native/stack',
|
||||||
"version": "0.8.16"
|
version: '0.8.16',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/switch": {
|
'@fluentui-react-native/switch': {
|
||||||
"name": "@fluentui-react-native/switch",
|
name: '@fluentui-react-native/switch',
|
||||||
"version": "0.11.7"
|
version: '0.11.7',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/tabs": {
|
'@fluentui-react-native/text': {
|
||||||
"name": "@fluentui-react-native/tabs",
|
name: '@fluentui-react-native/text',
|
||||||
"version": "0.13.19"
|
version: '0.21.14',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/text": {
|
'@uifabricshared/foundation-composable': {
|
||||||
"name": "@fluentui-react-native/text",
|
name: '@uifabricshared/foundation-composable',
|
||||||
"version": "0.21.14"
|
version: '0.12.2',
|
||||||
},
|
},
|
||||||
"@uifabricshared/foundation-composable": {
|
'@uifabricshared/foundation-compose': {
|
||||||
"name": "@uifabricshared/foundation-composable",
|
name: '@uifabricshared/foundation-compose',
|
||||||
"version": "0.12.2"
|
version: '1.14.12',
|
||||||
},
|
},
|
||||||
"@uifabricshared/foundation-compose": {
|
'@uifabricshared/foundation-settings': {
|
||||||
"name": "@uifabricshared/foundation-compose",
|
name: '@uifabricshared/foundation-settings',
|
||||||
"version": "1.14.12"
|
version: '0.13.2',
|
||||||
},
|
},
|
||||||
"@uifabricshared/foundation-settings": {
|
'@uifabricshared/foundation-tokens': {
|
||||||
"name": "@uifabricshared/foundation-settings",
|
name: '@uifabricshared/foundation-tokens',
|
||||||
"version": "0.13.2"
|
version: '0.13.9',
|
||||||
},
|
},
|
||||||
"@uifabricshared/foundation-tokens": {
|
'@uifabricshared/theme-registry': {
|
||||||
"name": "@uifabricshared/foundation-tokens",
|
name: '@uifabricshared/theme-registry',
|
||||||
"version": "0.13.9"
|
version: '0.10.1',
|
||||||
},
|
},
|
||||||
"@uifabricshared/theme-registry": {
|
'@uifabricshared/themed-settings': {
|
||||||
"name": "@uifabricshared/theme-registry",
|
name: '@uifabricshared/themed-settings',
|
||||||
"version": "0.10.1"
|
version: '0.10.2',
|
||||||
},
|
},
|
||||||
"@uifabricshared/themed-settings": {
|
'@uifabricshared/theming-ramp': {
|
||||||
"name": "@uifabricshared/themed-settings",
|
name: '@uifabricshared/theming-ramp',
|
||||||
"version": "0.10.2"
|
version: '0.19.4',
|
||||||
},
|
},
|
||||||
"@uifabricshared/theming-ramp": {
|
'@uifabricshared/theming-react-native': {
|
||||||
"name": "@uifabricshared/theming-ramp",
|
name: '@uifabricshared/theming-react-native',
|
||||||
"version": "0.19.4"
|
version: '0.18.12',
|
||||||
},
|
},
|
||||||
"@uifabricshared/theming-react-native": {
|
'@fluentui-react-native/experimental-activity-indicator': {
|
||||||
"name": "@uifabricshared/theming-react-native",
|
name: '@fluentui-react-native/experimental-activity-indicator',
|
||||||
"version": "0.18.12"
|
version: '0.8.12',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-activity-indicator": {
|
'@fluentui-react-native/experimental-appearance-additions': {
|
||||||
"name": "@fluentui-react-native/experimental-activity-indicator",
|
name: '@fluentui-react-native/experimental-appearance-additions',
|
||||||
"version": "0.8.12"
|
version: '0.5.12',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-appearance-additions": {
|
'@fluentui-react-native/experimental-avatar': {
|
||||||
"name": "@fluentui-react-native/experimental-appearance-additions",
|
name: '@fluentui-react-native/experimental-avatar',
|
||||||
"version": "0.5.12"
|
version: '0.19.11',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-avatar": {
|
'@fluentui-react-native/experimental-button': {
|
||||||
"name": "@fluentui-react-native/experimental-avatar",
|
name: '@fluentui-react-native/experimental-button',
|
||||||
"version": "0.19.11"
|
version: '0.18.22',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-button": {
|
'@fluentui-react-native/experimental-checkbox': {
|
||||||
"name": "@fluentui-react-native/experimental-button",
|
name: '@fluentui-react-native/experimental-checkbox',
|
||||||
"version": "0.18.22"
|
version: '0.15.17',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-checkbox": {
|
'@fluentui-react-native/drawer': {
|
||||||
"name": "@fluentui-react-native/experimental-checkbox",
|
name: '@fluentui-react-native/drawer',
|
||||||
"version": "0.15.17"
|
version: '0.2.13',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/drawer": {
|
'@fluentui-react-native/dropdown': {
|
||||||
"name": "@fluentui-react-native/drawer",
|
name: '@fluentui-react-native/dropdown',
|
||||||
"version": "0.2.13"
|
version: '0.8.29',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/dropdown": {
|
'@fluentui-react-native/experimental-expander': {
|
||||||
"name": "@fluentui-react-native/dropdown",
|
name: '@fluentui-react-native/experimental-expander',
|
||||||
"version": "0.8.29"
|
version: '0.6.13',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-expander": {
|
'@fluentui-react-native/experimental-link': {
|
||||||
"name": "@fluentui-react-native/experimental-expander",
|
name: '@fluentui-react-native/experimental-link',
|
||||||
"version": "0.6.13"
|
version: '0.6.16',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-link": {
|
'@fluentui-react-native/experimental-menu-button': {
|
||||||
"name": "@fluentui-react-native/experimental-link",
|
name: '@fluentui-react-native/experimental-menu-button',
|
||||||
"version": "0.6.16"
|
version: '0.7.31',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-menu-button": {
|
'@fluentui-react-native/experimental-native-date-picker': {
|
||||||
"name": "@fluentui-react-native/experimental-menu-button",
|
name: '@fluentui-react-native/experimental-native-date-picker',
|
||||||
"version": "0.7.31"
|
version: '0.9.1',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-native-date-picker": {
|
'@fluentui-react-native/experimental-native-font-metrics': {
|
||||||
"name": "@fluentui-react-native/experimental-native-date-picker",
|
name: '@fluentui-react-native/experimental-native-font-metrics',
|
||||||
"version": "0.9.1"
|
version: '0.4.1',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-native-font-metrics": {
|
'@fluentui-react-native/popover': {
|
||||||
"name": "@fluentui-react-native/experimental-native-font-metrics",
|
name: '@fluentui-react-native/popover',
|
||||||
"version": "0.4.1"
|
version: '0.2.11',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/popover": {
|
'@fluentui-react-native/experimental-radio-group': {
|
||||||
"name": "@fluentui-react-native/popover",
|
name: '@fluentui-react-native/experimental-radio-group',
|
||||||
"version": "0.2.11"
|
version: '0.11.19',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-radio-group": {
|
'@fluentui-react-native/experimental-shadow': {
|
||||||
"name": "@fluentui-react-native/experimental-radio-group",
|
name: '@fluentui-react-native/experimental-shadow',
|
||||||
"version": "0.11.19"
|
version: '0.4.12',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-shadow": {
|
'@fluentui-react-native/experimental-shimmer': {
|
||||||
"name": "@fluentui-react-native/experimental-shadow",
|
name: '@fluentui-react-native/experimental-shimmer',
|
||||||
"version": "0.4.12"
|
version: '0.11.6',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-shimmer": {
|
'@fluentui-react-native/spinner': {
|
||||||
"name": "@fluentui-react-native/experimental-shimmer",
|
name: '@fluentui-react-native/spinner',
|
||||||
"version": "0.11.6"
|
version: '0.7.15',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/spinner": {
|
'@fluentui-react-native/tablist': {
|
||||||
"name": "@fluentui-react-native/spinner",
|
name: '@fluentui-react-native/tablist',
|
||||||
"version": "0.7.15"
|
version: '0.4.10',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/tablist": {
|
'@fluentui-react-native/experimental-text': {
|
||||||
"name": "@fluentui-react-native/tablist",
|
name: '@fluentui-react-native/experimental-text',
|
||||||
"version": "0.4.10"
|
version: '0.13.14',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-tabs": {
|
'@fluentui-react-native/vibrancy-view': {
|
||||||
"name": "@fluentui-react-native/experimental-tabs",
|
name: '@fluentui-react-native/vibrancy-view',
|
||||||
"version": "0.9.21"
|
version: '0.0.3',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/experimental-text": {
|
'@fluentui-react-native/component-cache': {
|
||||||
"name": "@fluentui-react-native/experimental-text",
|
name: '@fluentui-react-native/component-cache',
|
||||||
"version": "0.13.14"
|
version: '1.5.1',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/vibrancy-view": {
|
'@fluentui-react-native/composition': {
|
||||||
"name": "@fluentui-react-native/vibrancy-view",
|
name: '@fluentui-react-native/composition',
|
||||||
"version": "0.0.3"
|
version: '0.9.2',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/component-cache": {
|
'@fluentui-react-native/eslint-config-rules': {
|
||||||
"name": "@fluentui-react-native/component-cache",
|
name: '@fluentui-react-native/eslint-config-rules',
|
||||||
"version": "1.5.1"
|
version: '0.1.1',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/composition": {
|
'@fluentui-react-native/framework': {
|
||||||
"name": "@fluentui-react-native/composition",
|
name: '@fluentui-react-native/framework',
|
||||||
"version": "0.9.2"
|
version: '0.11.10',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/eslint-config-rules": {
|
'@fluentui-react-native/immutable-merge': {
|
||||||
"name": "@fluentui-react-native/eslint-config-rules",
|
name: '@fluentui-react-native/immutable-merge',
|
||||||
"version": "0.1.1"
|
version: '1.2.1',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/framework": {
|
'@fluentui-react-native/memo-cache': {
|
||||||
"name": "@fluentui-react-native/framework",
|
name: '@fluentui-react-native/memo-cache',
|
||||||
"version": "0.11.10"
|
version: '1.3.1',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/immutable-merge": {
|
'@fluentui-react-native/merge-props': {
|
||||||
"name": "@fluentui-react-native/immutable-merge",
|
name: '@fluentui-react-native/merge-props',
|
||||||
"version": "1.2.1"
|
version: '0.7.1',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/memo-cache": {
|
'@fluentui-react-native/theme': {
|
||||||
"name": "@fluentui-react-native/memo-cache",
|
name: '@fluentui-react-native/theme',
|
||||||
"version": "1.3.1"
|
version: '0.9.4',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/merge-props": {
|
'@fluentui-react-native/themed-stylesheet': {
|
||||||
"name": "@fluentui-react-native/merge-props",
|
name: '@fluentui-react-native/themed-stylesheet',
|
||||||
"version": "0.7.1"
|
version: '1.5.2',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/theme": {
|
'@fluentui-react-native/use-slot': {
|
||||||
"name": "@fluentui-react-native/theme",
|
name: '@fluentui-react-native/use-slot',
|
||||||
"version": "0.9.4"
|
version: '0.4.2',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/themed-stylesheet": {
|
'@fluentui-react-native/use-slots': {
|
||||||
"name": "@fluentui-react-native/themed-stylesheet",
|
name: '@fluentui-react-native/use-slots',
|
||||||
"version": "1.5.2"
|
version: '0.8.2',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/use-slot": {
|
'@fluentui-react-native/use-styling': {
|
||||||
"name": "@fluentui-react-native/use-slot",
|
name: '@fluentui-react-native/use-styling',
|
||||||
"version": "0.4.2"
|
version: '0.11.1',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/use-slots": {
|
'@fluentui-react-native/use-tokens': {
|
||||||
"name": "@fluentui-react-native/use-slots",
|
name: '@fluentui-react-native/use-tokens',
|
||||||
"version": "0.8.2"
|
version: '0.4.2',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/use-styling": {
|
'@fluentui/react-native': {
|
||||||
"name": "@fluentui-react-native/use-styling",
|
name: '@fluentui/react-native',
|
||||||
"version": "0.11.1"
|
version: '0.38.6',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/use-tokens": {
|
'@fluentui-react-native/android-theme': {
|
||||||
"name": "@fluentui-react-native/use-tokens",
|
name: '@fluentui-react-native/android-theme',
|
||||||
"version": "0.4.2"
|
version: '0.18.9',
|
||||||
},
|
},
|
||||||
"@fluentui/react-native": {
|
'@fluentui-react-native/apple-theme': {
|
||||||
"name": "@fluentui/react-native",
|
name: '@fluentui-react-native/apple-theme',
|
||||||
"version": "0.38.6"
|
version: '0.21.13',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/android-theme": {
|
'@fluentui-react-native/default-theme': {
|
||||||
"name": "@fluentui-react-native/android-theme",
|
name: '@fluentui-react-native/default-theme',
|
||||||
"version": "0.18.9"
|
version: '0.19.11',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/apple-theme": {
|
'@fluentui-react-native/theme-tokens': {
|
||||||
"name": "@fluentui-react-native/apple-theme",
|
name: '@fluentui-react-native/theme-tokens',
|
||||||
"version": "0.21.13"
|
version: '0.25.4',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/default-theme": {
|
'@fluentui-react-native/theme-types': {
|
||||||
"name": "@fluentui-react-native/default-theme",
|
name: '@fluentui-react-native/theme-types',
|
||||||
"version": "0.19.11"
|
version: '0.32.3',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/theme-tokens": {
|
'@fluentui-react-native/theming-utils': {
|
||||||
"name": "@fluentui-react-native/theme-tokens",
|
name: '@fluentui-react-native/theming-utils',
|
||||||
"version": "0.25.4"
|
version: '0.24.7',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/theme-types": {
|
'@fluentui-react-native/win32-theme': {
|
||||||
"name": "@fluentui-react-native/theme-types",
|
name: '@fluentui-react-native/win32-theme',
|
||||||
"version": "0.32.3"
|
version: '0.27.10',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/theming-utils": {
|
'@fluentui-react-native/adapters': {
|
||||||
"name": "@fluentui-react-native/theming-utils",
|
name: '@fluentui-react-native/adapters',
|
||||||
"version": "0.24.7"
|
version: '0.11.3',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/win32-theme": {
|
'@fluentui-react-native/interactive-hooks': {
|
||||||
"name": "@fluentui-react-native/win32-theme",
|
name: '@fluentui-react-native/interactive-hooks',
|
||||||
"version": "0.27.10"
|
version: '0.24.12',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/adapters": {
|
'@fluentui-react-native/styling-utils': {
|
||||||
"name": "@fluentui-react-native/adapters",
|
name: '@fluentui-react-native/styling-utils',
|
||||||
"version": "0.11.3"
|
version: '0.5.0',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/interactive-hooks": {
|
'@fluentui-react-native/tokens': {
|
||||||
"name": "@fluentui-react-native/interactive-hooks",
|
name: '@fluentui-react-native/tokens',
|
||||||
"version": "0.24.12"
|
version: '0.21.6',
|
||||||
},
|
},
|
||||||
"@fluentui-react-native/styling-utils": {
|
},
|
||||||
"name": "@fluentui-react-native/styling-utils",
|
|
||||||
"version": "0.5.0"
|
|
||||||
},
|
|
||||||
"@fluentui-react-native/tokens": {
|
|
||||||
"name": "@fluentui-react-native/tokens",
|
|
||||||
"version": "0.21.6"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,3 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
extends: ['@fluentui-react-native/eslint-config-rules'],
|
|
||||||
};
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1 +0,0 @@
|
||||||
module.exports = require('@fluentui-react-native/scripts/babel.config');
|
|
|
@ -1,2 +0,0 @@
|
||||||
const { configureReactNativeJest } = require('@fluentui-react-native/scripts');
|
|
||||||
module.exports = configureReactNativeJest('win32');
|
|
|
@ -1,3 +0,0 @@
|
||||||
const { preset } = require('@fluentui-react-native/scripts');
|
|
||||||
|
|
||||||
preset();
|
|
|
@ -1,71 +0,0 @@
|
||||||
{
|
|
||||||
"name": "@fluentui-react-native/experimental-tabs",
|
|
||||||
"version": "0.10.7",
|
|
||||||
"description": "A cross-platform Experimental Tabs component using the Fluent Design System",
|
|
||||||
"main": "src/index.ts",
|
|
||||||
"module": "src/index.ts",
|
|
||||||
"typings": "lib/index.d.ts",
|
|
||||||
"onPublish": {
|
|
||||||
"main": "lib-commonjs/index.js",
|
|
||||||
"module": "lib/index.js"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "fluentui-scripts build",
|
|
||||||
"clean": "fluentui-scripts clean",
|
|
||||||
"depcheck": "fluentui-scripts depcheck",
|
|
||||||
"just": "fluentui-scripts",
|
|
||||||
"lint": "fluentui-scripts eslint",
|
|
||||||
"test": "fluentui-scripts jest",
|
|
||||||
"update-snapshots": "fluentui-scripts jest -u",
|
|
||||||
"prettier": "fluentui-scripts prettier",
|
|
||||||
"prettier-fix": "fluentui-scripts prettier --fix true"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/microsoft/fluentui-react-native.git",
|
|
||||||
"directory": "packages/experimental/Tabs"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"@fluentui-react-native/adapters": "0.12.0",
|
|
||||||
"@fluentui-react-native/focus-zone": ">=0.16.6 <1.0.0",
|
|
||||||
"@fluentui-react-native/framework": "0.13.5",
|
|
||||||
"@fluentui-react-native/icon": "0.20.7",
|
|
||||||
"@fluentui-react-native/interactive-hooks": ">=0.25.6 <1.0.0",
|
|
||||||
"@fluentui-react-native/text": ">=0.22.6 <1.0.0",
|
|
||||||
"@fluentui-react-native/tokens": ">=0.22.5 <1.0.0",
|
|
||||||
"@fluentui-react-native/use-styling": ">=0.12.0 <1.0.0",
|
|
||||||
"tslib": "^2.3.1"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@fluentui-react-native/eslint-config-rules": "^0.1.1",
|
|
||||||
"@fluentui-react-native/scripts": "^0.1.1",
|
|
||||||
"@fluentui-react-native/test-tools": ">=0.1.1 <1.0.0",
|
|
||||||
"@office-iss/react-native-win32": "^0.72.0",
|
|
||||||
"@react-native/metro-config": "^0.72.0",
|
|
||||||
"react": "18.2.0",
|
|
||||||
"react-native": "^0.72.0"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "18.2.0",
|
|
||||||
"react-native": "^0.72.0"
|
|
||||||
},
|
|
||||||
"author": "",
|
|
||||||
"license": "MIT",
|
|
||||||
"rnx-kit": {
|
|
||||||
"kitType": "library",
|
|
||||||
"alignDeps": {
|
|
||||||
"presets": [
|
|
||||||
"microsoft/react-native"
|
|
||||||
],
|
|
||||||
"requirements": [
|
|
||||||
"react-native@0.72"
|
|
||||||
],
|
|
||||||
"capabilities": [
|
|
||||||
"core",
|
|
||||||
"core-android",
|
|
||||||
"core-ios",
|
|
||||||
"react"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,45 +0,0 @@
|
||||||
import type { Theme, UseStylingOptions } from '@fluentui-react-native/framework';
|
|
||||||
import { buildProps } from '@fluentui-react-native/framework';
|
|
||||||
import { fontStyles } from '@fluentui-react-native/tokens';
|
|
||||||
|
|
||||||
import { tabsName } from './Tabs.types';
|
|
||||||
import type { TabsTokens, TabsSlotProps, TabsProps } from './Tabs.types';
|
|
||||||
import { getRootMargins, getLabelMargins, getStackMargins } from './TabsMargins';
|
|
||||||
import { defaultTabsTokens } from './TabsTokens';
|
|
||||||
|
|
||||||
export const stylingSettings: UseStylingOptions<TabsProps, TabsSlotProps, TabsTokens> = {
|
|
||||||
tokens: [defaultTabsTokens, tabsName],
|
|
||||||
slotProps: {
|
|
||||||
root: buildProps(
|
|
||||||
() => ({
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
minHeight: 32,
|
|
||||||
minWidth: 80,
|
|
||||||
...getRootMargins(),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
),
|
|
||||||
label: buildProps(
|
|
||||||
(tokens: TabsTokens, theme: Theme) => ({
|
|
||||||
style: {
|
|
||||||
color: tokens.color,
|
|
||||||
...getLabelMargins(),
|
|
||||||
...fontStyles.from(tokens, theme),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
['color', ...fontStyles.keys],
|
|
||||||
),
|
|
||||||
stack: buildProps(
|
|
||||||
(tokens: TabsTokens) => ({
|
|
||||||
style: {
|
|
||||||
flexDirection: 'row',
|
|
||||||
backgroundColor: tokens.backgroundColor,
|
|
||||||
...getStackMargins(),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
['backgroundColor'],
|
|
||||||
),
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,99 +0,0 @@
|
||||||
/** @jsxRuntime classic */
|
|
||||||
/** @jsx withSlots */
|
|
||||||
import * as React from 'react';
|
|
||||||
import { Pressable, View } from 'react-native';
|
|
||||||
|
|
||||||
import { FocusZone } from '@fluentui-react-native/focus-zone';
|
|
||||||
import type { UseSlots } from '@fluentui-react-native/framework';
|
|
||||||
import { compose, mergeProps, withSlots } from '@fluentui-react-native/framework';
|
|
||||||
import { TextV1 as Text } from '@fluentui-react-native/text';
|
|
||||||
|
|
||||||
import { stylingSettings } from './Tabs.styling';
|
|
||||||
import type { TabsType, TabsProps, TabsContextData } from './Tabs.types';
|
|
||||||
import { tabsName } from './Tabs.types';
|
|
||||||
import { useTabs } from './useTabs';
|
|
||||||
|
|
||||||
export const TabsContext = React.createContext<TabsContextData>({
|
|
||||||
selectedKey: null,
|
|
||||||
onTabsClick: (/* key: string */) => {
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
getTabId: (/* key:string, index: number*/) => {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
updateSelectedTabsItemRef: (/* ref: React.RefObject<any>*/) => {
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
tabsItemKeys: [],
|
|
||||||
views: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Tabs = compose<TabsType>({
|
|
||||||
displayName: tabsName,
|
|
||||||
...stylingSettings,
|
|
||||||
slots: {
|
|
||||||
root: Pressable,
|
|
||||||
label: Text,
|
|
||||||
container: FocusZone,
|
|
||||||
stack: View,
|
|
||||||
tabPanel: View,
|
|
||||||
},
|
|
||||||
useRender: (userProps: TabsProps, useSlots: UseSlots<TabsType>) => {
|
|
||||||
// configure props and state for tabs based on user props
|
|
||||||
const tabs = useTabs(userProps);
|
|
||||||
|
|
||||||
// Grab the styled slots.
|
|
||||||
const Slots = useSlots(userProps, (layer) => tabs.state[layer] || userProps[layer]);
|
|
||||||
|
|
||||||
// Return the handler to finish render.
|
|
||||||
return (final: TabsProps, ...children: React.ReactNode[]) => {
|
|
||||||
if (!tabs.state) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { label, defaultTabbableElement, isCircularNavigation, ...mergedProps } = mergeProps(tabs.props, final);
|
|
||||||
|
|
||||||
// Populate the tabsItemKeys array.
|
|
||||||
if (children) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
tabs.state.context.tabsItemKeys = React.Children.map(children, (child: React.ReactChild) => {
|
|
||||||
if (React.isValidElement(child)) {
|
|
||||||
// Sets default selected tabItem.
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
if (tabs.state?.context.selectedKey == null && !child.props.disabled) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
tabs.state.context.selectedKey = child.props.itemKey;
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
return child.props.itemKey;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TabsContext.Provider
|
|
||||||
// Passes in the selected key and a hook function to update the newly selected tabsItem and call the client's onTabsClick callback.
|
|
||||||
value={tabs.state.context}
|
|
||||||
>
|
|
||||||
<Slots.root {...mergedProps}>
|
|
||||||
{tabs?.state?.label && <Slots.label key="label">{label}</Slots.label>}
|
|
||||||
<Slots.container defaultTabbableElement={defaultTabbableElement} isCircularNavigation={isCircularNavigation}>
|
|
||||||
<Slots.stack>{children}</Slots.stack>
|
|
||||||
</Slots.container>
|
|
||||||
<Slots.tabPanel>
|
|
||||||
<TabsContext.Consumer>
|
|
||||||
{(context) => !tabs?.state?.headersOnly && <View>{context.views.get(context.selectedKey)}</View>}
|
|
||||||
</TabsContext.Consumer>
|
|
||||||
</Slots.tabPanel>
|
|
||||||
</Slots.root>
|
|
||||||
</TabsContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Tabs;
|
|
|
@ -1,121 +0,0 @@
|
||||||
import type * as React from 'react';
|
|
||||||
import type { View } from 'react-native';
|
|
||||||
|
|
||||||
import type { IViewProps } from '@fluentui-react-native/adapters';
|
|
||||||
import type { FocusZoneProps } from '@fluentui-react-native/focus-zone';
|
|
||||||
import type { TextProps } from '@fluentui-react-native/text';
|
|
||||||
import type { FontTokens, IForegroundColorTokens, IBackgroundColorTokens } from '@fluentui-react-native/tokens';
|
|
||||||
|
|
||||||
export const tabsName = 'Tabs';
|
|
||||||
|
|
||||||
export interface TabsContextData {
|
|
||||||
/**
|
|
||||||
* The currently selected TabsItem's key
|
|
||||||
*/
|
|
||||||
selectedKey: string | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Index of currently selected key
|
|
||||||
*/
|
|
||||||
getTabId?: (key: string, index: number) => string | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the selected tabsItem and calls the client’s onTabsClick callback
|
|
||||||
*/
|
|
||||||
onTabsClick?: (key: string) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Updates the selected tabsItem's ref to set as the default tabbable element
|
|
||||||
*/
|
|
||||||
updateSelectedTabsItemRef?: (ref: React.RefObject<any>) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of tabsItem keys in the group
|
|
||||||
*/
|
|
||||||
tabsItemKeys?: string[];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Map to for a TabItems corresponding view
|
|
||||||
*/
|
|
||||||
views?: Map<string, React.ReactNode[]> | null;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reference to the Focus Container as there is no FocusZone on windows.
|
|
||||||
* GH #964
|
|
||||||
*/
|
|
||||||
focusZoneRef?: React.RefObject<any> | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsTokens extends IForegroundColorTokens, FontTokens, IBackgroundColorTokens {}
|
|
||||||
|
|
||||||
export interface TabsProps extends Pick<FocusZoneProps, 'isCircularNavigation' | 'defaultTabbableElement'>, IViewProps {
|
|
||||||
/**
|
|
||||||
* Descriptive label for the Tabs. This will be displayed as the title of the Tabs to the user
|
|
||||||
*/
|
|
||||||
label?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The key of the TabsItem that will initially be selected
|
|
||||||
*/
|
|
||||||
defaultSelectedKey?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The key of the selected option. If you provide this, you must maintain selection state by observing
|
|
||||||
* onTabsClick events and passing a new value in when changed. This overrides defaultSelectedKey
|
|
||||||
* and makes the Tabs a controlled component. This prop is mutually exclusive to defaultSelectedKey.
|
|
||||||
*/
|
|
||||||
selectedKey?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback for receiving a notification when the choice has been changed
|
|
||||||
*/
|
|
||||||
onTabsClick?: (key: string) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Callback to customize how IDs are generated for each tab header.
|
|
||||||
* Useful if you're rendering content outside and need to connect accessibility-labelledby.
|
|
||||||
*/
|
|
||||||
getTabId?: (key: string, index: number) => string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets whether to only render the header
|
|
||||||
*/
|
|
||||||
headersOnly?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A RefObject to access Tabs.
|
|
||||||
*/
|
|
||||||
componentRef?: React.RefObject<View>;
|
|
||||||
|
|
||||||
testID?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsState {
|
|
||||||
context?: TabsContextData;
|
|
||||||
headersOnly?: boolean;
|
|
||||||
label?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Array of enabled keys in the group
|
|
||||||
* Windows-Specific Prop.
|
|
||||||
*/
|
|
||||||
enabledKeys?: string[];
|
|
||||||
}
|
|
||||||
export interface TabsInfo {
|
|
||||||
props: TabsProps;
|
|
||||||
state: TabsState;
|
|
||||||
}
|
|
||||||
export interface TabsSlotProps {
|
|
||||||
root: React.PropsWithRef<IViewProps>;
|
|
||||||
label: TextProps;
|
|
||||||
container?: FocusZoneProps;
|
|
||||||
stack: IViewProps;
|
|
||||||
tabPanel: IViewProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsType {
|
|
||||||
props: TabsProps;
|
|
||||||
tokens: TabsTokens;
|
|
||||||
slotProps: TabsSlotProps;
|
|
||||||
state: TabsState;
|
|
||||||
}
|
|
|
@ -1,134 +0,0 @@
|
||||||
/** @jsxRuntime classic */
|
|
||||||
/** @jsx withSlots */
|
|
||||||
import * as React from 'react';
|
|
||||||
import { View } from 'react-native';
|
|
||||||
|
|
||||||
import type { UseSlots } from '@fluentui-react-native/framework';
|
|
||||||
import { compose, mergeProps, withSlots } from '@fluentui-react-native/framework';
|
|
||||||
import { TextV1 as Text } from '@fluentui-react-native/text';
|
|
||||||
|
|
||||||
import { stylingSettings } from './Tabs.styling';
|
|
||||||
import type { TabsType, TabsProps, TabsContextData } from './Tabs.types';
|
|
||||||
import { tabsName } from './Tabs.types';
|
|
||||||
import { useTabs } from './useTabs';
|
|
||||||
|
|
||||||
export const TabsContext = React.createContext<TabsContextData>({
|
|
||||||
selectedKey: null,
|
|
||||||
onTabsClick: (/* key: string */) => {
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
getTabId: (/* key:string, index: number*/) => {
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
updateSelectedTabsItemRef: (/* ref: React.RefObject<any>*/) => {
|
|
||||||
return;
|
|
||||||
},
|
|
||||||
tabsItemKeys: [],
|
|
||||||
views: null,
|
|
||||||
focusZoneRef: null,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Tabs = compose<TabsType>({
|
|
||||||
displayName: tabsName,
|
|
||||||
...stylingSettings,
|
|
||||||
slots: {
|
|
||||||
root: View,
|
|
||||||
label: Text,
|
|
||||||
stack: View,
|
|
||||||
tabPanel: View,
|
|
||||||
},
|
|
||||||
useRender: (userProps: TabsProps, useSlots: UseSlots<TabsType>) => {
|
|
||||||
// configure props and state for tabs based on user props
|
|
||||||
const tabs = useTabs(userProps);
|
|
||||||
|
|
||||||
// Grab the styled slots.
|
|
||||||
const Slots = useSlots(userProps, (layer) => tabs.state[layer] || userProps[layer]);
|
|
||||||
|
|
||||||
const onKeyDown = (ev: any) => {
|
|
||||||
if (ev.nativeEvent.key === 'ArrowRight' || ev.nativeEvent.key === 'ArrowLeft') {
|
|
||||||
const length = tabs.state.enabledKeys.length;
|
|
||||||
const currTabItemIndex = tabs.state.enabledKeys.findIndex((x) => x == tabs.state.context.selectedKey);
|
|
||||||
let newCurrTabItemIndex;
|
|
||||||
if (ev.nativeEvent.key === 'ArrowRight') {
|
|
||||||
if (tabs.props.isCircularNavigation || !(currTabItemIndex + 1 == length)) {
|
|
||||||
newCurrTabItemIndex = (currTabItemIndex + 1) % length;
|
|
||||||
tabs.state.context.selectedKey = tabs.state.enabledKeys[newCurrTabItemIndex];
|
|
||||||
tabs.state.context.onTabsClick(tabs.state.context.selectedKey);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (tabs.props.isCircularNavigation || !(currTabItemIndex == 0)) {
|
|
||||||
newCurrTabItemIndex = (currTabItemIndex - 1 + length) % length;
|
|
||||||
tabs.state.context.selectedKey = tabs.state.enabledKeys[newCurrTabItemIndex];
|
|
||||||
tabs.state.context.onTabsClick(tabs.state.context.selectedKey);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const stackProps = {
|
|
||||||
focusable: true,
|
|
||||||
ref: tabs.state.context.focusZoneRef,
|
|
||||||
onKeyDown: onKeyDown,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Return the handler to finish render.
|
|
||||||
return (final: TabsProps, ...children: React.ReactNode[]) => {
|
|
||||||
if (!tabs.state) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { label, ...mergedProps } = mergeProps(tabs.props, final);
|
|
||||||
|
|
||||||
// Populate the tabsItemKeys array
|
|
||||||
if (children) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
tabs.state.context.tabsItemKeys = React.Children.map(children, (child: React.ReactChild) => {
|
|
||||||
if (React.isValidElement(child)) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
return child.props.itemKey;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
tabs.state.enabledKeys = React.Children.map(children, (child: React.ReactChild) => {
|
|
||||||
if (React.isValidElement(child)) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
if (!child.props.disabled) {
|
|
||||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
||||||
// @ts-ignore - TODO, fix typing error
|
|
||||||
return child.props.itemKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/* Sets the default selected TabsItem if a TabsItem is hidden.
|
|
||||||
The default selected Tabsitem is the first enabled TabsItem. */
|
|
||||||
if (!tabs.state.enabledKeys.includes(tabs.state.context.selectedKey)) {
|
|
||||||
tabs.state.context.selectedKey = tabs.state.enabledKeys[0] ?? null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<TabsContext.Provider
|
|
||||||
// Passes in the selected key and a hook function to update the newly selected tabsItem and call the client's onTabsClick callback.
|
|
||||||
value={tabs.state.context}
|
|
||||||
>
|
|
||||||
<Slots.root {...mergedProps}>
|
|
||||||
{tabs?.state?.label && <Slots.label key="label">{label}</Slots.label>}
|
|
||||||
<Slots.stack {...stackProps}>{children}</Slots.stack>
|
|
||||||
<Slots.tabPanel>
|
|
||||||
<TabsContext.Consumer>
|
|
||||||
{(context) => !tabs?.state?.headersOnly && <View>{context.views.get(context.selectedKey)}</View>}
|
|
||||||
</TabsContext.Consumer>
|
|
||||||
</Slots.tabPanel>
|
|
||||||
</Slots.root>
|
|
||||||
</TabsContext.Provider>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default Tabs;
|
|
|
@ -1,73 +0,0 @@
|
||||||
import type { Theme, UseStylingOptions } from '@fluentui-react-native/framework';
|
|
||||||
import { buildProps } from '@fluentui-react-native/framework';
|
|
||||||
import { borderStyles, fontStyles } from '@fluentui-react-native/tokens';
|
|
||||||
|
|
||||||
import { tabsItemName } from './TabsItem.types';
|
|
||||||
import type { TabsItemSlotProps, TabsItemTokens, TabsItemProps } from './TabsItem.types';
|
|
||||||
import { tabsItemStates, defaultTabsItemTokens } from './TabsItemTokens';
|
|
||||||
|
|
||||||
export const stylingSettings: UseStylingOptions<TabsItemProps, TabsItemSlotProps, TabsItemTokens> = {
|
|
||||||
tokens: [defaultTabsItemTokens, tabsItemName],
|
|
||||||
states: tabsItemStates,
|
|
||||||
slotProps: {
|
|
||||||
root: buildProps(
|
|
||||||
(tokens: TabsItemTokens, theme: Theme) => ({
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'column',
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
justifyContent: 'center',
|
|
||||||
...borderStyles.from(tokens, theme),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
[...borderStyles.keys],
|
|
||||||
),
|
|
||||||
content: buildProps(
|
|
||||||
(tokens: TabsItemTokens, theme: Theme) => ({
|
|
||||||
style: {
|
|
||||||
color: tokens.color,
|
|
||||||
...fontStyles.from(tokens, theme),
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
['color', ...fontStyles.keys],
|
|
||||||
),
|
|
||||||
icon: buildProps(
|
|
||||||
(tokens: TabsItemTokens) => ({
|
|
||||||
style: {
|
|
||||||
tintColor: tokens.iconColor,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
['iconColor'],
|
|
||||||
),
|
|
||||||
stack: buildProps(
|
|
||||||
(tokens: TabsItemTokens) => ({
|
|
||||||
style: {
|
|
||||||
display: 'flex',
|
|
||||||
marginHorizontal: 10,
|
|
||||||
alignItems: 'center',
|
|
||||||
flexDirection: 'row',
|
|
||||||
alignSelf: 'flex-start',
|
|
||||||
minHeight: 32,
|
|
||||||
minWidth: 32,
|
|
||||||
justifyContent: 'center',
|
|
||||||
opacity: tokens.tabsItemOpacity,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
['tabsItemOpacity'],
|
|
||||||
),
|
|
||||||
indicator: buildProps(
|
|
||||||
(tokens: TabsItemTokens) => ({
|
|
||||||
style: {
|
|
||||||
minHeight: 2,
|
|
||||||
borderRadius: 2,
|
|
||||||
marginBottom: 2,
|
|
||||||
alignSelf: 'stretch',
|
|
||||||
marginHorizontal: tokens.indicatorMarginHorizontal,
|
|
||||||
backgroundColor: tokens.indicatorColor,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
['indicatorColor', 'indicatorMarginHorizontal'],
|
|
||||||
),
|
|
||||||
},
|
|
||||||
};
|
|
|
@ -1,64 +0,0 @@
|
||||||
/** @jsxRuntime classic */
|
|
||||||
/** @jsx withSlots */
|
|
||||||
import * as React from 'react';
|
|
||||||
import { Pressable, View } from 'react-native';
|
|
||||||
|
|
||||||
import type { UseSlots } from '@fluentui-react-native/framework';
|
|
||||||
import { compose, mergeProps, withSlots } from '@fluentui-react-native/framework';
|
|
||||||
import { Icon, createIconProps } from '@fluentui-react-native/icon';
|
|
||||||
import { TextV1 as Text } from '@fluentui-react-native/text';
|
|
||||||
|
|
||||||
import { TabsContext } from './Tabs';
|
|
||||||
import { stylingSettings } from './TabsItem.styling';
|
|
||||||
import type { TabItemType, TabsItemProps } from './TabsItem.types';
|
|
||||||
import { tabsItemName } from './TabsItem.types';
|
|
||||||
import { useTabsItem } from './useTabsItem';
|
|
||||||
|
|
||||||
export const TabsItem = compose<TabItemType>({
|
|
||||||
displayName: tabsItemName,
|
|
||||||
...stylingSettings,
|
|
||||||
slots: {
|
|
||||||
root: Pressable,
|
|
||||||
stack: View,
|
|
||||||
icon: Icon,
|
|
||||||
indicator: View,
|
|
||||||
content: Text,
|
|
||||||
},
|
|
||||||
useRender: (userProps: TabsItemProps, useSlots: UseSlots<TabItemType>) => {
|
|
||||||
const tabsItem = useTabsItem(userProps);
|
|
||||||
|
|
||||||
const iconProps = createIconProps(userProps.icon);
|
|
||||||
const context = React.useContext(TabsContext);
|
|
||||||
|
|
||||||
// Grab the styled slots.
|
|
||||||
const Slots = useSlots(userProps, (layer) => tabsItem.state[layer] || userProps[layer]);
|
|
||||||
// Return the handler to finish render.
|
|
||||||
return (final: TabsItemProps, ...children: React.ReactNode[]) => {
|
|
||||||
if (!tabsItem.state) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { icon, itemKey, itemCount, headerText, ...mergedProps } = mergeProps(tabsItem.props, final);
|
|
||||||
|
|
||||||
let containerText = headerText;
|
|
||||||
if (itemCount !== undefined) {
|
|
||||||
containerText += ` (${itemCount})`;
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderContent = !!headerText || itemCount !== undefined;
|
|
||||||
context?.views?.set(itemKey, children);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Slots.root {...mergedProps}>
|
|
||||||
<Slots.stack>
|
|
||||||
{icon && <Slots.icon {...iconProps} />}
|
|
||||||
{renderContent && <Slots.content key="content">{containerText}</Slots.content>}
|
|
||||||
</Slots.stack>
|
|
||||||
<Slots.indicator />
|
|
||||||
</Slots.root>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
export default TabsItem;
|
|
|
@ -1,162 +0,0 @@
|
||||||
import type * as React from 'react';
|
|
||||||
import type { ViewStyle, ColorValue } from 'react-native';
|
|
||||||
|
|
||||||
import type { IViewProps } from '@fluentui-react-native/adapters';
|
|
||||||
import type { IconProps, IconSourcesType } from '@fluentui-react-native/icon';
|
|
||||||
import type { IFocusable, PressableState, PressablePropsExtended } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
import type { TextProps } from '@fluentui-react-native/text';
|
|
||||||
import type { FontTokens, IBorderTokens } from '@fluentui-react-native/tokens';
|
|
||||||
|
|
||||||
export const tabsItemName = 'TabsItem';
|
|
||||||
|
|
||||||
export interface TabsItemTokens extends FontTokens, IBorderTokens {
|
|
||||||
/**
|
|
||||||
* The indicator color.
|
|
||||||
*/
|
|
||||||
indicatorColor?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The opacity of the tabs item.
|
|
||||||
*/
|
|
||||||
tabsItemOpacity?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The indicator marginHorizontal value.
|
|
||||||
*/
|
|
||||||
indicatorMarginHorizontal?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The icon color.
|
|
||||||
*/
|
|
||||||
iconColor?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Source URL or name of the icon to show on the TabsItem.
|
|
||||||
*/
|
|
||||||
icon?: IconSourcesType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Text to show on the TabsItem.
|
|
||||||
*/
|
|
||||||
headerText?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The amount of padding between the border and the headerText.
|
|
||||||
*/
|
|
||||||
headerTextPadding?: number | string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The amount of padding between the border and the headerText when the TabsItem has focus.
|
|
||||||
*/
|
|
||||||
headerTextPaddingFocused?: number | string;
|
|
||||||
/**
|
|
||||||
* Background color for the button
|
|
||||||
*/
|
|
||||||
backgroundColor?: ColorValue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Foreground color for the text and/or icon of the button
|
|
||||||
*/
|
|
||||||
color?: ColorValue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The amount of padding between the border and the contents.
|
|
||||||
*/
|
|
||||||
contentPadding?: number | string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The amount of padding between the border and the contents when the Button has focus.
|
|
||||||
*/
|
|
||||||
contentPaddingFocused?: number | string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The icon color when hovering over the Button.
|
|
||||||
*/
|
|
||||||
iconColorHovered?: ColorValue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The icon color when the Button is being pressed.
|
|
||||||
*/
|
|
||||||
iconColorPressed?: ColorValue;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The size of the icon.
|
|
||||||
*/
|
|
||||||
iconSize?: number | string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The weight of the lines used when drawing the icon.
|
|
||||||
*/
|
|
||||||
iconWeight?: number;
|
|
||||||
|
|
||||||
width?: ViewStyle['width'];
|
|
||||||
minHeight?: ViewStyle['minHeight'];
|
|
||||||
minWidth?: ViewStyle['minWidth'];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* States that can be applied to a button
|
|
||||||
*/
|
|
||||||
hovered?: TabsItemTokens;
|
|
||||||
focused?: TabsItemTokens;
|
|
||||||
pressed?: TabsItemTokens;
|
|
||||||
disabled?: TabsItemTokens;
|
|
||||||
selected?: TabsItemTokens;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsItemProps extends Omit<PressablePropsExtended, 'onPress'> {
|
|
||||||
/**
|
|
||||||
* The text string for the option
|
|
||||||
*/
|
|
||||||
headerText?: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The number for the TabsItem count
|
|
||||||
*/
|
|
||||||
itemCount?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A unique key-identifier for each option
|
|
||||||
*/
|
|
||||||
itemKey: string;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether or not the tabs item is selectable
|
|
||||||
*/
|
|
||||||
disabled?: boolean;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Source URL or name of the icon to show on the Button.
|
|
||||||
*/
|
|
||||||
icon?: IconSourcesType;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A RefObject to access the IButton interface. Use this to access the public methods and properties of the component.
|
|
||||||
*/
|
|
||||||
componentRef?: React.RefObject<IFocusable>;
|
|
||||||
|
|
||||||
testID?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsItemState extends PressableState {
|
|
||||||
selected?: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsItemInfo {
|
|
||||||
props: TabsItemProps & React.ComponentPropsWithRef<any>;
|
|
||||||
state: TabsItemState;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabsItemSlotProps {
|
|
||||||
root: React.PropsWithRef<PressablePropsExtended>;
|
|
||||||
icon: IconProps;
|
|
||||||
stack: IViewProps;
|
|
||||||
indicator: IViewProps;
|
|
||||||
content: TextProps;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TabItemType {
|
|
||||||
props: TabsItemProps;
|
|
||||||
tokens: TabsItemTokens;
|
|
||||||
slotProps: TabsItemSlotProps;
|
|
||||||
state: TabsItemState;
|
|
||||||
}
|
|
|
@ -1,32 +0,0 @@
|
||||||
import type { Theme } from '@fluentui-react-native/framework';
|
|
||||||
import type { TokenSettings } from '@fluentui-react-native/use-styling';
|
|
||||||
|
|
||||||
import type { TabsItemTokens } from './TabsItem.types';
|
|
||||||
|
|
||||||
export const tabsItemStates: (keyof TabsItemTokens)[] = ['hovered', 'selected', 'focused', 'disabled'];
|
|
||||||
|
|
||||||
export const defaultTabsItemTokens: TokenSettings<TabsItemTokens, Theme> = (t: Theme) =>
|
|
||||||
({
|
|
||||||
color: t.colors.bodyText,
|
|
||||||
variant: 'bodyStandard',
|
|
||||||
indicatorColor: 'transparent',
|
|
||||||
borderColor: 'transparent',
|
|
||||||
indicatorMarginHorizontal: 10,
|
|
||||||
iconColor: t.colors.buttonIcon,
|
|
||||||
disabled: {
|
|
||||||
color: t.colors.buttonTextDisabled,
|
|
||||||
indicatorColor: 'transparent',
|
|
||||||
fontWeight: 'normal',
|
|
||||||
},
|
|
||||||
hovered: {
|
|
||||||
fontWeight: 'bold',
|
|
||||||
selected: {
|
|
||||||
indicatorMarginHorizontal: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
selected: {
|
|
||||||
icon: t.colors.buttonFocusedIcon,
|
|
||||||
indicatorColor: t.colors.accentButtonBackground,
|
|
||||||
fontWeight: 'bold',
|
|
||||||
},
|
|
||||||
} as TabsItemTokens);
|
|
|
@ -1,44 +0,0 @@
|
||||||
import type { Theme } from '@fluentui-react-native/framework';
|
|
||||||
import type { TokenSettings } from '@fluentui-react-native/use-styling';
|
|
||||||
|
|
||||||
import type { TabsItemTokens } from '.';
|
|
||||||
|
|
||||||
export const tabsItemStates: (keyof TabsItemTokens)[] = ['hovered', 'selected', 'focused', 'disabled', 'pressed'];
|
|
||||||
|
|
||||||
export const defaultTabsItemTokens: TokenSettings<TabsItemTokens, Theme> = (t: Theme) =>
|
|
||||||
({
|
|
||||||
color: t.colors.neutralStrokeAccessible,
|
|
||||||
borderColor: 'transparent',
|
|
||||||
indicatorColor: 'transparent',
|
|
||||||
variant: 'bodyStandard',
|
|
||||||
borderWidth: 2,
|
|
||||||
borderRadius: 4,
|
|
||||||
indicatorMarginHorizontal: 10,
|
|
||||||
disabled: {
|
|
||||||
color: t.colors.neutralForegroundDisabled,
|
|
||||||
borderColor: 'transparent',
|
|
||||||
indicatorColor: 'transparent',
|
|
||||||
},
|
|
||||||
hovered: {
|
|
||||||
color: t.colors.neutralForeground1,
|
|
||||||
indicatorColor: t.colors.neutralStroke1,
|
|
||||||
selected: {
|
|
||||||
indicatorMarginHorizontal: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
pressed: {
|
|
||||||
color: t.colors.neutralForeground2Pressed,
|
|
||||||
indicatorColor: t.colors.brandStroke1,
|
|
||||||
},
|
|
||||||
focused: {
|
|
||||||
color: t.colors.neutralForeground1,
|
|
||||||
borderColor: t.colors.neutralForeground1,
|
|
||||||
icon: t.colors.buttonFocusedIcon,
|
|
||||||
},
|
|
||||||
selected: {
|
|
||||||
color: t.colors.neutralForeground1,
|
|
||||||
icon: t.colors.buttonFocusedIcon,
|
|
||||||
indicatorColor: t.colors.brandStroke1,
|
|
||||||
variant: 'bodySemibold',
|
|
||||||
},
|
|
||||||
} as TabsItemTokens);
|
|
|
@ -1,29 +0,0 @@
|
||||||
import type { Theme } from '@fluentui-react-native/framework';
|
|
||||||
import type { TokenSettings } from '@fluentui-react-native/use-styling';
|
|
||||||
|
|
||||||
import type { TabsItemTokens } from '.';
|
|
||||||
|
|
||||||
export const tabsItemStates: (keyof TabsItemTokens)[] = ['hovered', 'selected', 'disabled'];
|
|
||||||
|
|
||||||
export const defaultTabsItemTokens: TokenSettings<TabsItemTokens, Theme> = (t: Theme) =>
|
|
||||||
({
|
|
||||||
color: t.colors.buttonText,
|
|
||||||
borderColor: 'transparent',
|
|
||||||
indicatorColor: 'transparent',
|
|
||||||
variant: 'heroStandard',
|
|
||||||
fontSize: 20,
|
|
||||||
borderWidth: 2,
|
|
||||||
borderRadius: 4,
|
|
||||||
indicatorMarginHorizontal: 10,
|
|
||||||
tabsItemOpacity: 0.6,
|
|
||||||
disabled: {
|
|
||||||
tabsItemOpacity: 0.2,
|
|
||||||
},
|
|
||||||
hovered: {
|
|
||||||
tabsItemOpacity: 0.8,
|
|
||||||
},
|
|
||||||
selected: {
|
|
||||||
indicatorColor: t.colors.brandStroke1,
|
|
||||||
tabsItemOpacity: 1,
|
|
||||||
},
|
|
||||||
} as TabsItemTokens);
|
|
|
@ -1,15 +0,0 @@
|
||||||
export const getRootMargins = () => {
|
|
||||||
return {
|
|
||||||
marginLeft: 4,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getLabelMargins = () => {
|
|
||||||
return {};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getStackMargins = () => {
|
|
||||||
return {
|
|
||||||
marginTop: 6,
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,11 +0,0 @@
|
||||||
export const getRootMargins = () => {
|
|
||||||
return {};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getLabelMargins = () => {
|
|
||||||
return {};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getStackMargins = () => {
|
|
||||||
return {};
|
|
||||||
};
|
|
|
@ -1,15 +0,0 @@
|
||||||
export const getRootMargins = () => {
|
|
||||||
return {};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getLabelMargins = () => {
|
|
||||||
return {
|
|
||||||
marginStart: 10,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getStackMargins = () => {
|
|
||||||
return {
|
|
||||||
marginTop: 6,
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,15 +0,0 @@
|
||||||
import type { Theme } from '@fluentui-react-native/framework';
|
|
||||||
import type { TokenSettings } from '@fluentui-react-native/use-styling';
|
|
||||||
|
|
||||||
import type { TabsTokens } from '.';
|
|
||||||
|
|
||||||
export const defaultTabsTokens: TokenSettings<TabsTokens, Theme> = (t: Theme) =>
|
|
||||||
({
|
|
||||||
color: t.colors.menuItemText,
|
|
||||||
variant: 'bodySemibold',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
fontSize: 14,
|
|
||||||
backgroundColor: t.colors.transparent,
|
|
||||||
borderColor: t.colors.buttonBorder,
|
|
||||||
iconColor: t.colors.iconColor,
|
|
||||||
} as TabsTokens);
|
|
|
@ -1,13 +0,0 @@
|
||||||
import type { Theme } from '@fluentui-react-native/framework';
|
|
||||||
import type { TokenSettings } from '@fluentui-react-native/use-styling';
|
|
||||||
|
|
||||||
import type { TabsTokens } from '.';
|
|
||||||
|
|
||||||
export const defaultTabsTokens: TokenSettings<TabsTokens, Theme> = (t: Theme) =>
|
|
||||||
({
|
|
||||||
backgroundColor: t.colors.transparent,
|
|
||||||
color: t.colors.buttonText,
|
|
||||||
variant: 'subheaderSemibold',
|
|
||||||
borderColor: t.colors.buttonBorder,
|
|
||||||
iconColor: t.colors.iconColor,
|
|
||||||
} as TabsTokens);
|
|
|
@ -1,15 +0,0 @@
|
||||||
import type { Theme } from '@fluentui-react-native/framework';
|
|
||||||
import type { TokenSettings } from '@fluentui-react-native/use-styling';
|
|
||||||
|
|
||||||
import type { TabsTokens } from '.';
|
|
||||||
|
|
||||||
export const defaultTabsTokens: TokenSettings<TabsTokens, Theme> = (t: Theme) =>
|
|
||||||
({
|
|
||||||
color: t.colors.menuItemText,
|
|
||||||
variant: 'bodySemibold',
|
|
||||||
fontWeight: 'bold',
|
|
||||||
fontSize: 14,
|
|
||||||
backgroundColor: t.colors.transparent,
|
|
||||||
borderColor: t.colors.buttonBorder,
|
|
||||||
iconColor: t.colors.iconColor,
|
|
||||||
} as TabsTokens);
|
|
|
@ -1,83 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import * as renderer from 'react-test-renderer';
|
|
||||||
|
|
||||||
import { Tabs, TabsItem } from '..';
|
|
||||||
|
|
||||||
it('Tabs default props', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs>
|
|
||||||
<TabsItem itemKey="1" />
|
|
||||||
<TabsItem itemKey="2" />
|
|
||||||
<TabsItem itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Tabs disabled', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs>
|
|
||||||
<TabsItem itemKey="1" disabled={true} />
|
|
||||||
<TabsItem itemKey="2" disabled={true} />
|
|
||||||
<TabsItem itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Tabs header text and count', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs>
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={1} itemKey="1" />
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={0} itemKey="2" />
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={100} itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Tabs headers only', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs headersOnly={true}>
|
|
||||||
<TabsItem itemKey="1" />
|
|
||||||
<TabsItem itemKey="2" />
|
|
||||||
<TabsItem itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Tabs FocusZone props', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs defaultSelectedKey="2" isCircularNavigation={false}>
|
|
||||||
<TabsItem itemKey="1" />
|
|
||||||
<TabsItem itemKey="2" />
|
|
||||||
<TabsItem itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('Tabs props', () => {
|
|
||||||
const tree = renderer
|
|
||||||
.create(
|
|
||||||
<Tabs label="Tabs" defaultSelectedKey="2" isCircularNavigation={false} headersOnly={true}>
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={1} itemKey="1" disabled={true} />
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={0} itemKey="2" />
|
|
||||||
<TabsItem headerText="TabsItem" itemCount={100} itemKey="3" />
|
|
||||||
</Tabs>,
|
|
||||||
)
|
|
||||||
.toJSON();
|
|
||||||
expect(tree).toMatchSnapshot();
|
|
||||||
});
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,6 +0,0 @@
|
||||||
export { tabsItemName } from './TabsItem.types';
|
|
||||||
export type { TabItemType, TabsItemInfo, TabsItemProps, TabsItemSlotProps, TabsItemState, TabsItemTokens } from './TabsItem.types';
|
|
||||||
export { TabsItem } from './TabsItem';
|
|
||||||
export { tabsName } from './Tabs.types';
|
|
||||||
export type { TabsContextData, TabsInfo, TabsProps, TabsSlotProps, TabsState, TabsTokens, TabsType } from './Tabs.types';
|
|
||||||
export { Tabs, TabsContext } from './Tabs';
|
|
|
@ -1,69 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
import type { View } from 'react-native';
|
|
||||||
|
|
||||||
import { useSelectedKey } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
|
|
||||||
import type { TabsProps, TabsState, TabsInfo } from './Tabs.types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Re-usable hook for Tabs.
|
|
||||||
* This hook configures tabs props and state for Tabs.
|
|
||||||
*
|
|
||||||
* @param props user props sent to Tabs
|
|
||||||
* @returns configured props and state for Tabs
|
|
||||||
*/
|
|
||||||
export const useTabs = (props: TabsProps): TabsInfo => {
|
|
||||||
const defaultComponentRef = React.useRef(null);
|
|
||||||
const { accessible, componentRef = defaultComponentRef, selectedKey, getTabId, onTabsClick, defaultSelectedKey } = props;
|
|
||||||
|
|
||||||
const data = useSelectedKey(selectedKey || defaultSelectedKey || null, onTabsClick);
|
|
||||||
|
|
||||||
// selectedTabsItemRef should be set to default tabbale element.
|
|
||||||
const [selectedTabsItemRef, setSelectedTabsItemRef] = React.useState(React.useRef<View>(null));
|
|
||||||
|
|
||||||
const onSelectTabsItemRef = React.useCallback(
|
|
||||||
(ref: React.RefObject<View>) => {
|
|
||||||
setSelectedTabsItemRef(ref);
|
|
||||||
},
|
|
||||||
[setSelectedTabsItemRef],
|
|
||||||
);
|
|
||||||
|
|
||||||
const findTabId = React.useCallback(
|
|
||||||
(key: string, index: number) => {
|
|
||||||
if (getTabId) {
|
|
||||||
return getTabId(key, index);
|
|
||||||
}
|
|
||||||
return `${key}-Tab${index}`;
|
|
||||||
},
|
|
||||||
[getTabId],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Stores views to be displayed.
|
|
||||||
const map = new Map<string, React.ReactNode[]>();
|
|
||||||
|
|
||||||
const state: TabsState = {
|
|
||||||
context: {
|
|
||||||
selectedKey: selectedKey ?? data.selectedKey,
|
|
||||||
onTabsClick: data.onKeySelect,
|
|
||||||
getTabId: findTabId,
|
|
||||||
updateSelectedTabsItemRef: onSelectTabsItemRef,
|
|
||||||
views: map,
|
|
||||||
},
|
|
||||||
headersOnly: props.headersOnly ?? false,
|
|
||||||
label: !!props.label,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
...props,
|
|
||||||
accessible: accessible ?? true,
|
|
||||||
accessibilityRole: 'tablist',
|
|
||||||
componentRef: componentRef,
|
|
||||||
defaultTabbableElement: selectedTabsItemRef,
|
|
||||||
isCircularNavigation: props.isCircularNavigation ?? false,
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
...state,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,68 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import { useSelectedKey } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
|
|
||||||
import type { TabsProps, TabsState, TabsInfo } from './Tabs.types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Re-usable hook for Tabs.
|
|
||||||
* This hook configures tabs props and state for Tabs.
|
|
||||||
*
|
|
||||||
* @param props user props sent to Tabs
|
|
||||||
* @returns configured props and state for Tabs
|
|
||||||
*/
|
|
||||||
export const useTabs = (props: TabsProps): TabsInfo => {
|
|
||||||
const defaultComponentRef = React.useRef(null);
|
|
||||||
const focusZoneRef = React.useRef(null);
|
|
||||||
const {
|
|
||||||
accessible,
|
|
||||||
componentRef = defaultComponentRef,
|
|
||||||
selectedKey,
|
|
||||||
getTabId,
|
|
||||||
onTabsClick,
|
|
||||||
defaultSelectedKey,
|
|
||||||
isCircularNavigation,
|
|
||||||
headersOnly,
|
|
||||||
label,
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
const data = useSelectedKey(selectedKey || defaultSelectedKey || null, onTabsClick);
|
|
||||||
|
|
||||||
const findTabId = React.useCallback(
|
|
||||||
(key: string, index: number) => {
|
|
||||||
if (getTabId) {
|
|
||||||
return getTabId(key, index);
|
|
||||||
}
|
|
||||||
return `${key}-Tab${index}`;
|
|
||||||
},
|
|
||||||
[getTabId],
|
|
||||||
);
|
|
||||||
|
|
||||||
// Stores views to be displayed.
|
|
||||||
const map = new Map<string, React.ReactNode[]>();
|
|
||||||
|
|
||||||
const state: TabsState = {
|
|
||||||
context: {
|
|
||||||
selectedKey: selectedKey ?? data.selectedKey,
|
|
||||||
onTabsClick: data.onKeySelect,
|
|
||||||
getTabId: findTabId,
|
|
||||||
views: map,
|
|
||||||
focusZoneRef: focusZoneRef,
|
|
||||||
},
|
|
||||||
headersOnly: headersOnly ?? false,
|
|
||||||
label: !!label,
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
...props,
|
|
||||||
accessible: accessible ?? true,
|
|
||||||
accessibilityRole: 'tablist',
|
|
||||||
componentRef: componentRef,
|
|
||||||
isCircularNavigation: isCircularNavigation ?? false,
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
...state,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,93 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import type { IFocusable } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
import { usePressableState, useKeyProps, useOnPressWithFocus, useViewCommandFocus } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
|
|
||||||
import { TabsContext } from './Tabs';
|
|
||||||
import type { TabsItemProps, TabsItemInfo } from './TabsItem.types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Re-usable hook for TabsItem.
|
|
||||||
* This hook configures tabs item props and state for TabsItem.
|
|
||||||
*
|
|
||||||
* @param props user props sent to TabsItem
|
|
||||||
* @returns configured props and state for TabsItem
|
|
||||||
*/
|
|
||||||
export const useTabsItem = (props: TabsItemProps): TabsItemInfo => {
|
|
||||||
const defaultComponentRef = React.useRef<IFocusable>(null);
|
|
||||||
const {
|
|
||||||
accessibilityLabel,
|
|
||||||
accessible,
|
|
||||||
headerText,
|
|
||||||
componentRef = defaultComponentRef,
|
|
||||||
itemKey,
|
|
||||||
disabled,
|
|
||||||
itemCount,
|
|
||||||
icon,
|
|
||||||
...rest
|
|
||||||
} = props;
|
|
||||||
// Grabs the context information from Tabs (currently selected TabsItem and client's onTabsClick callback).
|
|
||||||
const info = React.useContext(TabsContext);
|
|
||||||
|
|
||||||
const changeSelection = React.useCallback(() => {
|
|
||||||
if (itemKey != info.selectedKey) {
|
|
||||||
info.onTabsClick && info.onTabsClick(itemKey);
|
|
||||||
info.getTabId && info.getTabId(itemKey, info.tabsItemKeys.findIndex((x) => x == itemKey) + 1);
|
|
||||||
info.updateSelectedTabsItemRef && componentRef && info.updateSelectedTabsItemRef(componentRef);
|
|
||||||
}
|
|
||||||
}, [componentRef, info, itemKey]);
|
|
||||||
|
|
||||||
const changeSelectionWithFocus = useOnPressWithFocus(componentRef, changeSelection);
|
|
||||||
|
|
||||||
const pressable = usePressableState({
|
|
||||||
...rest,
|
|
||||||
onPress: changeSelectionWithFocus,
|
|
||||||
onFocus: changeSelection,
|
|
||||||
});
|
|
||||||
|
|
||||||
const onKeyUpProps = useKeyProps(changeSelection, ' ', 'Enter');
|
|
||||||
|
|
||||||
// Used when creating accessibility properties in mergeSettings below.
|
|
||||||
const onAccessibilityAction = React.useCallback(
|
|
||||||
(event: { nativeEvent: { actionName: any } }) => {
|
|
||||||
switch (event.nativeEvent.actionName) {
|
|
||||||
case 'Select':
|
|
||||||
changeSelection();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[changeSelection],
|
|
||||||
);
|
|
||||||
|
|
||||||
/* We use the componentRef of the currently selected tabsItem to maintain the default tabbable
|
|
||||||
element in Tabs. Since the componentRef isn't generated until after initial render,
|
|
||||||
we must update it once here. */
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (itemKey == info.selectedKey) {
|
|
||||||
info.updateSelectedTabsItemRef && componentRef && info.updateSelectedTabsItemRef(componentRef);
|
|
||||||
}
|
|
||||||
}, [componentRef, info, itemKey]);
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
...pressable.props,
|
|
||||||
accessible: accessible ?? true,
|
|
||||||
accessibilityRole: 'tab',
|
|
||||||
accessibilityLabel: accessibilityLabel || headerText,
|
|
||||||
focusable: !disabled ?? true,
|
|
||||||
headerText: headerText ?? '',
|
|
||||||
accessibilityState: { disabled: disabled, selected: info.selectedKey === itemKey },
|
|
||||||
accessibilityActions: [{ name: 'Select' }],
|
|
||||||
onAccessibilityAction: onAccessibilityAction,
|
|
||||||
itemCount: itemCount,
|
|
||||||
ref: useViewCommandFocus(componentRef),
|
|
||||||
itemKey: itemKey,
|
|
||||||
icon: icon,
|
|
||||||
...onKeyUpProps,
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
...pressable.state,
|
|
||||||
selected: itemKey === info.selectedKey,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,79 +0,0 @@
|
||||||
import * as React from 'react';
|
|
||||||
|
|
||||||
import { usePressableState, useViewCommandFocus } from '@fluentui-react-native/interactive-hooks';
|
|
||||||
|
|
||||||
import { TabsContext } from './Tabs';
|
|
||||||
import type { TabsItemProps, TabsItemInfo, TabsItemState } from './TabsItem.types';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Re-usable hook for TabsItem.
|
|
||||||
* This hook configures tabs item props and state for TabsItem.
|
|
||||||
*
|
|
||||||
* @param props user props sent to TabsItem
|
|
||||||
* @returns configured props and state for TabsItem
|
|
||||||
*/
|
|
||||||
export const useTabsItem = (props: TabsItemProps): TabsItemInfo => {
|
|
||||||
const defaultComponentRef = React.useRef(null);
|
|
||||||
const { accessibilityLabel, accessible, headerText, componentRef = defaultComponentRef, itemKey, disabled, itemCount, ...rest } = props;
|
|
||||||
// Grabs the context information from Tabs (currently selected TabsItem and client's onTabsClick callback).
|
|
||||||
const info = React.useContext(TabsContext);
|
|
||||||
|
|
||||||
const changeSelection = React.useCallback(() => {
|
|
||||||
info.focusZoneRef?.current?.focus(); // GH #964, FocusZone not implemented on windows.
|
|
||||||
info.onTabsClick && info.onTabsClick(itemKey);
|
|
||||||
info.getTabId && info.getTabId(itemKey, info.tabsItemKeys.findIndex((x) => x == itemKey) + 1);
|
|
||||||
info.updateSelectedTabsItemRef && componentRef && info.updateSelectedTabsItemRef(componentRef);
|
|
||||||
}, [componentRef, info, itemKey]);
|
|
||||||
|
|
||||||
const pressable = usePressableState({
|
|
||||||
...rest,
|
|
||||||
onPress: changeSelection,
|
|
||||||
});
|
|
||||||
|
|
||||||
const state: TabsItemState = {
|
|
||||||
...pressable.state,
|
|
||||||
selected: info.selectedKey === itemKey,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Used when creating accessibility properties in mergeSettings below.
|
|
||||||
const onAccessibilityAction = React.useCallback(
|
|
||||||
(event: { nativeEvent: { actionName: any } }) => {
|
|
||||||
switch (event.nativeEvent.actionName) {
|
|
||||||
case 'Select':
|
|
||||||
changeSelection();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[info, itemKey],
|
|
||||||
);
|
|
||||||
|
|
||||||
/* We use the componentRef of the currently selected tabsItem to maintain the default tabbable
|
|
||||||
element in Tabs. Since the componentRef isn't generated until after initial render,
|
|
||||||
we must update it once here. */
|
|
||||||
React.useEffect(() => {
|
|
||||||
if (itemKey == info.selectedKey) {
|
|
||||||
info.updateSelectedTabsItemRef && componentRef && info.updateSelectedTabsItemRef(componentRef);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
...rest,
|
|
||||||
...pressable.props,
|
|
||||||
accessible: accessible ?? true,
|
|
||||||
ref: useViewCommandFocus(componentRef),
|
|
||||||
accessibilityRole: 'tab',
|
|
||||||
accessibilityLabel: accessibilityLabel || headerText,
|
|
||||||
focusable: false,
|
|
||||||
headerText: headerText ?? '',
|
|
||||||
accessibilityState: { disabled: disabled, selected: info.selectedKey === itemKey },
|
|
||||||
accessibilityActions: [{ name: 'Select' }],
|
|
||||||
onAccessibilityAction: onAccessibilityAction,
|
|
||||||
itemCount: itemCount,
|
|
||||||
itemKey: itemKey,
|
|
||||||
},
|
|
||||||
state: {
|
|
||||||
...state,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"extends": "@fluentui-react-native/scripts/tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"importHelpers": true,
|
|
||||||
"outDir": "lib",
|
|
||||||
"types": ["node", "jest"]
|
|
||||||
},
|
|
||||||
"include": ["src"]
|
|
||||||
}
|
|
|
@ -42,7 +42,7 @@
|
||||||
"@fluentui-react-native/pressable": "0.11.6",
|
"@fluentui-react-native/pressable": "0.11.6",
|
||||||
"@fluentui-react-native/radio-group": "0.20.8",
|
"@fluentui-react-native/radio-group": "0.20.8",
|
||||||
"@fluentui-react-native/separator": "0.17.6",
|
"@fluentui-react-native/separator": "0.17.6",
|
||||||
"@fluentui-react-native/tabs": "0.14.7",
|
"@fluentui-react-native/tablist": "0.5.13",
|
||||||
"@fluentui-react-native/text": "0.22.6"
|
"@fluentui-react-native/text": "0.22.6"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|
|
@ -322,21 +322,18 @@ export type {
|
||||||
MenuButtonType,
|
MenuButtonType,
|
||||||
} from '@fluentui-react-native/menu-button';
|
} from '@fluentui-react-native/menu-button';
|
||||||
|
|
||||||
export { Tabs, TabsContext, TabsItem, tabsItemName, tabsName } from '@fluentui-react-native/tabs';
|
export { TabList, tabListName, Tab, tabName } from '@fluentui-react-native/tablist';
|
||||||
export type {
|
export type {
|
||||||
TabsContextData,
|
TabListInfo,
|
||||||
TabsInfo,
|
TabListProps,
|
||||||
TabsItemInfo,
|
TabListSlotProps,
|
||||||
TabsItemProps,
|
TabListState,
|
||||||
TabsItemRenderData,
|
TabListTokens,
|
||||||
TabsItemSlotProps,
|
TabListType,
|
||||||
TabsItemState,
|
TabInfo,
|
||||||
TabsItemTokens,
|
TabProps,
|
||||||
TabsItemType,
|
TabSlotProps,
|
||||||
TabsProps,
|
TabState,
|
||||||
TabsRenderData,
|
TabTokens,
|
||||||
TabsSlotProps,
|
TabType,
|
||||||
TabsState,
|
} from '@fluentui-react-native/tablist';
|
||||||
TabsTokens,
|
|
||||||
TabsType,
|
|
||||||
} from '@fluentui-react-native/tabs';
|
|
||||||
|
|
57
yarn.lock
57
yarn.lock
|
@ -2642,7 +2642,6 @@ __metadata:
|
||||||
"@fluentui-react-native/experimental-shadow": "*"
|
"@fluentui-react-native/experimental-shadow": "*"
|
||||||
"@fluentui-react-native/experimental-shimmer": "*"
|
"@fluentui-react-native/experimental-shimmer": "*"
|
||||||
"@fluentui-react-native/experimental-stack": "*"
|
"@fluentui-react-native/experimental-stack": "*"
|
||||||
"@fluentui-react-native/experimental-tabs": "*"
|
|
||||||
"@fluentui-react-native/experimental-text": "*"
|
"@fluentui-react-native/experimental-text": "*"
|
||||||
"@fluentui-react-native/focus-trap-zone": "*"
|
"@fluentui-react-native/focus-trap-zone": "*"
|
||||||
"@fluentui-react-native/focus-zone": "*"
|
"@fluentui-react-native/focus-zone": "*"
|
||||||
|
@ -2666,7 +2665,6 @@ __metadata:
|
||||||
"@fluentui-react-native/stack": "*"
|
"@fluentui-react-native/stack": "*"
|
||||||
"@fluentui-react-native/styling-utils": "*"
|
"@fluentui-react-native/styling-utils": "*"
|
||||||
"@fluentui-react-native/switch": "*"
|
"@fluentui-react-native/switch": "*"
|
||||||
"@fluentui-react-native/tabs": "*"
|
|
||||||
"@fluentui-react-native/tester": "*"
|
"@fluentui-react-native/tester": "*"
|
||||||
"@fluentui-react-native/tester-win32": "*"
|
"@fluentui-react-native/tester-win32": "*"
|
||||||
"@fluentui-react-native/text": "*"
|
"@fluentui-react-native/text": "*"
|
||||||
|
@ -3084,32 +3082,6 @@ __metadata:
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@fluentui-react-native/experimental-tabs@*, @fluentui-react-native/experimental-tabs@0.10.7, @fluentui-react-native/experimental-tabs@workspace:packages/experimental/Tabs":
|
|
||||||
version: 0.0.0-use.local
|
|
||||||
resolution: "@fluentui-react-native/experimental-tabs@workspace:packages/experimental/Tabs"
|
|
||||||
dependencies:
|
|
||||||
"@fluentui-react-native/adapters": 0.12.0
|
|
||||||
"@fluentui-react-native/eslint-config-rules": ^0.1.1
|
|
||||||
"@fluentui-react-native/focus-zone": ">=0.16.6 <1.0.0"
|
|
||||||
"@fluentui-react-native/framework": 0.13.5
|
|
||||||
"@fluentui-react-native/icon": 0.20.7
|
|
||||||
"@fluentui-react-native/interactive-hooks": ">=0.25.6 <1.0.0"
|
|
||||||
"@fluentui-react-native/scripts": ^0.1.1
|
|
||||||
"@fluentui-react-native/test-tools": ">=0.1.1 <1.0.0"
|
|
||||||
"@fluentui-react-native/text": ">=0.22.6 <1.0.0"
|
|
||||||
"@fluentui-react-native/tokens": ">=0.22.5 <1.0.0"
|
|
||||||
"@fluentui-react-native/use-styling": ">=0.12.0 <1.0.0"
|
|
||||||
"@office-iss/react-native-win32": ^0.72.0
|
|
||||||
"@react-native/metro-config": ^0.72.0
|
|
||||||
react: 18.2.0
|
|
||||||
react-native: ^0.72.0
|
|
||||||
tslib: ^2.3.1
|
|
||||||
peerDependencies:
|
|
||||||
react: 18.2.0
|
|
||||||
react-native: ^0.72.0
|
|
||||||
languageName: unknown
|
|
||||||
linkType: soft
|
|
||||||
|
|
||||||
"@fluentui-react-native/experimental-text@*, @fluentui-react-native/experimental-text@>=0.14.6 <1.0.0, @fluentui-react-native/experimental-text@workspace:packages/experimental/Text":
|
"@fluentui-react-native/experimental-text@*, @fluentui-react-native/experimental-text@>=0.14.6 <1.0.0, @fluentui-react-native/experimental-text@workspace:packages/experimental/Text":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@fluentui-react-native/experimental-text@workspace:packages/experimental/Text"
|
resolution: "@fluentui-react-native/experimental-text@workspace:packages/experimental/Text"
|
||||||
|
@ -3749,32 +3721,6 @@ __metadata:
|
||||||
languageName: unknown
|
languageName: unknown
|
||||||
linkType: soft
|
linkType: soft
|
||||||
|
|
||||||
"@fluentui-react-native/tabs@*, @fluentui-react-native/tabs@0.14.7, @fluentui-react-native/tabs@workspace:packages/components/Tabs":
|
|
||||||
version: 0.0.0-use.local
|
|
||||||
resolution: "@fluentui-react-native/tabs@workspace:packages/components/Tabs"
|
|
||||||
dependencies:
|
|
||||||
"@fluentui-react-native/adapters": ">=0.12.0 <1.0.0"
|
|
||||||
"@fluentui-react-native/eslint-config-rules": ^0.1.1
|
|
||||||
"@fluentui-react-native/focus-zone": ">=0.16.6 <1.0.0"
|
|
||||||
"@fluentui-react-native/icon": 0.20.7
|
|
||||||
"@fluentui-react-native/interactive-hooks": ">=0.25.6 <1.0.0"
|
|
||||||
"@fluentui-react-native/scripts": ^0.1.1
|
|
||||||
"@fluentui-react-native/test-tools": ">=0.1.1 <1.0.0"
|
|
||||||
"@fluentui-react-native/text": ">=0.22.6 <1.0.0"
|
|
||||||
"@fluentui-react-native/tokens": ">=0.22.5 <1.0.0"
|
|
||||||
"@office-iss/react-native-win32": ^0.72.0
|
|
||||||
"@react-native/metro-config": ^0.72.0
|
|
||||||
"@uifabricshared/foundation-composable": ">=0.12.3 <1.0.0"
|
|
||||||
"@uifabricshared/foundation-compose": ^1.14.19
|
|
||||||
"@uifabricshared/foundation-settings": ">=0.14.0 <1.0.0"
|
|
||||||
react: 18.2.0
|
|
||||||
react-native: ^0.72.0
|
|
||||||
peerDependencies:
|
|
||||||
react: 18.2.0
|
|
||||||
react-native: ^0.72.0
|
|
||||||
languageName: unknown
|
|
||||||
linkType: soft
|
|
||||||
|
|
||||||
"@fluentui-react-native/test-tools@>=0.1.1 <1.0.0, @fluentui-react-native/test-tools@workspace:packages/utils/test-tools":
|
"@fluentui-react-native/test-tools@>=0.1.1 <1.0.0, @fluentui-react-native/test-tools@workspace:packages/utils/test-tools":
|
||||||
version: 0.0.0-use.local
|
version: 0.0.0-use.local
|
||||||
resolution: "@fluentui-react-native/test-tools@workspace:packages/utils/test-tools"
|
resolution: "@fluentui-react-native/test-tools@workspace:packages/utils/test-tools"
|
||||||
|
@ -3844,7 +3790,6 @@ __metadata:
|
||||||
"@fluentui-react-native/experimental-native-date-picker": ">=0.10.0 <1.0.0"
|
"@fluentui-react-native/experimental-native-date-picker": ">=0.10.0 <1.0.0"
|
||||||
"@fluentui-react-native/experimental-shadow": 0.5.6
|
"@fluentui-react-native/experimental-shadow": 0.5.6
|
||||||
"@fluentui-react-native/experimental-shimmer": 0.12.8
|
"@fluentui-react-native/experimental-shimmer": 0.12.8
|
||||||
"@fluentui-react-native/experimental-tabs": 0.10.7
|
|
||||||
"@fluentui-react-native/experimental-text": ">=0.14.6 <1.0.0"
|
"@fluentui-react-native/experimental-text": ">=0.14.6 <1.0.0"
|
||||||
"@fluentui-react-native/focus-zone": ^0.16.6
|
"@fluentui-react-native/focus-zone": ^0.16.6
|
||||||
"@fluentui-react-native/framework": ">=0.13.5 <1.0.0"
|
"@fluentui-react-native/framework": ">=0.13.5 <1.0.0"
|
||||||
|
@ -4187,7 +4132,7 @@ __metadata:
|
||||||
"@fluentui-react-native/radio-group": 0.20.8
|
"@fluentui-react-native/radio-group": 0.20.8
|
||||||
"@fluentui-react-native/scripts": ^0.1.1
|
"@fluentui-react-native/scripts": ^0.1.1
|
||||||
"@fluentui-react-native/separator": 0.17.6
|
"@fluentui-react-native/separator": 0.17.6
|
||||||
"@fluentui-react-native/tabs": 0.14.7
|
"@fluentui-react-native/tablist": 0.5.13
|
||||||
"@fluentui-react-native/text": 0.22.6
|
"@fluentui-react-native/text": 0.22.6
|
||||||
"@react-native/metro-config": ^0.72.0
|
"@react-native/metro-config": ^0.72.0
|
||||||
react: 18.2.0
|
react: 18.2.0
|
||||||
|
|
Загрузка…
Ссылка в новой задаче