Реагировать на пользовательский интерфейс - PullRequest
0 голосов
/ 25 марта 2020

Я сейчас занимаюсь разработкой приложения для команд MS. После того, как вы привыкли к библиотеке MS UI (теперь она называется fluent-ui), все начинает собираться вместе. Поскольку я хочу предоставить своим пользователям «встроенный» опыт, я хочу использовать собственные темы и стили, которые также использует Microsoft.

В качестве основы я использую @ fluentui / реагировать-northstar , который официально поддерживается командами , проверьте здесь. И самое лучшее, он имеет встроенные темы для команды на борту. Круто.

Пока все хорошо. Я также хочу показать несколько списков, где отображаются данные текущего вошедшего в систему пользователя. Для этого я хотел использовать Shimmer-DetailsList . Проблема в том, что я не могу применить темы из @ fluentui / реагировать на север, что сводит меня с ума. Кто-нибудь знает, что я могу сделать здесь? Это сводит меня с ума от того, что предоставленные пользовательские интерфейсы несовместимы друг с другом, или, может быть, я не использую правильный подход.

Я также могу показать некоторый код, если хотите, но в этом состоянии я просто пытаюсь понять.

Большое спасибо за вашу помощь, ребята!

Лучше, Том

Обновление: Да, может быть немного сложнее, но я стараюсь изо всех сил показывать свой код. Я буду сокращать ненужные части. Код написан для React.

Index. js Здесь я определяю, какая тема у пользователя активна, что можно сделать с помощью window.location.search. Затем тема также вставляется в приложение. js в качестве реквизита.

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { Provider, themes } from '@fluentui/react-northstar'

...

const teamsTheme =  updateTheme(getQueryVariable('theme'));
//const baseUrl = document.getElementsByTagName('base')[0].getAttribute('href');
const rootElement = document.getElementById('root');
console.log("theme in index: " + teamsTheme);
ReactDOM.render(
    <Provider theme={teamsTheme}>
        <App theme={teamsTheme}/>
    </Provider>,
    rootElement
);

приложение. js в приложении. js Я определяю некоторые общие вещи. Я проверяю, могут ли Команды аутентифицировать пользователя, а также принял ли пользователь TOU при первом использовании (запрос по моему API). Если все в порядке, я рендеринг пользовательского компонента, называемого контентом, где я также передаю тему в качестве поддержки. Я оставлю объявления общих функций, потому что они в настоящее время не вызывают проблемы.

import React, { Component } from 'react';
import TouService from "./services/touService";
import { Stack } from 'office-ui-fabric-react'
import { Loader } from '@fluentui/react-northstar'
import "./css/settings.css"
import Content from "./components/Content"
import AcceptTou from "./components/AcceptTou"
const microsoftTeams = require('@microsoft/teams-js');

export default class App extends Component {
    static displayName = App.name;

    constructor(props) {
        super(props)

        this.touService = new TouService();

        this.state = {
            userIsAuthenticated: false,
            authenticationLoading: true,
            authMessage: "Unauthorized!!!",
            currentUser: "",
            tokenString: "",
            touAccepted: false,
            touLoading: true
        };

        **some functions here**

    componentDidMount() {
        this.initializeTeams();
    }

    render() {
        const loading = (this.state.authenticationLoading || this.state.touLoading || (this.state.touAccepted === false)) ?
            <div>
                <br />
                <Loader label='Loading...' />
                <br />
            </div> :
            <Content theme={this.props.theme}/>;

        const tou = (this.state.userIsAuthenticated && !this.state.authenticationLoading && !this.state.touLoading && !this.state.touAccepted) &&
            <AcceptTou currentUser={this.state.currentUser} touAccepted={this.state.touAccepted} theme={this.props.theme} onTouChange={this.touAcceptedChanged}/>;

        //console.logconsole.log(this.state);

        return (
            <Stack
                horizontalAlign="center"
                verticalFill
                styles={{
                    root: {
                        width: this.width,
                        height: this.height,
                        margin: '0 auto',
                        textAlign: 'center',
                        color: '#605e5c'
                    }
                }}>
                {loading}
                {tou}
            </Stack>
        );
    }
}

Содержимое. js По содержанию я определяю свое общее содержимое для макета страницы.

import React, { Component } from 'react';
import AssetMenu from "../UI/AssetMenu"
import Layout from "../UI/Layout"
import ToolbarMenu from '../UI/ToolbarMenu';
import ShimmerApplicationExample from "./List"

export default class Content extends React.Component {
    constructor(props) {
        super(props)
        console.log("theme in content.js: " + this.props.theme);
    }
    render() {
        const content = "my Content";
        return (
            <Layout header={<AssetMenu />} toolbar={<ToolbarMenu />} content={<ShimmerApplicationExample theme={this.props.theme}/>} />
        );
    }
}

Макет. js обрабатывает общий макет страницы. который в настоящее время не идеален, потому что я все еще учусь, но это можно сделать позже.

import React from 'react';
import { Flex, Segment, Divider } from '@fluentui/react-northstar'

export default class Layout extends React.Component {

    //<Grid columns="repeat(3, 1fr)" rows="50px 150px 50px">
    render() {
        return (
            <Flex column fill>
                {this.props.header}
                {this.props.toolbar}
                <Segment content={this.props.content} />
            </Flex>
        );
    }
}

ToolbarMenu. js предоставляет панель инструментов для взаимодействия пользователя или создания некоторого контента , Но пока не имеет никакой функциональности.

import React from 'react';
import { Menu, menuAsToolbarBehavior } from '@fluentui/react-northstar';

const items = [
    {
        key: 'add',
        icon: {
            name: 'add',
            outline: true,
        },
        content: "New",
        'aria-label': 'add',
    },
    {
        key: 'edit',
        icon: {
            name: 'edit',
            outline: true,
        },
        content: "Edit",
        'aria-label': 'Edit Tool',
    },
    {
        key: 'delete',
        icon: {
            name: 'trash-can',
            outline: true,
        },
        content: "Delete",
        'aria-label': 'Delete Tool',
    },
];

export default class ToolbarMenu extends React.Component {
    render() {
        return (
            <Menu
                defaultActiveIndex={0}
                items={items}
                primary
                iconOnly
                accessibility={menuAsToolbarBehavior}
                aria-label="Compose Editor"
            />
        )
    }
}

List.tsx должен предоставить подробный список для пользовательского контента. Вот где проблема в настоящее время. Код в основном является примером из MS здесь: . За исключением того, что я пытался использовать мою тему из Index. js здесь в списке, который не работает.

import * as React from 'react';
import { Async } from 'office-ui-fabric-react/lib/Utilities';
import { createListItems, IExampleItem } from '@uifabric/example-data';
import { IColumn, buildColumns, SelectionMode, Toggle } from 'office-ui-fabric-react/lib/index';
import { ShimmeredDetailsList } from 'office-ui-fabric-react/lib/ShimmeredDetailsList';

const fileIcons: { name: string }[] = [
  { name: 'accdb' },
  { name: 'csv' },
  { name: 'docx' },
  { name: 'dotx' },
  { name: 'mpt' },
  { name: 'odt' },
  { name: 'one' },
  { name: 'onepkg' },
  { name: 'onetoc' },
  { name: 'pptx' },
  { name: 'pub' },
  { name: 'vsdx' },
  { name: 'xls' },
  { name: 'xlsx' },
  { name: 'xsn' }
];

const ITEMS_COUNT = 200;
const INTERVAL_DELAY = 2500;

let _items: IExampleItem[];

export interface IShimmerApplicationExampleState {
  items: IExampleItem[]; // DetailsList `items` prop is required so it expects at least an empty array.
  columns?: IColumn[];
  isDataLoaded?: boolean;
}

interface IShimmerListProps {
  theme?: any;
}

export default class ShimmerApplicationExample extends React.Component<IShimmerListProps, IShimmerApplicationExampleState> {
  private _lastIntervalId: number = 0;
  private _lastIndexWithData: number = 0;
  private _async: Async;

  constructor(props: {}) {
    super(props);

    this.state = {
      items: [],
      columns: _buildColumns(),
      isDataLoaded: false
    };

    this._async = new Async(this);
    console.log("theme in shimmer list consturctor: " + this.props.theme);
  }

  public componentWillUnmount(): void {
    this._async.dispose();
  }

  public render(): JSX.Element {
    const { items, columns, isDataLoaded } = this.state;
    const theme = this.props.theme;
    return (
      <div>
        <Toggle
          theme = {theme}
          label="Toggle to load content"
          style={{ display: 'block', marginBottom: '20px' }}
          checked={isDataLoaded}
          onText="Content"
          offText="Shimmer"
        />
        <div>
          <ShimmeredDetailsList
            theme = {theme}
            setKey="items"
            items={items}
            columns={columns}
            selectionMode={SelectionMode.none}
            enableShimmer={!isDataLoaded}
            ariaLabelForShimmer="Content is being fetched"
            ariaLabelForGrid="Item details"
            listProps={{ renderedWindowsAhead: 0, renderedWindowsBehind: 0 }}
          />
        </div>
      </div>
    );
  }

  private _loadData = (): void => {
    this._lastIntervalId = this._async.setInterval(() => {
      const randomQuantity: number = Math.floor(Math.random() * 10) + 1;
      const itemsCopy = this.state.items!.slice(0);
      itemsCopy.splice(
        this._lastIndexWithData,
        randomQuantity,
        ..._items.slice(this._lastIndexWithData, this._lastIndexWithData + randomQuantity)
      );
      this._lastIndexWithData += randomQuantity;
      this.setState({
        items: itemsCopy
      });
    }, INTERVAL_DELAY);
  };

  private _onLoadData = (ev: React.MouseEvent<HTMLElement>, checked: boolean): void => {
    if (!_items) {
      _items = createListItems(ITEMS_COUNT);
      _items.map((item: IExampleItem) => {
        const randomFileType = this._randomFileIcon();
        item.thumbnail = randomFileType.url;
      });
    }

    let items: IExampleItem[];
    const randomQuantity: number = Math.floor(Math.random() * 10) + 1;
    if (checked) {
      items = _items.slice(0, randomQuantity).concat(new Array(ITEMS_COUNT - randomQuantity));
      this._lastIndexWithData = randomQuantity;
      this._loadData();
    } else {
      items = [];
      this._async.clearInterval(this._lastIntervalId);
    }
    this.setState({
      isDataLoaded: checked,
      items: items
    });
  };

  private _onRenderItemColumn = (item: IExampleItem, index: number, column: IColumn): JSX.Element | string | number => {
    if (column.key === 'thumbnail') {
      return <img src={item.thumbnail} />;
    }

    return item[column.key as keyof IExampleItem];
  };

  private _randomFileIcon(): { docType: string; url: string } {
    const docType: string = fileIcons[Math.floor(Math.random() * fileIcons.length) + 0].name;
    return {
      docType,
      url: `https://static2.sharepointonline.com/files/fabric/assets/brand-icons/document/svg/${docType}_16x1.svg`
    };
  }
}

function _buildColumns(): IColumn[] {
  const _item = createListItems(1);
  const columns: IColumn[] = buildColumns(_item);

  for (const column of columns) {
    if (column.key === 'thumbnail') {
      column.name = 'FileType';
      column.minWidth = 16;
      column.maxWidth = 16;
      column.isIconOnly = true;
      column.iconName = 'Page';
      break;
    }
  }

  return columns;
}


Для лучшего понимания: Microsoft говорит, что этот пакет (fluentui / реагировать на северную звезду) лучше всего подходит для поддержки команд, потому что в нем есть все, а также есть интегрированные темы для команд, но он делает не предоставлять DetailsList как office-ui-реагировать (что на самом деле должно быть почти одинаковой библиотекой?), и они также не совместимы друг с другом?

Понятия не имею, что я сделал неправильно, и если возможно, я предпочел бы не определять мои собственные темы, чем использовать уже существующие.

...