Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .babelrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"sourceType": "unambiguous",
"presets": [
[
"@babel/preset-env",
{
"targets": {
"chrome": 100
}
}
],
"@babel/preset-typescript",
"@babel/preset-react"
],
"plugins": []
}
12 changes: 7 additions & 5 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
'airbnb',
'plugin:react-hooks/recommended',
'prettier',
'plugin:storybook/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
Expand All @@ -34,11 +35,9 @@ module.exports = {
'@typescript-eslint/no-use-before-define': 'error',
'no-shadow': 'off',
'@typescript-eslint/no-shadow': 'error',

'no-void': 'off',
'consistent-return': 'off',
'no-restricted-syntax': 'off',

'import/prefer-default-export': 'off',
'import/no-extraneous-dependencies': 'off',
'import/extensions': [
Expand All @@ -47,12 +46,15 @@ module.exports = {
tsx: 'never',
},
],

'react/jsx-filename-extension': ['error', { extensions: ['.tsx', '.mdx'] }],
'react/jsx-filename-extension': [
'error',
{
extensions: ['.tsx', '.mdx'],
},
],
'react/jsx-props-no-spreading': 'off',
'react/require-default-props': 'off',
'react/no-unused-prop-types': 'off',

'jsx-a11y/no-static-element-interactions': 'off',
},
};
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ _/

# storybook
storybook-static/
.env
16 changes: 15 additions & 1 deletion .storybook/main.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,23 @@
module.exports = {
stories: ['../examples/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/preset-create-react-app',
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
],
framework: '@storybook/react',
typescript: {
check: false,
checkOptions: {},
reactDocgen: 'react-docgen-typescript',
reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop) =>
prop.parent ? !/node_modules/.test(prop.parent.fileName) : true,
},
},
framework: {
name: '@storybook/react-webpack5',
options: {},
},
};
11 changes: 11 additions & 0 deletions .storybook/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = ({ config, mode }) => {
config.module.rules.push({
test: /\.(ts|tsx)$/,
loader: require.resolve('babel-loader'),
options: {
presets: [['react-app', { flow: false, typescript: true }]],
},
});
config.resolve.extensions.push('.ts', '.tsx');
return config;
};
54 changes: 52 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const Demo = () => {

#### `lineRenderer`: ({ index: number, active: boolean, line: Line }) => React.ReactNode

The method to render every valid line of parsed lrc. `active` means whether it is current line. `Line` is `LrcLine` when using `Lrc` component or is `MultipleLrcLine` when `MultipleLrc`.
The method to render every valid line of parsed lrc. `active` means whether it is current line. `Line` is `LrcLine` when using `Lrc` component, is `EnhancedLrcLine` when `EnhancedLrc` or is `MultipleLrcLine` when `MultipleLrc`.

#### `currentMillisecond`?: number

Expand All @@ -59,7 +59,7 @@ with verticalSpace:

#### `onLineUpdate`?: ({ index: number, line: Line | null }) => void

Call this when current line changed. `Line` is `LrcLine` when using `Lrc` component or is `MultipleLrcLine` when `MultipleLrc`.
Call this when current line changed. `Line` is `LrcLine` when using `Lrc` component, is `EnhancedLrcLine` when `EnhancedLrc`, or is `MultipleLrcLine` when `MultipleLrc`.

#### `recoverAutoScrollInterval`

Expand All @@ -71,6 +71,12 @@ The interval of recovering auto scroll after user scroll. It is `millisecond`, d

The lrc.

### Component `EnhancedLrc`

#### `lrc`: string

The lrc.

### Component `MultipleLrc`

#### `lrcs`: string[]
Expand Down Expand Up @@ -135,4 +141,48 @@ const Demo = () => {

## License

[MIT](./LICENSE)

<Lrc {...otherProps} recoverAutoScrollSingal={signal} />
</>
);
};
```

## Q & A

### How to prevent user scroll ?

```jsx
<Lrc
style={{ overflow: 'hidden !important' }}
recoverAutoScrollInterval={0}
{...otherProps}
/>
```

### How to hide scrollbar ?

```scss
.lrc {
/* webkit */
&::-webkit-scrollbar {
width: 0;
height: 0;
}

/* firefox */
scrollbar-width: none;

/* ie */
-ms-overflow-style: none;
}
```

```jsx
<Lrc className="lrc" {...otherProps} />
```

## License

[MIT](./LICENSE)
12 changes: 12 additions & 0 deletions examples/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,15 @@ export const translatedLrc = `[00:13.62]错过了末班电车,我们并肩站
[03:32.43]花了太长的时间,我才察觉到真正重要的是什么
[03:37.38]再不要放开相牵的手,留在我身边
[03:44.58]再次和你携手`;

export const extraLrc = `
[00:00.00]Little <00:00.79>jagged <00:01.35>edge<00:02.46>
[00:02.71]I'm <00:03.10>leaning <00:04.01>in <00:04.80>again<00:05.67>
[00:05.92]I <00:06.40>felt <00:06.74>it <00:07.06>when <00:07.58>you <00:08.02>said<00:08.79>
[00:09.04]That <00:09.55>I am <00:10.22>just <00:10.75>a <00:11.14>mess<00:11.85>
[00:12.10]There was <00:12.65>nothing <00:13.25>I <00:13.96>could <00:14.22>do<00:15.36>
[00:15.61]But <00:15.91>see <00:16.25>your <00:16.61>point <00:17.03>of <00:17.31>view<00:18.21>
[00:19.24]<00:19.28>
[00:19.49]And <00:19.73>that's <00:20.19>the <00:20.40>truth<00:21.29>
[00:22.88]<00:22.92>
`;
104 changes: 104 additions & 0 deletions examples/enhanced_lrc/auto_scroll.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
/* eslint-disable react/no-unstable-nested-components */
import React, { CSSProperties } from 'react';
import styled from 'styled-components';
import { EnhancedLrc, useRecoverAutoScrollImmediately } from '../..';
import Control from '../control';
import useTimer from '../use_timer';

const Root = styled.div`
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;

display: flex;
flex-direction: column;

> .lrc-box {
position: relative;

flex: 1;
min-height: 0;

&::before {
content: '';
width: 100%;
height: 1px;

position: absolute;
top: 50%;
left: 0;

background: rgb(255 0 0 / 0.15);
}
}
`;
const lrcStyle: CSSProperties = {
height: '100%',
padding: '5px 0',
};

const Line = styled.div`
min-height: 10px;
padding: 5px 20px;

font-size: 16px;
text-align: center;
`;

function LrcDemo({
lrc,
recoverAutoScrollInterval,
verticalSpace,
}: {
lrc: string;
recoverAutoScrollInterval: number;
verticalSpace: boolean;
}) {
const { currentMillisecond, setCurrentMillisecond, reset, play, pause } =
useTimer(1);
const { signal, recoverAutoScrollImmediately } =
useRecoverAutoScrollImmediately();

return (
<Root>
<Control
onPlay={play}
onPause={pause}
onReset={reset}
current={currentMillisecond}
setCurrent={setCurrentMillisecond}
recoverAutoScrollImmediately={recoverAutoScrollImmediately}
/>
<div className="lrc-box">
<EnhancedLrc
lrc={lrc}
lineRenderer={({ active, line: { syllables } }) => (
<Line>
{syllables.map((s) => (
<span
style={{
color:
active && s.startMillisecond < currentMillisecond
? 'red'
: 'black',
}}
>
{s.content}
</span>
))}
</Line>
)}
currentMillisecond={currentMillisecond}
verticalSpace={verticalSpace}
style={lrcStyle}
recoverAutoScrollSingal={signal}
recoverAutoScrollInterval={recoverAutoScrollInterval}
/>
</div>
</Root>
);
}

export default LrcDemo;
37 changes: 37 additions & 0 deletions examples/enhanced_lrc/index.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/* eslint-disable react/function-component-definition */
import { StoryObj } from '@storybook/react';
import { extraLrc } from '../data';
import AutoScrollComponent from './auto_scroll';
import StaticComponent from './static';
import { Renderer } from '../utils';

type CompArgs = {
lrc: string;
recoverAutoScrollInterval?: number;
verticalSpace?: boolean;
};

export default {
title: 'EnhancedLrc',
component: Renderer<CompArgs>,
};

export const AutoScroll: StoryObj<typeof Renderer<CompArgs>> = {
args: {
compArgs: {
lrc: extraLrc,
recoverAutoScrollInterval: 5000,
verticalSpace: true,
},
component: AutoScrollComponent,
},
};

export const Static: StoryObj<typeof Renderer<CompArgs>> = {
args: {
compArgs: {
lrc: extraLrc,
},
component: StaticComponent,
},
};
Loading