mirror of
https://github.com/wassname/talk.git
synced 2026-07-07 09:53:01 +08:00
Merge branch 'next' into next-passport
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
|
||||
exports[`renders correctly on big screens 1`] = `
|
||||
<div
|
||||
className="Flex-root TopBar-root Flex-itemGutter Flex-alignCenter Flex-directionRow"
|
||||
className="Flex-root TopBar-root Flex-itemGutter Flex-alignBaseline Flex-directionRow"
|
||||
>
|
||||
<div>
|
||||
Hello World
|
||||
|
||||
@@ -43,12 +43,12 @@ exports[`loads more comments 1`] = `
|
||||
</form>
|
||||
<div
|
||||
aria-live="polite"
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
id="talk-comments-stream-log"
|
||||
role="log"
|
||||
>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
>
|
||||
<div
|
||||
role="article"
|
||||
@@ -77,7 +77,7 @@ exports[`loads more comments 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
>
|
||||
<div
|
||||
role="article"
|
||||
@@ -106,7 +106,7 @@ exports[`loads more comments 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
>
|
||||
<div
|
||||
role="article"
|
||||
@@ -182,12 +182,12 @@ exports[`renders comment stream 1`] = `
|
||||
</form>
|
||||
<div
|
||||
aria-live="polite"
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
id="talk-comments-stream-log"
|
||||
role="log"
|
||||
>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
>
|
||||
<div
|
||||
role="article"
|
||||
@@ -216,7 +216,7 @@ exports[`renders comment stream 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
>
|
||||
<div
|
||||
role="article"
|
||||
|
||||
@@ -43,12 +43,12 @@ exports[`renders comment stream 1`] = `
|
||||
</form>
|
||||
<div
|
||||
aria-live="polite"
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
id="talk-comments-stream-log"
|
||||
role="log"
|
||||
>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
>
|
||||
<div
|
||||
role="article"
|
||||
@@ -77,7 +77,7 @@ exports[`renders comment stream 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
>
|
||||
<div
|
||||
role="article"
|
||||
@@ -108,7 +108,7 @@ exports[`renders comment stream 1`] = `
|
||||
className="Indent-root Indent-level0"
|
||||
>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
id="talk-comments-replyList-log--comment-with-replies"
|
||||
role="log"
|
||||
>
|
||||
|
||||
@@ -43,12 +43,12 @@ exports[`renders comment stream 1`] = `
|
||||
</form>
|
||||
<div
|
||||
aria-live="polite"
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
id="talk-comments-stream-log"
|
||||
role="log"
|
||||
>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
>
|
||||
<div
|
||||
role="article"
|
||||
@@ -77,7 +77,7 @@ exports[`renders comment stream 1`] = `
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
>
|
||||
<div
|
||||
role="article"
|
||||
|
||||
@@ -43,12 +43,12 @@ exports[`renders comment stream 1`] = `
|
||||
</form>
|
||||
<div
|
||||
aria-live="polite"
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
id="talk-comments-stream-log"
|
||||
role="log"
|
||||
>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
>
|
||||
<div
|
||||
role="article"
|
||||
@@ -79,7 +79,7 @@ exports[`renders comment stream 1`] = `
|
||||
className="Indent-root Indent-level0"
|
||||
>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
id="talk-comments-replyList-log--comment-0"
|
||||
role="log"
|
||||
>
|
||||
@@ -174,12 +174,12 @@ exports[`show all replies 1`] = `
|
||||
</form>
|
||||
<div
|
||||
aria-live="polite"
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
id="talk-comments-stream-log"
|
||||
role="log"
|
||||
>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
>
|
||||
<div
|
||||
role="article"
|
||||
@@ -210,7 +210,7 @@ exports[`show all replies 1`] = `
|
||||
className="Indent-root Indent-level0"
|
||||
>
|
||||
<div
|
||||
className="Flex-root Flex-itemGutter Flex-directionColumn"
|
||||
className="Flex-root Flex-itemGutter Flex-alignFlexStart Flex-directionColumn"
|
||||
id="talk-comments-replyList-log--comment-0"
|
||||
role="log"
|
||||
>
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
---
|
||||
name: AriaInfo
|
||||
menu: UI Kit
|
||||
---
|
||||
|
||||
import { Playground, PropsTable } from 'docz'
|
||||
import AriaInfo from './AriaInfo'
|
||||
|
||||
# AriaInfo
|
||||
|
||||
Renders Text that is only seen by screen readers.
|
||||
|
||||
## Basic usage
|
||||
<Playground>
|
||||
<AriaInfo>This can only be seen by screen readers</AriaInfo>
|
||||
<div>Above this line is a hidden text that you can't see</div>
|
||||
</Playground>
|
||||
@@ -0,0 +1,10 @@
|
||||
.root {
|
||||
position: absolute !important;
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
padding: 0;
|
||||
overflow: hidden;
|
||||
clip: rect(0, 0, 0, 0);
|
||||
white-space: nowrap;
|
||||
border: 0;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import React from "react";
|
||||
import TestRenderer from "react-test-renderer";
|
||||
|
||||
import { PropTypesOf } from "talk-framework/types";
|
||||
|
||||
import AriaInfo from "./AriaInfo";
|
||||
|
||||
it("renders correctly", () => {
|
||||
const props: PropTypesOf<typeof AriaInfo> = {
|
||||
children: "This text is only for screen readers",
|
||||
};
|
||||
const renderer = TestRenderer.create(<AriaInfo {...props} />);
|
||||
expect(renderer.toJSON()).toMatchSnapshot();
|
||||
});
|
||||
@@ -0,0 +1,32 @@
|
||||
import cn from "classnames";
|
||||
import React, { HTMLAttributes, StatelessComponent } from "react";
|
||||
|
||||
import { withForwardRef, withStyles } from "talk-ui/hocs";
|
||||
import { PropTypesOf } from "talk-ui/types";
|
||||
|
||||
import * as styles from "./AriaInfo.css";
|
||||
|
||||
interface InnerProps extends HTMLAttributes<HTMLElement> {
|
||||
/**
|
||||
* This prop can be used to add custom classnames.
|
||||
* It is handled by the `withStyles `HOC.
|
||||
*/
|
||||
classes: typeof styles;
|
||||
component?: string;
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
const AriaInfo: StatelessComponent<InnerProps> = props => {
|
||||
const { component, className, classes, ...rest } = props;
|
||||
const Component = component!;
|
||||
const rootClassName = cn(classes.root, className);
|
||||
return <Component className={rootClassName} {...rest} />;
|
||||
};
|
||||
|
||||
AriaInfo.defaultProps = {
|
||||
component: "div",
|
||||
};
|
||||
|
||||
const enhanced = withForwardRef(withStyles(styles)(AriaInfo));
|
||||
export type AriaInfoProps = PropTypesOf<typeof enhanced>;
|
||||
export default enhanced;
|
||||
@@ -0,0 +1,9 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`renders correctly 1`] = `
|
||||
<div
|
||||
className="AriaInfo-root"
|
||||
>
|
||||
This text is only for screen readers
|
||||
</div>
|
||||
`;
|
||||
@@ -0,0 +1 @@
|
||||
export { default, AriaInfoProps } from "./AriaInfo";
|
||||
@@ -2,7 +2,7 @@
|
||||
border-radius: var(--round-corners);
|
||||
background-color: transparent;
|
||||
position: relative;
|
||||
display: flex;
|
||||
display: inline-flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
|
||||
@@ -47,8 +47,9 @@ const Flex: StatelessComponent<InnerProps> = props => {
|
||||
} = props;
|
||||
|
||||
let alignItemsWithDefault = alignItems;
|
||||
if (!direction || !direction.startsWith("column")) {
|
||||
alignItemsWithDefault = "center";
|
||||
if (!alignItems) {
|
||||
alignItemsWithDefault =
|
||||
direction && direction.startsWith("column") ? "flex-start" : "center";
|
||||
}
|
||||
|
||||
const classObject: Record<string, boolean> = {
|
||||
|
||||
@@ -9,7 +9,7 @@ it("renders correctly", () => {
|
||||
{({ toggleShow, show }) => (
|
||||
<div>
|
||||
{show && <div>SHOW ME</div>}
|
||||
<button onClick={toggleShow}>Click me and I disapear</button>
|
||||
<button onClick={toggleShow}>Click me and I disappear</button>
|
||||
</div>
|
||||
)}
|
||||
</ToggleShow>
|
||||
|
||||
@@ -5,18 +5,22 @@ menu: UI Kit
|
||||
|
||||
import { Playground } from 'docz'
|
||||
import ToggleShow from './ToggleShow'
|
||||
import Button from '../Button'
|
||||
import Flex from '../Flex'
|
||||
|
||||
# ToggleShow
|
||||
A Component that provides a render function to display nodes
|
||||
A render props component to manage visible state.
|
||||
|
||||
## Basic usage
|
||||
<Playground>
|
||||
<ToggleShow>
|
||||
{({ toggleShow, show }) => (
|
||||
<div>
|
||||
{show && <div>SHOW ME</div>}
|
||||
<button onClick={toggleShow}>ClickMe and I disapear</button>
|
||||
</div>
|
||||
<Flex itemGutter direction="column">
|
||||
{show && <div>Hello World!</div>}
|
||||
<Button onClick={toggleShow} variant="filled" color="primary">
|
||||
Toggle Show
|
||||
</Button>
|
||||
</Flex>
|
||||
)}
|
||||
</ToggleShow>
|
||||
</Playground>
|
||||
|
||||
@@ -8,7 +8,7 @@ exports[`renders correctly 1`] = `
|
||||
<button
|
||||
onClick={[Function]}
|
||||
>
|
||||
Click me and I disapear
|
||||
Click me and I disappear
|
||||
</button>
|
||||
</div>
|
||||
`;
|
||||
|
||||
@@ -5,6 +5,7 @@ menu: UI Kit
|
||||
|
||||
import { Playground } from 'docz'
|
||||
import TrapFocus from './TrapFocus'
|
||||
import Button from '../Button'
|
||||
|
||||
# TrapFocus
|
||||
|
||||
@@ -12,28 +13,15 @@ Traps focus inside component when using keyboard navigation for accessibility pu
|
||||
|
||||
## Basic usage
|
||||
|
||||
```ts
|
||||
import React from "react";
|
||||
|
||||
class Dialog extends React.Component {
|
||||
private firstFocusable: HTMLElement;
|
||||
private lastFocusable: HTMLElement;
|
||||
|
||||
private setFirstFocusable = (ref: HTMLElement) => (this.firstFocusable = ref);
|
||||
private setLastFocusable = (ref: HTMLElement) => (this.lastFocusable = ref);
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<Playground>
|
||||
<div>
|
||||
<TrapFocus>
|
||||
{({firstFocusableRef, lastFocusableRef}) =>
|
||||
<div>
|
||||
<TrapFocus
|
||||
firstFocusable={this.firstFocusable}
|
||||
lastFocusable={this.lastFocusable}
|
||||
>
|
||||
<TextField ref={this.setFirstFocusable} />
|
||||
<Button ref={this.setLastFocusable}>Send</Button>
|
||||
</TrapFocus>
|
||||
<Button forwardRef={firstFocusableRef} autoFocus>Cancel</Button>
|
||||
<Button forwardRef={lastFocusableRef}>Send</Button>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
```
|
||||
}
|
||||
</TrapFocus>
|
||||
</div>
|
||||
</Playground>
|
||||
|
||||
@@ -5,11 +5,16 @@ import Sinon from "sinon";
|
||||
import { PropTypesOf } from "talk-ui/types";
|
||||
import TrapFocus from "./TrapFocus";
|
||||
|
||||
const FakeFocusable: any = class extends React.Component {
|
||||
public focus = Sinon.spy();
|
||||
public render() {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
it("renders correctly", () => {
|
||||
const props: PropTypesOf<TrapFocus> = {
|
||||
firstFocusable: null,
|
||||
lastFocusable: null,
|
||||
children: (
|
||||
children: () => (
|
||||
<>
|
||||
<span>child1</span>
|
||||
<span>child2</span>
|
||||
@@ -25,15 +30,13 @@ it("renders correctly", () => {
|
||||
});
|
||||
|
||||
it("Change focus to `lastFocusable` when focus reaches beginning", () => {
|
||||
const fakeHTMLElementBegin = { focus: Sinon.spy() };
|
||||
const fakeHTMLElementEnd = { focus: Sinon.spy() };
|
||||
const props: PropTypesOf<TrapFocus> = {
|
||||
firstFocusable: fakeHTMLElementBegin as any,
|
||||
lastFocusable: fakeHTMLElementEnd as any,
|
||||
children: (
|
||||
children: ({ firstFocusableRef, lastFocusableRef }) => (
|
||||
<>
|
||||
<FakeFocusable ref={firstFocusableRef} />
|
||||
<span>child1</span>
|
||||
<span>child2</span>
|
||||
<FakeFocusable ref={lastFocusableRef} />
|
||||
</>
|
||||
),
|
||||
};
|
||||
@@ -43,20 +46,22 @@ it("Change focus to `lastFocusable` when focus reaches beginning", () => {
|
||||
</div>
|
||||
);
|
||||
renderer.root.findAllByProps({ tabIndex: 0 })[0].props.onFocus();
|
||||
expect(fakeHTMLElementBegin.focus.called).toBe(false);
|
||||
expect(fakeHTMLElementEnd.focus.called).toBe(true);
|
||||
expect(
|
||||
renderer.root.findAllByType(FakeFocusable)[0].instance.focus.called
|
||||
).toBe(false);
|
||||
expect(
|
||||
renderer.root.findAllByType(FakeFocusable)[1].instance.focus.called
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("Change focus to `firstFocusable` when focus reaches the end", () => {
|
||||
const fakeHTMLElementBegin = { focus: Sinon.spy() };
|
||||
const fakeHTMLElementEnd = { focus: Sinon.spy() };
|
||||
it("Change focus to `firstFocusable` when focus reaches end", () => {
|
||||
const props: PropTypesOf<TrapFocus> = {
|
||||
firstFocusable: fakeHTMLElementBegin as any,
|
||||
lastFocusable: fakeHTMLElementEnd as any,
|
||||
children: (
|
||||
children: ({ firstFocusableRef, lastFocusableRef }) => (
|
||||
<>
|
||||
<FakeFocusable ref={firstFocusableRef} />
|
||||
<span>child1</span>
|
||||
<span>child2</span>
|
||||
<FakeFocusable ref={lastFocusableRef} />
|
||||
</>
|
||||
),
|
||||
};
|
||||
@@ -66,6 +71,10 @@ it("Change focus to `firstFocusable` when focus reaches the end", () => {
|
||||
</div>
|
||||
);
|
||||
renderer.root.findAllByProps({ tabIndex: 0 })[1].props.onFocus();
|
||||
expect(fakeHTMLElementBegin.focus.called).toBe(true);
|
||||
expect(fakeHTMLElementEnd.focus.called).toBe(false);
|
||||
expect(
|
||||
renderer.root.findAllByType(FakeFocusable)[0].instance.focus.called
|
||||
).toBe(true);
|
||||
expect(
|
||||
renderer.root.findAllByType(FakeFocusable)[1].instance.focus.called
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
@@ -1,25 +1,34 @@
|
||||
import React from "react";
|
||||
import React, { RefObject } from "react";
|
||||
|
||||
export interface Focusable {
|
||||
focus: () => void;
|
||||
}
|
||||
|
||||
interface RenderProps {
|
||||
firstFocusableRef: RefObject<Focusable>;
|
||||
lastFocusableRef: RefObject<Focusable>;
|
||||
}
|
||||
|
||||
export interface TrapFocusProps {
|
||||
firstFocusable: Focusable | null;
|
||||
lastFocusable: Focusable | null;
|
||||
children: React.ReactNode;
|
||||
children: (props: RenderProps) => React.ReactNode;
|
||||
}
|
||||
|
||||
export default class TrapFocus extends React.Component<TrapFocusProps> {
|
||||
private firstFocusableRef = React.createRef<Focusable>();
|
||||
private lastFocusableRef = React.createRef<Focusable>();
|
||||
|
||||
// Trap keyboard focus inside the dropdown until a value has been chosen.
|
||||
public focusBegin = () => this.props.firstFocusable!.focus();
|
||||
public focusEnd = () => this.props.lastFocusable!.focus();
|
||||
private focusBegin = () => this.firstFocusableRef.current!.focus();
|
||||
private focusEnd = () => this.lastFocusableRef.current!.focus();
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<>
|
||||
<div tabIndex={0} onFocus={this.focusEnd} />
|
||||
{this.props.children}
|
||||
{this.props.children({
|
||||
firstFocusableRef: this.firstFocusableRef,
|
||||
lastFocusableRef: this.lastFocusableRef,
|
||||
})}
|
||||
<div tabIndex={0} onFocus={this.focusBegin} />
|
||||
</>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user