diff --git a/README.md b/README.md
index 42a0e24..b90c02b 100644
--- a/README.md
+++ b/README.md
@@ -201,6 +201,7 @@ Available options in useEpg
| `isSidebar` | `boolean` | optional | Show/hide sidebar |
| `isTimeline` | `boolean` | optional | Show/hide timeline |
| `isLine` | `boolean` | optional | Show/hide line |
+| `isRTL` | `boolean` | optional | Change direction to RTL or LTR. Default value is false |
| `theme` | `object` | optional | Object with theme schema |
#### Note about width and height props
@@ -412,6 +413,76 @@ function App() {
export default App;
```
+## renderProgram - RTL direction
+
+Below is an example that allows you to render your custom Program component with RTL direction using Plaby's style components.
+
+```tsx
+...
+const Item = ({ program, ...rest }: ProgramItem) => {
+ const {
+ isRTL,
+ isLive,
+ isMinWidth,
+ formatTime,
+ styles,
+ set12HoursTimeFormat,
+ getRTLSinceTime,
+ getRTLTillTime,
+ } = useProgram({
+ program,
+ ...rest
+ });
+
+ const { data } = program;
+ const { image, title, since, till } = data;
+
+ const sinceTime = formatTime(
+ getRTLSinceTime(since),
+ set12HoursTimeFormat()
+ ).toLowerCase();
+ const tillTime = formatTime(
+ getRTLTillTime(till),
+ set12HoursTimeFormat()
+ ).toLowerCase();
+
+ return (
+
+
+
+ {isLive && isMinWidth && }
+
+ {title}
+
+ {sinceTime} - {tillTime}
+
+
+
+
+
+ );
+};
+
+function App() {
+
+ ...
+
+ const {
+ getEpgProps,
+ getLayoutProps,
+} = useEpg({
+ epg,
+ channels,
+ isBaseTimeFormat: true,
+ startDate: '2022/02/02', // or 2022-02-02T00:00:00
+});
+
+...
+}
+
+export default App;
+```
+
## renderChannel
Below is an example that allows you to render your custom Channel component using Plaby's style components.
@@ -561,6 +632,60 @@ function App() {
export default App;
```
+## renderTimeline - RTL direction
+
+Below is an example that allows you to render your custom Timeline component using Plaby's style components.
+
+```tsx
+import {
+ TimelineWrapper,
+ TimelineBox,
+ TimelineTime,
+ TimelineDivider,
+ TimelineDividers,
+ useTimeline,
+} from 'planby';
+
+interface TimelineProps {
+ isRTL: boolean;
+ isBaseTimeFormat: boolean;
+ isSidebar: boolean;
+ dayWidth: number;
+ hourWidth: number;
+ numberOfHoursInDay: number;
+ offsetStartHoursRange: number;
+ sidebarWidth: number;
+}
+
+export function Timeline({
+ isRTL,
+ isBaseTimeFormat,
+ isSidebar,
+ dayWidth,
+ hourWidth,
+ numberOfHoursInDay,
+ offsetStartHoursRange,
+ sidebarWidth,
+}: TimelineProps) {
+ const { time, dividers, formatTime } = useTimeline(
+ numberOfHoursInDay,
+ isBaseTimeFormat
+ );
+
+ const renderTime = (index: number) => (
+
+
+ {formatTime(index + offsetStartHoursRange).toLowerCase()}
+
+ {renderDividers()}
+
+ );
+
+ ...
+}
+
+```
+
## Theme
### Schema
diff --git a/package.json b/package.json
index 79a53fb..810ba68 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "planby",
"author": "Karol Kozer",
- "version": "0.3.0",
+ "version": "0.4.0",
"license": "MIT",
"repository": {
"type": "git",
diff --git a/src/Epg/Epg.tsx b/src/Epg/Epg.tsx
index f1b02e0..325cc59 100644
--- a/src/Epg/Epg.tsx
+++ b/src/Epg/Epg.tsx
@@ -16,6 +16,7 @@ import { Loader } from "./components";
interface EpgProps {
width?: number;
height?: number;
+ isRTL?: boolean;
isSidebar: boolean;
isTimeline?: boolean;
isLoading?: boolean;
@@ -35,6 +36,7 @@ export const Epg = React.forwardRef(
height,
theme,
sidebarWidth,
+ isRTL = false,
isSidebar = true,
isTimeline = true,
isLoading = false,
@@ -57,6 +59,7 @@ export const Epg = React.forwardRef(
{isSidebar && isTimeline && (
boolean;
channels: ChannelWithPosiiton[];
scrollY: number;
sidebarWidth: number;
- isTimeline: boolean;
- isChannelVisible: (position: any) => boolean;
renderChannel?: (v: { channel: ChannelWithPosiiton }) => React.ReactNode;
}
@@ -21,7 +22,7 @@ const { Box } = ChannelsStyled;
export function Channels(props: ChannelsProps) {
const { channels, scrollY, sidebarWidth, renderChannel } = props;
- const { isTimeline, isChannelVisible } = props;
+ const { isRTL, isTimeline, isChannelVisible } = props;
const renderChannels = (channel: ChannelWithPosiiton) => {
const isVisible = isChannelVisible(channel.position);
@@ -35,8 +36,9 @@ export function Channels(props: ChannelsProps) {
return (
{channels.map(renderChannels)}
diff --git a/src/Epg/components/Layout.tsx b/src/Epg/components/Layout.tsx
index a8accc1..71cfa17 100644
--- a/src/Epg/components/Layout.tsx
+++ b/src/Epg/components/Layout.tsx
@@ -20,12 +20,13 @@ import { EpgStyled } from "../styles";
import { Timeline, Channels, Program, Line } from "../components";
interface RenderTimeline {
+ isBaseTimeFormat: BaseTimeFormat;
+ isSidebar: boolean;
+ isRTL: boolean;
sidebarWidth: number;
hourWidth: number;
numberOfHoursInDay: number;
offsetStartHoursRange: number;
- isBaseTimeFormat: BaseTimeFormat;
- isSidebar: boolean;
dayWidth: number;
}
@@ -44,6 +45,7 @@ interface LayoutProps {
onScroll: (
e: React.UIEvent & { target: Element }
) => void;
+ isRTL?: boolean;
isBaseTimeFormat?: BaseTimeFormat;
isSidebar?: boolean;
isTimeline?: boolean;
@@ -52,6 +54,7 @@ interface LayoutProps {
isChannelVisible: (position: Pick) => boolean;
renderProgram?: (v: {
program: ProgramItem;
+ isRTL: boolean;
isBaseTimeFormat: BaseTimeFormat;
}) => React.ReactNode;
renderChannel?: (v: { channel: ChannelWithPosiiton }) => React.ReactNode;
@@ -70,6 +73,7 @@ export const Layout = React.forwardRef(
isTimeline = true,
isLine = true,
isBaseTimeFormat = false,
+ isRTL = false,
} = props;
const {
@@ -97,11 +101,13 @@ export const Layout = React.forwardRef(
if (renderProgram)
return renderProgram({
program: options,
+ isRTL,
isBaseTimeFormat,
});
return (
@@ -112,9 +118,10 @@ export const Layout = React.forwardRef(
const renderTopbar = () => {
const props = {
+ sidebarWidth,
+ isSidebar,
+ isRTL,
dayWidth,
- sidebarWidth: sidebarWidth,
- isSidebar: isSidebar,
numberOfHoursInDay,
};
const timeProps = {
@@ -130,7 +137,7 @@ export const Layout = React.forwardRef(
};
return (
-
+
{isLine && isFuture && (
(
{isTimeline && renderTopbar()}
{isSidebar && (
{
- program: T;
+ isRTL?: boolean;
isBaseTimeFormat: BaseTimeFormat;
+ program: T;
onClick?: (v: ProgramType) => void;
}
@@ -31,19 +32,21 @@ const {
export function Program({
program,
- isBaseTimeFormat,
onClick,
...rest
}: ProgramProps) {
const {
+ isRTL,
+ isLive,
+ isMinWidth,
styles,
formatTime,
set12HoursTimeFormat,
- isLive,
- isMinWidth,
+ getRTLSinceTime,
+ getRTLTillTime,
} = useProgram({
program,
- isBaseTimeFormat,
+ ...rest,
});
const { data } = program;
@@ -51,6 +54,15 @@ export function Program({
const handleOnContentClick = () => onClick?.(data);
+ const sinceTime = formatTime(
+ getRTLSinceTime(since),
+ set12HoursTimeFormat()
+ ).toLowerCase();
+ const tillTime = formatTime(
+ getRTLTillTime(till),
+ set12HoursTimeFormat()
+ ).toLowerCase();
+
return (
({
>
{isLive && isMinWidth && }
-
+
{title}
- {formatTime(since, set12HoursTimeFormat())} -{" "}
- {formatTime(till, set12HoursTimeFormat())}
+ {sinceTime} - {tillTime}
diff --git a/src/Epg/components/Timeline.tsx b/src/Epg/components/Timeline.tsx
index d38dd07..f5e655a 100644
--- a/src/Epg/components/Timeline.tsx
+++ b/src/Epg/components/Timeline.tsx
@@ -18,6 +18,7 @@ const {
} = TimelineStyled;
interface TimelineProps {
+ isRTL?: boolean;
isBaseTimeFormat: BaseTimeFormat;
isSidebar: boolean;
dayWidth: number;
@@ -28,6 +29,7 @@ interface TimelineProps {
}
export function Timeline({
+ isRTL,
isBaseTimeFormat,
isSidebar,
dayWidth,
@@ -43,7 +45,9 @@ export function Timeline({
const renderTime = (index: number) => (
- {formatTime(index + offsetStartHoursRange)}
+
+ {formatTime(index + offsetStartHoursRange)}
+
{renderDividers()}
);
diff --git a/src/Epg/hooks/__tests__/useProgram.test.tsx b/src/Epg/hooks/__tests__/useProgram.test.tsx
index fd21d74..8716535 100644
--- a/src/Epg/hooks/__tests__/useProgram.test.tsx
+++ b/src/Epg/hooks/__tests__/useProgram.test.tsx
@@ -11,8 +11,11 @@ const defaultState = ({ overrides, styles }: DefaultState = {}) => {
return {
formatTime: expect.any(Function),
set12HoursTimeFormat: expect.any(Function),
+ getRTLSinceTime: expect.any(Function),
+ getRTLTillTime: expect.any(Function),
isLive: false,
isMinWidth: true,
+ isRTL: false,
styles,
...overrides,
};
@@ -41,7 +44,11 @@ test("should return generated props from useTimeline", () => {
test("should specify an initial state in useTimeline", () => {
const program = buildProgramWithPosition();
- const props = { program, isBaseTimeFormat: true, minWidth: 800 };
+ const props = {
+ program,
+ isBaseTimeFormat: true,
+ minWidth: 800,
+ };
const { result } = renderHook(() => useProgram(props));
const options = {
...getStyles(program),
diff --git a/src/Epg/hooks/useEpg.tsx b/src/Epg/hooks/useEpg.tsx
index 2d04fdd..cd6a23d 100644
--- a/src/Epg/hooks/useEpg.tsx
+++ b/src/Epg/hooks/useEpg.tsx
@@ -42,6 +42,7 @@ interface useEpgProps {
isBaseTimeFormat?: BaseTimeFormat;
isSidebar?: boolean;
isTimeline?: boolean;
+ isRTL?: boolean;
isLine?: boolean;
theme?: Theme;
dayWidth?: number;
@@ -57,6 +58,7 @@ export function useEpg({
epg,
startDate: startDateInput = defaultStartDateTime,
endDate: endDateInput = "",
+ isRTL = false,
isBaseTimeFormat = false,
isSidebar = true,
isTimeline = true,
@@ -93,8 +95,13 @@ export function useEpg({
});
const { scrollX, scrollY, layoutWidth, layoutHeight } = layoutProps;
- const { onScroll, onScrollToNow, onScrollTop, onScrollLeft, onScrollRight } =
- layoutProps;
+ const {
+ onScroll,
+ onScrollToNow,
+ onScrollTop,
+ onScrollLeft,
+ onScrollRight,
+ } = layoutProps;
//-------- Variables --------
const channels = React.useMemo(
@@ -140,11 +147,12 @@ export function useEpg({
);
const getEpgProps = () => ({
- width,
- height,
+ isRTL,
isSidebar,
isLine,
isTimeline,
+ width,
+ height,
sidebarWidth,
ref: containerRef,
theme,
@@ -157,6 +165,7 @@ export function useEpg({
endDate,
scrollY,
onScroll,
+ isRTL,
isBaseTimeFormat,
isSidebar,
isTimeline,
diff --git a/src/Epg/hooks/useProgram.tsx b/src/Epg/hooks/useProgram.tsx
index 3934bc0..c518780 100644
--- a/src/Epg/hooks/useProgram.tsx
+++ b/src/Epg/hooks/useProgram.tsx
@@ -12,13 +12,15 @@ import { useInterval } from "./useInterval";
interface useProgramProps {
program: T;
+ isRTL?: boolean;
isBaseTimeFormat: BaseTimeFormat;
minWidth?: number;
}
export function useProgram({
- program,
+ isRTL = false,
isBaseTimeFormat,
+ program,
minWidth = 200,
}: useProgramProps) {
const { data, position } = program;
@@ -41,6 +43,11 @@ export function useProgram({
return TIME_FORMAT.HOURS_MIN;
};
+ const getRTLSinceTime = (since: string | number | Date) =>
+ isRTL ? till : since;
+ const getRTLTillTime = (till: string | number | Date) =>
+ isRTL ? since : till;
+
useInterval(() => {
const status = getLiveStatus(since, till);
setIsLive(status);
@@ -49,10 +56,13 @@ export function useProgram({
const isMinWidth = width > minWidth;
return {
- formatTime,
- set12HoursTimeFormat,
isLive,
isMinWidth,
+ isRTL,
+ formatTime,
+ set12HoursTimeFormat,
+ getRTLSinceTime,
+ getRTLTillTime,
styles: { width, position: newPosition },
};
}
diff --git a/src/Epg/index.ts b/src/Epg/index.ts
index 7c91447..7e3828b 100644
--- a/src/Epg/index.ts
+++ b/src/Epg/index.ts
@@ -14,6 +14,7 @@ export type Channel = ChannelWithPosiiton;
export type Program = ProgramItemType;
export type ProgramItem = {
program: ProgramItemType;
+ isRTL: boolean;
isBaseTimeFormat: BaseTimeFormatType;
};
diff --git a/src/Epg/styles/Channels.styles.ts b/src/Epg/styles/Channels.styles.ts
index 754848d..e6208a7 100644
--- a/src/Epg/styles/Channels.styles.ts
+++ b/src/Epg/styles/Channels.styles.ts
@@ -2,8 +2,9 @@ import styled from "@emotion/styled/macro";
import { Theme } from "../helpers";
export const Box = styled.div<{
- width: number;
isTimeline: boolean;
+ isRTL: boolean;
+ width: number;
bottom: number;
theme?: Theme;
}>`
@@ -14,4 +15,6 @@ export const Box = styled.div<{
left: 0;
z-index: 100;
background-color: ${({ theme }) => theme.primary[900]};
+
+ ${({ isRTL }) => isRTL && `transform: scale(-1,1)`};
`;
diff --git a/src/Epg/styles/Epg.styles.ts b/src/Epg/styles/Epg.styles.ts
index bffaac7..7bcf6d7 100644
--- a/src/Epg/styles/Epg.styles.ts
+++ b/src/Epg/styles/Epg.styles.ts
@@ -20,7 +20,7 @@ export const Wrapper = styled.div`
overflow: hidden;
`;
-export const ScrollBox = styled.div<{ theme?: Theme }>`
+export const ScrollBox = styled.div<{ theme?: Theme; isRTL?: boolean }>`
height: 100%;
width: 100%;
position: relative;
@@ -28,6 +28,8 @@ export const ScrollBox = styled.div<{ theme?: Theme }>`
scroll-behavior: smooth;
background: ${({ theme }) => theme.primary[900]};
+ ${({ isRTL }) => isRTL && `transform: scale(-1,1)`};
+
::-webkit-scrollbar {
width: 10px;
height: 10px;
@@ -54,6 +56,7 @@ export const ScrollBox = styled.div<{ theme?: Theme }>`
`;
export const Box = styled.div<{
+ isRTL?: boolean;
width: number;
height: number;
left?: number;
@@ -64,9 +67,10 @@ export const Box = styled.div<{
height: ${({ height }) => height}px;
width: ${({ width }) => width}px;
top: ${({ top = 0 }) => top}px;
- left: ${({ left = 0 }) => left}px;
background: ${({ theme }) => theme.primary[900]};
z-index: 900;
+
+ ${({ isRTL, left = 0 }) => (isRTL ? `right:0px;` : ` left: ${left}px`)};
`;
export const Content = styled.div<{
diff --git a/src/Epg/styles/Program.styles.ts b/src/Epg/styles/Program.styles.ts
index ee5b816..9a47231 100644
--- a/src/Epg/styles/Program.styles.ts
+++ b/src/Epg/styles/Program.styles.ts
@@ -72,6 +72,12 @@ export const ProgramImage = styled.img`
width: 100px;
`;
-export const ProgramStack = styled.div`
+export const ProgramStack = styled.div<{ isRTL?: boolean }>`
overflow: hidden;
+ ${({ isRTL }) =>
+ isRTL &&
+ `transform: scale(-1,1);
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end`};
`;
diff --git a/src/Epg/styles/Timeline.styles.ts b/src/Epg/styles/Timeline.styles.ts
index 893a10f..77ebabf 100644
--- a/src/Epg/styles/Timeline.styles.ts
+++ b/src/Epg/styles/Timeline.styles.ts
@@ -4,11 +4,18 @@ import { Theme } from "../helpers";
// Import heleprs
import { ITEM_HEIGHT } from "../helpers";
-export const TimelineTime = styled.span<{ theme?: Theme }>`
+export const TimelineTime = styled.span<{
+ theme?: Theme;
+ isBaseTimeFormat?: boolean;
+ isRTL?: boolean;
+}>`
color: ${({ theme }) => theme.text.grey[300]};
position: absolute;
top: 18px;
- left: -18px;
+ left: ${({ isRTL, isBaseTimeFormat }) =>
+ isRTL && isBaseTimeFormat ? "-32" : "-18"}px;
+
+ ${({ isRTL }) => isRTL && `transform: scale(-1,1)`};
`;
export const TimelineDividers = styled.div`