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:
Lawrence Win 2024-01-16 16:56:21 -08:00 коммит произвёл GitHub
Родитель 5e85050d5b
Коммит 4eb131d61e
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
83 изменённых файлов: 771 добавлений и 27697 удалений

Просмотреть файл

@ -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 './Switch/consts';
export * from './TabList/consts';
export * from './TabsLegacy/consts';
export * from './TabsV1/consts';
export * from './TextLegacy/consts';
export * from './TextV1/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-shadow": "0.5.6",
"@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/framework": ">=0.13.5 <1.0.0",
"@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 { SwitchTest } from './TestComponents/Switch';
import { TabListTest } from './TestComponents/TabList/TabListTest';
import { TabsLegacyTest } from './TestComponents/TabsLegacy';
import { TabsV1Test } from './TestComponents/TabsV1';
import { TextLegacyTest } from './TestComponents/TextLegacy';
import { TextV1Test } from './TestComponents/TextV1';
import { ThemeTest } from './TestComponents/Theme';
@ -302,18 +300,6 @@ export const tests: TestDescription[] = [
testPageButton: Constants.HOMEPAGE_TABLIST_BUTTON,
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',
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,
} as TTokens);
export const Foo = compose<TabItemType>({
export const Foo = compose<FooType>({
displayName: fooName,
tokens: tokens,
slots: {
@ -50,7 +50,7 @@ export const Foo = compose<TabItemType>({
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

Просмотреть файл

@ -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 clients 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-shimmer": "*",
"@fluentui-react-native/experimental-stack": "*",
"@fluentui-react-native/experimental-tabs": "*",
"@fluentui-react-native/experimental-text": "*",
"@fluentui-react-native/focus-trap-zone": "*",
"@fluentui-react-native/focus-zone": "*",
@ -64,7 +63,6 @@
"@fluentui-react-native/stack": "*",
"@fluentui-react-native/styling-utils": "*",
"@fluentui-react-native/switch": "*",
"@fluentui-react-native/tabs": "*",
"@fluentui-react-native/tester": "*",
"@fluentui-react-native/tester-win32": "*",
"@fluentui-react-native/text": "*",

Просмотреть файл

@ -1,334 +1,326 @@
// This file was generated by 'update-profile.js'
/* eslint-disable */
module.exports = {
"0.71": {
"@fluentui-react-native/e2e-testing": {
"name": "@fluentui-react-native/e2e-testing",
"version": "1.32.8"
0.71: {
'@fluentui-react-native/e2e-testing': {
name: '@fluentui-react-native/e2e-testing',
version: '1.32.8',
},
"@fluentui-react-native/tester": {
"name": "@fluentui-react-native/tester",
"version": "0.157.10"
'@fluentui-react-native/tester': {
name: '@fluentui-react-native/tester',
version: '0.157.10',
},
"@fluentui-react-native/tester-win32": {
"name": "@fluentui-react-native/tester-win32",
"version": "0.36.17"
'@fluentui-react-native/tester-win32': {
name: '@fluentui-react-native/tester-win32',
version: '0.36.17',
},
"@fluentui-react-native/avatar": {
"name": "@fluentui-react-native/avatar",
"version": "1.10.18"
'@fluentui-react-native/avatar': {
name: '@fluentui-react-native/avatar',
version: '1.10.18',
},
"@fluentui-react-native/badge": {
"name": "@fluentui-react-native/badge",
"version": "0.7.14"
'@fluentui-react-native/badge': {
name: '@fluentui-react-native/badge',
version: '0.7.14',
},
"@fluentui-react-native/button": {
"name": "@fluentui-react-native/button",
"version": "0.35.11"
'@fluentui-react-native/button': {
name: '@fluentui-react-native/button',
version: '0.35.11',
},
"@fluentui-react-native/callout": {
"name": "@fluentui-react-native/callout",
"version": "0.24.19"
'@fluentui-react-native/callout': {
name: '@fluentui-react-native/callout',
version: '0.24.19',
},
"@fluentui-react-native/checkbox": {
"name": "@fluentui-react-native/checkbox",
"version": "0.21.7"
'@fluentui-react-native/checkbox': {
name: '@fluentui-react-native/checkbox',
version: '0.21.7',
},
"@fluentui-react-native/chip": {
"name": "@fluentui-react-native/chip",
"version": "0.2.9"
'@fluentui-react-native/chip': {
name: '@fluentui-react-native/chip',
version: '0.2.9',
},
"@fluentui-react-native/contextual-menu": {
"name": "@fluentui-react-native/contextual-menu",
"version": "0.22.25"
'@fluentui-react-native/contextual-menu': {
name: '@fluentui-react-native/contextual-menu',
version: '0.22.25',
},
"@fluentui-react-native/divider": {
"name": "@fluentui-react-native/divider",
"version": "0.5.16"
'@fluentui-react-native/divider': {
name: '@fluentui-react-native/divider',
version: '0.5.16',
},
"@fluentui-react-native/focus-trap-zone": {
"name": "@fluentui-react-native/focus-trap-zone",
"version": "0.10.14"
'@fluentui-react-native/focus-trap-zone': {
name: '@fluentui-react-native/focus-trap-zone',
version: '0.10.14',
},
"@fluentui-react-native/focus-zone": {
"name": "@fluentui-react-native/focus-zone",
"version": "0.15.0"
'@fluentui-react-native/focus-zone': {
name: '@fluentui-react-native/focus-zone',
version: '0.15.0',
},
"@fluentui-react-native/icon": {
"name": "@fluentui-react-native/icon",
"version": "0.19.16"
'@fluentui-react-native/icon': {
name: '@fluentui-react-native/icon',
version: '0.19.16',
},
"@fluentui-react-native/input": {
"name": "@fluentui-react-native/input",
"version": "0.4.9"
'@fluentui-react-native/input': {
name: '@fluentui-react-native/input',
version: '0.4.9',
},
"@fluentui-react-native/link": {
"name": "@fluentui-react-native/link",
"version": "0.20.7"
'@fluentui-react-native/link': {
name: '@fluentui-react-native/link',
version: '0.20.7',
},
"@fluentui-react-native/menu": {
"name": "@fluentui-react-native/menu",
"version": "1.11.30"
'@fluentui-react-native/menu': {
name: '@fluentui-react-native/menu',
version: '1.11.30',
},
"@fluentui-react-native/menu-button": {
"name": "@fluentui-react-native/menu-button",
"version": "0.11.31"
'@fluentui-react-native/menu-button': {
name: '@fluentui-react-native/menu-button',
version: '0.11.31',
},
"@fluentui-react-native/notification": {
"name": "@fluentui-react-native/notification",
"version": "0.23.22"
'@fluentui-react-native/notification': {
name: '@fluentui-react-native/notification',
version: '0.23.22',
},
"@fluentui-react-native/persona": {
"name": "@fluentui-react-native/persona",
"version": "0.14.12"
'@fluentui-react-native/persona': {
name: '@fluentui-react-native/persona',
version: '0.14.12',
},
"@fluentui-react-native/persona-coin": {
"name": "@fluentui-react-native/persona-coin",
"version": "0.13.12"
'@fluentui-react-native/persona-coin': {
name: '@fluentui-react-native/persona-coin',
version: '0.13.12',
},
"@fluentui-react-native/pressable": {
"name": "@fluentui-react-native/pressable",
"version": "0.10.13"
'@fluentui-react-native/pressable': {
name: '@fluentui-react-native/pressable',
version: '0.10.13',
},
"@fluentui-react-native/radio-group": {
"name": "@fluentui-react-native/radio-group",
"version": "0.19.9"
'@fluentui-react-native/radio-group': {
name: '@fluentui-react-native/radio-group',
version: '0.19.9',
},
"@fluentui-react-native/separator": {
"name": "@fluentui-react-native/separator",
"version": "0.16.10"
'@fluentui-react-native/separator': {
name: '@fluentui-react-native/separator',
version: '0.16.10',
},
"@fluentui-react-native/stack": {
"name": "@fluentui-react-native/stack",
"version": "0.8.16"
'@fluentui-react-native/stack': {
name: '@fluentui-react-native/stack',
version: '0.8.16',
},
"@fluentui-react-native/switch": {
"name": "@fluentui-react-native/switch",
"version": "0.11.7"
'@fluentui-react-native/switch': {
name: '@fluentui-react-native/switch',
version: '0.11.7',
},
"@fluentui-react-native/tabs": {
"name": "@fluentui-react-native/tabs",
"version": "0.13.19"
'@fluentui-react-native/text': {
name: '@fluentui-react-native/text',
version: '0.21.14',
},
"@fluentui-react-native/text": {
"name": "@fluentui-react-native/text",
"version": "0.21.14"
'@uifabricshared/foundation-composable': {
name: '@uifabricshared/foundation-composable',
version: '0.12.2',
},
"@uifabricshared/foundation-composable": {
"name": "@uifabricshared/foundation-composable",
"version": "0.12.2"
'@uifabricshared/foundation-compose': {
name: '@uifabricshared/foundation-compose',
version: '1.14.12',
},
"@uifabricshared/foundation-compose": {
"name": "@uifabricshared/foundation-compose",
"version": "1.14.12"
'@uifabricshared/foundation-settings': {
name: '@uifabricshared/foundation-settings',
version: '0.13.2',
},
"@uifabricshared/foundation-settings": {
"name": "@uifabricshared/foundation-settings",
"version": "0.13.2"
'@uifabricshared/foundation-tokens': {
name: '@uifabricshared/foundation-tokens',
version: '0.13.9',
},
"@uifabricshared/foundation-tokens": {
"name": "@uifabricshared/foundation-tokens",
"version": "0.13.9"
'@uifabricshared/theme-registry': {
name: '@uifabricshared/theme-registry',
version: '0.10.1',
},
"@uifabricshared/theme-registry": {
"name": "@uifabricshared/theme-registry",
"version": "0.10.1"
'@uifabricshared/themed-settings': {
name: '@uifabricshared/themed-settings',
version: '0.10.2',
},
"@uifabricshared/themed-settings": {
"name": "@uifabricshared/themed-settings",
"version": "0.10.2"
'@uifabricshared/theming-ramp': {
name: '@uifabricshared/theming-ramp',
version: '0.19.4',
},
"@uifabricshared/theming-ramp": {
"name": "@uifabricshared/theming-ramp",
"version": "0.19.4"
'@uifabricshared/theming-react-native': {
name: '@uifabricshared/theming-react-native',
version: '0.18.12',
},
"@uifabricshared/theming-react-native": {
"name": "@uifabricshared/theming-react-native",
"version": "0.18.12"
'@fluentui-react-native/experimental-activity-indicator': {
name: '@fluentui-react-native/experimental-activity-indicator',
version: '0.8.12',
},
"@fluentui-react-native/experimental-activity-indicator": {
"name": "@fluentui-react-native/experimental-activity-indicator",
"version": "0.8.12"
'@fluentui-react-native/experimental-appearance-additions': {
name: '@fluentui-react-native/experimental-appearance-additions',
version: '0.5.12',
},
"@fluentui-react-native/experimental-appearance-additions": {
"name": "@fluentui-react-native/experimental-appearance-additions",
"version": "0.5.12"
'@fluentui-react-native/experimental-avatar': {
name: '@fluentui-react-native/experimental-avatar',
version: '0.19.11',
},
"@fluentui-react-native/experimental-avatar": {
"name": "@fluentui-react-native/experimental-avatar",
"version": "0.19.11"
'@fluentui-react-native/experimental-button': {
name: '@fluentui-react-native/experimental-button',
version: '0.18.22',
},
"@fluentui-react-native/experimental-button": {
"name": "@fluentui-react-native/experimental-button",
"version": "0.18.22"
'@fluentui-react-native/experimental-checkbox': {
name: '@fluentui-react-native/experimental-checkbox',
version: '0.15.17',
},
"@fluentui-react-native/experimental-checkbox": {
"name": "@fluentui-react-native/experimental-checkbox",
"version": "0.15.17"
'@fluentui-react-native/drawer': {
name: '@fluentui-react-native/drawer',
version: '0.2.13',
},
"@fluentui-react-native/drawer": {
"name": "@fluentui-react-native/drawer",
"version": "0.2.13"
'@fluentui-react-native/dropdown': {
name: '@fluentui-react-native/dropdown',
version: '0.8.29',
},
"@fluentui-react-native/dropdown": {
"name": "@fluentui-react-native/dropdown",
"version": "0.8.29"
'@fluentui-react-native/experimental-expander': {
name: '@fluentui-react-native/experimental-expander',
version: '0.6.13',
},
"@fluentui-react-native/experimental-expander": {
"name": "@fluentui-react-native/experimental-expander",
"version": "0.6.13"
'@fluentui-react-native/experimental-link': {
name: '@fluentui-react-native/experimental-link',
version: '0.6.16',
},
"@fluentui-react-native/experimental-link": {
"name": "@fluentui-react-native/experimental-link",
"version": "0.6.16"
'@fluentui-react-native/experimental-menu-button': {
name: '@fluentui-react-native/experimental-menu-button',
version: '0.7.31',
},
"@fluentui-react-native/experimental-menu-button": {
"name": "@fluentui-react-native/experimental-menu-button",
"version": "0.7.31"
'@fluentui-react-native/experimental-native-date-picker': {
name: '@fluentui-react-native/experimental-native-date-picker',
version: '0.9.1',
},
"@fluentui-react-native/experimental-native-date-picker": {
"name": "@fluentui-react-native/experimental-native-date-picker",
"version": "0.9.1"
'@fluentui-react-native/experimental-native-font-metrics': {
name: '@fluentui-react-native/experimental-native-font-metrics',
version: '0.4.1',
},
"@fluentui-react-native/experimental-native-font-metrics": {
"name": "@fluentui-react-native/experimental-native-font-metrics",
"version": "0.4.1"
'@fluentui-react-native/popover': {
name: '@fluentui-react-native/popover',
version: '0.2.11',
},
"@fluentui-react-native/popover": {
"name": "@fluentui-react-native/popover",
"version": "0.2.11"
'@fluentui-react-native/experimental-radio-group': {
name: '@fluentui-react-native/experimental-radio-group',
version: '0.11.19',
},
"@fluentui-react-native/experimental-radio-group": {
"name": "@fluentui-react-native/experimental-radio-group",
"version": "0.11.19"
'@fluentui-react-native/experimental-shadow': {
name: '@fluentui-react-native/experimental-shadow',
version: '0.4.12',
},
"@fluentui-react-native/experimental-shadow": {
"name": "@fluentui-react-native/experimental-shadow",
"version": "0.4.12"
'@fluentui-react-native/experimental-shimmer': {
name: '@fluentui-react-native/experimental-shimmer',
version: '0.11.6',
},
"@fluentui-react-native/experimental-shimmer": {
"name": "@fluentui-react-native/experimental-shimmer",
"version": "0.11.6"
'@fluentui-react-native/spinner': {
name: '@fluentui-react-native/spinner',
version: '0.7.15',
},
"@fluentui-react-native/spinner": {
"name": "@fluentui-react-native/spinner",
"version": "0.7.15"
'@fluentui-react-native/tablist': {
name: '@fluentui-react-native/tablist',
version: '0.4.10',
},
"@fluentui-react-native/tablist": {
"name": "@fluentui-react-native/tablist",
"version": "0.4.10"
'@fluentui-react-native/experimental-text': {
name: '@fluentui-react-native/experimental-text',
version: '0.13.14',
},
"@fluentui-react-native/experimental-tabs": {
"name": "@fluentui-react-native/experimental-tabs",
"version": "0.9.21"
'@fluentui-react-native/vibrancy-view': {
name: '@fluentui-react-native/vibrancy-view',
version: '0.0.3',
},
"@fluentui-react-native/experimental-text": {
"name": "@fluentui-react-native/experimental-text",
"version": "0.13.14"
'@fluentui-react-native/component-cache': {
name: '@fluentui-react-native/component-cache',
version: '1.5.1',
},
"@fluentui-react-native/vibrancy-view": {
"name": "@fluentui-react-native/vibrancy-view",
"version": "0.0.3"
'@fluentui-react-native/composition': {
name: '@fluentui-react-native/composition',
version: '0.9.2',
},
"@fluentui-react-native/component-cache": {
"name": "@fluentui-react-native/component-cache",
"version": "1.5.1"
'@fluentui-react-native/eslint-config-rules': {
name: '@fluentui-react-native/eslint-config-rules',
version: '0.1.1',
},
"@fluentui-react-native/composition": {
"name": "@fluentui-react-native/composition",
"version": "0.9.2"
'@fluentui-react-native/framework': {
name: '@fluentui-react-native/framework',
version: '0.11.10',
},
"@fluentui-react-native/eslint-config-rules": {
"name": "@fluentui-react-native/eslint-config-rules",
"version": "0.1.1"
'@fluentui-react-native/immutable-merge': {
name: '@fluentui-react-native/immutable-merge',
version: '1.2.1',
},
"@fluentui-react-native/framework": {
"name": "@fluentui-react-native/framework",
"version": "0.11.10"
'@fluentui-react-native/memo-cache': {
name: '@fluentui-react-native/memo-cache',
version: '1.3.1',
},
"@fluentui-react-native/immutable-merge": {
"name": "@fluentui-react-native/immutable-merge",
"version": "1.2.1"
'@fluentui-react-native/merge-props': {
name: '@fluentui-react-native/merge-props',
version: '0.7.1',
},
"@fluentui-react-native/memo-cache": {
"name": "@fluentui-react-native/memo-cache",
"version": "1.3.1"
'@fluentui-react-native/theme': {
name: '@fluentui-react-native/theme',
version: '0.9.4',
},
"@fluentui-react-native/merge-props": {
"name": "@fluentui-react-native/merge-props",
"version": "0.7.1"
'@fluentui-react-native/themed-stylesheet': {
name: '@fluentui-react-native/themed-stylesheet',
version: '1.5.2',
},
"@fluentui-react-native/theme": {
"name": "@fluentui-react-native/theme",
"version": "0.9.4"
'@fluentui-react-native/use-slot': {
name: '@fluentui-react-native/use-slot',
version: '0.4.2',
},
"@fluentui-react-native/themed-stylesheet": {
"name": "@fluentui-react-native/themed-stylesheet",
"version": "1.5.2"
'@fluentui-react-native/use-slots': {
name: '@fluentui-react-native/use-slots',
version: '0.8.2',
},
"@fluentui-react-native/use-slot": {
"name": "@fluentui-react-native/use-slot",
"version": "0.4.2"
'@fluentui-react-native/use-styling': {
name: '@fluentui-react-native/use-styling',
version: '0.11.1',
},
"@fluentui-react-native/use-slots": {
"name": "@fluentui-react-native/use-slots",
"version": "0.8.2"
'@fluentui-react-native/use-tokens': {
name: '@fluentui-react-native/use-tokens',
version: '0.4.2',
},
"@fluentui-react-native/use-styling": {
"name": "@fluentui-react-native/use-styling",
"version": "0.11.1"
'@fluentui/react-native': {
name: '@fluentui/react-native',
version: '0.38.6',
},
"@fluentui-react-native/use-tokens": {
"name": "@fluentui-react-native/use-tokens",
"version": "0.4.2"
'@fluentui-react-native/android-theme': {
name: '@fluentui-react-native/android-theme',
version: '0.18.9',
},
"@fluentui/react-native": {
"name": "@fluentui/react-native",
"version": "0.38.6"
'@fluentui-react-native/apple-theme': {
name: '@fluentui-react-native/apple-theme',
version: '0.21.13',
},
"@fluentui-react-native/android-theme": {
"name": "@fluentui-react-native/android-theme",
"version": "0.18.9"
'@fluentui-react-native/default-theme': {
name: '@fluentui-react-native/default-theme',
version: '0.19.11',
},
"@fluentui-react-native/apple-theme": {
"name": "@fluentui-react-native/apple-theme",
"version": "0.21.13"
'@fluentui-react-native/theme-tokens': {
name: '@fluentui-react-native/theme-tokens',
version: '0.25.4',
},
"@fluentui-react-native/default-theme": {
"name": "@fluentui-react-native/default-theme",
"version": "0.19.11"
'@fluentui-react-native/theme-types': {
name: '@fluentui-react-native/theme-types',
version: '0.32.3',
},
"@fluentui-react-native/theme-tokens": {
"name": "@fluentui-react-native/theme-tokens",
"version": "0.25.4"
'@fluentui-react-native/theming-utils': {
name: '@fluentui-react-native/theming-utils',
version: '0.24.7',
},
"@fluentui-react-native/theme-types": {
"name": "@fluentui-react-native/theme-types",
"version": "0.32.3"
'@fluentui-react-native/win32-theme': {
name: '@fluentui-react-native/win32-theme',
version: '0.27.10',
},
"@fluentui-react-native/theming-utils": {
"name": "@fluentui-react-native/theming-utils",
"version": "0.24.7"
'@fluentui-react-native/adapters': {
name: '@fluentui-react-native/adapters',
version: '0.11.3',
},
"@fluentui-react-native/win32-theme": {
"name": "@fluentui-react-native/win32-theme",
"version": "0.27.10"
'@fluentui-react-native/interactive-hooks': {
name: '@fluentui-react-native/interactive-hooks',
version: '0.24.12',
},
"@fluentui-react-native/adapters": {
"name": "@fluentui-react-native/adapters",
"version": "0.11.3"
'@fluentui-react-native/styling-utils': {
name: '@fluentui-react-native/styling-utils',
version: '0.5.0',
},
"@fluentui-react-native/interactive-hooks": {
"name": "@fluentui-react-native/interactive-hooks",
"version": "0.24.12"
'@fluentui-react-native/tokens': {
name: '@fluentui-react-native/tokens',
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 clients 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/radio-group": "0.20.8",
"@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"
},
"devDependencies": {

Просмотреть файл

@ -322,21 +322,18 @@ export type {
MenuButtonType,
} 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 {
TabsContextData,
TabsInfo,
TabsItemInfo,
TabsItemProps,
TabsItemRenderData,
TabsItemSlotProps,
TabsItemState,
TabsItemTokens,
TabsItemType,
TabsProps,
TabsRenderData,
TabsSlotProps,
TabsState,
TabsTokens,
TabsType,
} from '@fluentui-react-native/tabs';
TabListInfo,
TabListProps,
TabListSlotProps,
TabListState,
TabListTokens,
TabListType,
TabInfo,
TabProps,
TabSlotProps,
TabState,
TabTokens,
TabType,
} from '@fluentui-react-native/tablist';

Просмотреть файл

@ -2642,7 +2642,6 @@ __metadata:
"@fluentui-react-native/experimental-shadow": "*"
"@fluentui-react-native/experimental-shimmer": "*"
"@fluentui-react-native/experimental-stack": "*"
"@fluentui-react-native/experimental-tabs": "*"
"@fluentui-react-native/experimental-text": "*"
"@fluentui-react-native/focus-trap-zone": "*"
"@fluentui-react-native/focus-zone": "*"
@ -2666,7 +2665,6 @@ __metadata:
"@fluentui-react-native/stack": "*"
"@fluentui-react-native/styling-utils": "*"
"@fluentui-react-native/switch": "*"
"@fluentui-react-native/tabs": "*"
"@fluentui-react-native/tester": "*"
"@fluentui-react-native/tester-win32": "*"
"@fluentui-react-native/text": "*"
@ -3084,32 +3082,6 @@ __metadata:
languageName: unknown
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":
version: 0.0.0-use.local
resolution: "@fluentui-react-native/experimental-text@workspace:packages/experimental/Text"
@ -3749,32 +3721,6 @@ __metadata:
languageName: unknown
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":
version: 0.0.0-use.local
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-shadow": 0.5.6
"@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/focus-zone": ^0.16.6
"@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/scripts": ^0.1.1
"@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
"@react-native/metro-config": ^0.72.0
react: 18.2.0