mirror of
https://github.com/strapi/strapi.git
synced 2025-12-25 06:04:29 +00:00
Move utils to old/utils, done trigger container
This commit is contained in:
parent
5e9591edcf
commit
b8a60d7d0e
@ -4,6 +4,25 @@ import { TextButton } from '@strapi/parts/TextButton';
|
||||
import { Field, FieldArray, useFormikContext } from 'formik';
|
||||
import React from 'react';
|
||||
import { useIntl } from 'react-intl';
|
||||
import styled from 'styled-components';
|
||||
import { pxToRem } from '@strapi/helper-plugin';
|
||||
|
||||
const StyledIconButton = styled(IconButton)(
|
||||
({ theme }) => `
|
||||
border-radius: ${pxToRem(30)};
|
||||
width: ${pxToRem(20)};
|
||||
height: ${pxToRem(20)};
|
||||
padding: ${pxToRem(3)};
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
svg {
|
||||
width: ${pxToRem(8)};
|
||||
rect {
|
||||
fill: ${theme.colors.primary600}
|
||||
}
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
const HeadersInput = () => {
|
||||
const { formatMessage } = useIntl();
|
||||
@ -46,6 +65,7 @@ const HeadersInput = () => {
|
||||
<Field
|
||||
as={TextInput}
|
||||
name={`headers.${i}.key`}
|
||||
aria-label={`row ${i + 1} key`}
|
||||
error={
|
||||
errors.headers?.[i]?.key && formatMessage({ id: errors.headers[i]?.key })
|
||||
}
|
||||
@ -56,6 +76,7 @@ const HeadersInput = () => {
|
||||
<Box style={{ flex: 1 }}>
|
||||
<Field
|
||||
as={TextInput}
|
||||
aria-label={`row ${i + 1} value`}
|
||||
name={`headers.${i}.value`}
|
||||
error={
|
||||
errors.headers?.[i]?.value &&
|
||||
@ -64,13 +85,16 @@ const HeadersInput = () => {
|
||||
/>
|
||||
</Box>
|
||||
<Box paddingLeft={2}>
|
||||
<IconButton
|
||||
<StyledIconButton
|
||||
onClick={() => values.headers.length !== 1 && remove(i)}
|
||||
label={formatMessage({
|
||||
id: 'Settings.webhooks.events.update',
|
||||
})}
|
||||
label={formatMessage(
|
||||
{
|
||||
id: 'Settings.webhooks.headers.remove',
|
||||
defaultMessage: 'Remove header row {number}',
|
||||
},
|
||||
{ number: i + 1 }
|
||||
)}
|
||||
icon={<Autoselect />}
|
||||
noBorder
|
||||
/>
|
||||
</Box>
|
||||
</Row>
|
||||
|
||||
@ -1,36 +1,53 @@
|
||||
import React from 'react';
|
||||
import { CheckIcon, ClearField, Close, LoadingIcon } from '@strapi/icons';
|
||||
import { Box, Grid, GridItem, Row, Stack, Text } from '@strapi/parts';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { Fail, Success, Pending, Remove } from '@buffetjs/icons';
|
||||
import { Grid, GridItem } from '@strapi/parts';
|
||||
import styled from 'styled-components';
|
||||
|
||||
// Being discussed in Notion: create a <Icon /> component in Parts
|
||||
const Icon = styled.svg(
|
||||
({ theme, color }) => `
|
||||
width: ${12 / 16}rem;
|
||||
height: ${12 / 16}rem;
|
||||
|
||||
path {
|
||||
fill: ${theme.colors[color]};
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
const Status = ({ isPending, statusCode }) => {
|
||||
if (isPending) {
|
||||
return (
|
||||
<>
|
||||
<Pending fill="#ffb500" width="15px" height="15px" />
|
||||
<FormattedMessage id="Settings.webhooks.trigger.pending" defaultMessage="pending" />
|
||||
</>
|
||||
<Stack horizontal size={2} style={{ alignItems: 'center' }}>
|
||||
<Icon as={LoadingIcon} />
|
||||
<Text>
|
||||
<FormattedMessage id="Settings.webhooks.trigger.pending" defaultMessage="pending" />
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
return (
|
||||
<>
|
||||
<Success fill="#6DBB1A" width="19px" height="19px" />
|
||||
<FormattedMessage id="Settings.webhooks.trigger.success" defaultMessage="success" />
|
||||
</>
|
||||
<Stack horizontal size={2} style={{ alignItems: 'center' }}>
|
||||
<Icon as={CheckIcon} color="success700" />
|
||||
<Text>
|
||||
<FormattedMessage id="Settings.webhooks.trigger.success" defaultMessage="success" />
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
if (statusCode >= 300) {
|
||||
return (
|
||||
<>
|
||||
<Fail fill="#f64d0a" width="15px" height="15px" />
|
||||
<FormattedMessage id="Settings.error" defaultMessage="error" />
|
||||
|
||||
{statusCode}
|
||||
</>
|
||||
<Stack horizontal size={2} style={{ alignItems: 'center' }}>
|
||||
<Icon as={Close} color="danger700" />
|
||||
<Text>
|
||||
<FormattedMessage id="Settings.error" defaultMessage="error" /> {statusCode}
|
||||
</Text>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@ -47,31 +64,53 @@ Status.defaultProps = {
|
||||
const Message = ({ statusCode, message }) => {
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
return (
|
||||
<>
|
||||
<FormattedMessage id="Settings.webhooks.trigger.success.label" defaultMessage="success" />
|
||||
</>
|
||||
<Row justifyContent="flex-end">
|
||||
<Text>
|
||||
<FormattedMessage id="Settings.webhooks.trigger.success.label" defaultMessage="success" />
|
||||
</Text>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
if (statusCode >= 300) {
|
||||
return <p title={message}>{message}</p>;
|
||||
return (
|
||||
<Row justifyContent="flex-end" title={message}>
|
||||
<Text
|
||||
// ! REMOVE THIS WHEN DS IS UPDATED WITH ELLIPSIS PROP
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
whiteSpace: 'nowrap',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{message}
|
||||
</Text>
|
||||
</Row>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
Message.propTypes = {
|
||||
statusCode: PropTypes.number,
|
||||
message: PropTypes.string.isRequired,
|
||||
message: PropTypes.string,
|
||||
};
|
||||
Message.defaultProps = {
|
||||
statusCode: undefined,
|
||||
message: undefined,
|
||||
};
|
||||
|
||||
const CancelButton = ({ onCancel }) => (
|
||||
<button onClick={onCancel} type="button">
|
||||
<FormattedMessage id="Settings.webhooks.trigger.cancel" defaultMessage="cancel" />
|
||||
<Remove fill="#b4b6ba" />
|
||||
</button>
|
||||
<Row justifyContent="flex-end">
|
||||
<button onClick={onCancel} type="button">
|
||||
<Stack horizontal size={2} style={{ alignItems: 'center' }}>
|
||||
<Text textColor="neutral400">
|
||||
<FormattedMessage id="Settings.webhooks.trigger.cancel" defaultMessage="cancel" />
|
||||
</Text>
|
||||
<Icon as={ClearField} color="neutral400" />
|
||||
</Stack>
|
||||
</button>
|
||||
</Row>
|
||||
);
|
||||
CancelButton.propTypes = { onCancel: PropTypes.func.isRequired };
|
||||
|
||||
@ -79,21 +118,25 @@ const TriggerContainer = ({ isPending, onCancel, response }) => {
|
||||
const { statusCode, message } = response;
|
||||
|
||||
return (
|
||||
<Grid gap={4}>
|
||||
<GridItem col={3}>
|
||||
<FormattedMessage id="Settings.webhooks.trigger.test" defaultMessage="test-trigger" />
|
||||
</GridItem>
|
||||
<GridItem col={3}>
|
||||
<Status isPending={isPending} statusCode={statusCode} />
|
||||
</GridItem>
|
||||
<GridItem col={6}>
|
||||
{!isPending ? (
|
||||
<Message statusCode={statusCode} message={message} />
|
||||
) : (
|
||||
<CancelButton onCancel={onCancel} />
|
||||
)}
|
||||
</GridItem>
|
||||
</Grid>
|
||||
<Box background="neutral0" padding={5} shadow="filterShadow" hasRadius>
|
||||
<Grid gap={4} style={{ alignItems: 'center' }}>
|
||||
<GridItem col={3}>
|
||||
<Text>
|
||||
<FormattedMessage id="Settings.webhooks.trigger.test" defaultMessage="test-trigger" />
|
||||
</Text>
|
||||
</GridItem>
|
||||
<GridItem col={3}>
|
||||
<Status isPending={isPending} statusCode={statusCode} />
|
||||
</GridItem>
|
||||
<GridItem col={6}>
|
||||
{!isPending ? (
|
||||
<Message statusCode={statusCode} message={message} />
|
||||
) : (
|
||||
<CancelButton onCancel={onCancel} />
|
||||
)}
|
||||
</GridItem>
|
||||
</Grid>
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@ -41,6 +41,7 @@ const EditView = () => {
|
||||
const {
|
||||
params: { id },
|
||||
} = useRouteMatch('/settings/webhooks/:id');
|
||||
|
||||
const { formatMessage } = useIntl();
|
||||
const { replace } = useHistory();
|
||||
const { lockApp, unlockApp } = useOverlayBlocker();
|
||||
@ -74,9 +75,13 @@ const EditView = () => {
|
||||
|
||||
const triggerWebhookFn = useCallback(
|
||||
async id => {
|
||||
const abortController = new AbortController();
|
||||
const { signal } = abortController;
|
||||
|
||||
const [err, { data }] = await to(
|
||||
request(`/admin/webhooks/${id}/trigger`, {
|
||||
method: 'POST',
|
||||
signal,
|
||||
})
|
||||
);
|
||||
|
||||
@ -87,6 +92,8 @@ const EditView = () => {
|
||||
});
|
||||
}
|
||||
|
||||
data.cancel = () => abortController.abort();
|
||||
|
||||
return data;
|
||||
},
|
||||
[toggleNotification]
|
||||
@ -237,45 +244,47 @@ const EditView = () => {
|
||||
as="h1"
|
||||
/>
|
||||
<ContentLayout>
|
||||
{(isTriggering || !isTriggerIdle) && (
|
||||
<div className="trigger-wrapper">
|
||||
<TriggerContainer
|
||||
isPending={isTriggering}
|
||||
response={triggerResponse}
|
||||
onCancel={() => {}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Box background="neutral0" padding={8} shadow="filterShadow" hasRadius>
|
||||
<Stack size={6}>
|
||||
<Grid gap={6}>
|
||||
<GridItem col={6}>
|
||||
<Field
|
||||
as={TextInput}
|
||||
name="name"
|
||||
error={errors.name && formatMessage({ id: errors.name })}
|
||||
label={formatMessage({
|
||||
id: 'Settings.webhooks.form.name',
|
||||
defaultMessage: 'Name',
|
||||
})}
|
||||
/>
|
||||
</GridItem>
|
||||
<GridItem col={12}>
|
||||
<Field
|
||||
as={TextInput}
|
||||
name="url"
|
||||
error={errors.url && formatMessage({ id: errors.url })}
|
||||
label={formatMessage({
|
||||
id: 'Settings.roles.form.input.url',
|
||||
defaultMessage: 'Url',
|
||||
})}
|
||||
/>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
<HeadersInput />
|
||||
<EventInput isDraftAndPublish={isDraftAndPublishEvents} />
|
||||
</Stack>
|
||||
</Box>
|
||||
<Stack size={4}>
|
||||
{(isTriggering || !isTriggerIdle) && (
|
||||
<div className="trigger-wrapper">
|
||||
<TriggerContainer
|
||||
isPending={isTriggering}
|
||||
response={triggerResponse}
|
||||
onCancel={triggerResponse?.cancel}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Box background="neutral0" padding={8} shadow="filterShadow" hasRadius>
|
||||
<Stack size={6}>
|
||||
<Grid gap={6}>
|
||||
<GridItem col={6}>
|
||||
<Field
|
||||
as={TextInput}
|
||||
name="name"
|
||||
error={errors.name && formatMessage({ id: errors.name })}
|
||||
label={formatMessage({
|
||||
id: 'Settings.webhooks.form.name',
|
||||
defaultMessage: 'Name',
|
||||
})}
|
||||
/>
|
||||
</GridItem>
|
||||
<GridItem col={12}>
|
||||
<Field
|
||||
as={TextInput}
|
||||
name="url"
|
||||
error={errors.url && formatMessage({ id: errors.url })}
|
||||
label={formatMessage({
|
||||
id: 'Settings.roles.form.input.url',
|
||||
defaultMessage: 'Url',
|
||||
})}
|
||||
/>
|
||||
</GridItem>
|
||||
</Grid>
|
||||
<HeadersInput />
|
||||
<EventInput isDraftAndPublish={isDraftAndPublishEvents} />
|
||||
</Stack>
|
||||
</Box>
|
||||
</Stack>
|
||||
</ContentLayout>
|
||||
</Form>
|
||||
)}
|
||||
|
||||
@ -161,6 +161,7 @@
|
||||
"Settings.sso.title": "Single Sign-On",
|
||||
"Settings.webhooks.create": "Create a webhook",
|
||||
"Settings.webhooks.create.header": "Create a new header",
|
||||
"Settings.webhooks.headers.remove": "Remove header row {number}",
|
||||
"Settings.webhooks.created": "Webhook created",
|
||||
"Settings.webhooks.disabled": "Disabled",
|
||||
"Settings.webhooks.enabled": "Enabled",
|
||||
|
||||
@ -3,7 +3,7 @@ import { Redirect } from 'react-router-dom';
|
||||
import PropTypes from 'prop-types';
|
||||
import useNotification from '../../hooks/useNotification';
|
||||
import useRBACProvider from '../../hooks/useRBACProvider';
|
||||
import hasPermissions from '../../utils/hasPermissions';
|
||||
import hasPermissions from '../../old/utils/hasPermissions';
|
||||
import LoadingIndicatorPage from '../LoadingIndicatorPage';
|
||||
|
||||
const CheckPagePermissions = ({ permissions, children }) => {
|
||||
|
||||
@ -2,7 +2,7 @@ import { useEffect, useRef, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import useNotification from '../../hooks/useNotification';
|
||||
|
||||
import hasPermissions from '../../utils/hasPermissions';
|
||||
import hasPermissions from '../../old/utils/hasPermissions';
|
||||
import useRBACProvider from '../../hooks/useRBACProvider';
|
||||
|
||||
// NOTE: this component is very similar to the CheckPagePermissions
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { useCallback, useEffect, useMemo, useReducer, useRef } from 'react';
|
||||
import hasPermissions from '../../utils/hasPermissions';
|
||||
import hasPermissions from '../../old/utils/hasPermissions';
|
||||
|
||||
import generateResultsObject from './utils/generateResultsObject';
|
||||
import reducer from './reducer';
|
||||
|
||||
@ -134,33 +134,35 @@ export { default as NotificationsProvider } from './providers/NotificationsProvi
|
||||
export { default as StrapiAppProvider } from './providers/StrapiAppProvider';
|
||||
|
||||
// Utils
|
||||
export { default as auth } from './utils/auth';
|
||||
export { default as cleanData } from './utils/cleanData';
|
||||
export { default as difference } from './utils/difference';
|
||||
export { default as auth } from './old/utils/auth';
|
||||
export { default as cleanData } from './old/utils/cleanData';
|
||||
export { default as difference } from './old/utils/difference';
|
||||
export { default as contentManagementUtilRemoveFieldsFromData } from './content-manager/utils/contentManagementUtilRemoveFieldsFromData';
|
||||
export { default as dateFormats } from './utils/dateFormats';
|
||||
export { default as dateToUtcTime } from './utils/dateToUtcTime';
|
||||
export { default as dateFormats } from './old/utils/dateFormats';
|
||||
export { default as dateToUtcTime } from './old/utils/dateToUtcTime';
|
||||
export { default as formatComponentData } from './content-manager/utils/formatComponentData';
|
||||
export { default as hasPermissions } from './utils/hasPermissions';
|
||||
export { findMatchingPermissions } from './utils/hasPermissions';
|
||||
export { default as translatedErrors } from './utils/translatedErrors';
|
||||
export { default as to } from './utils/await-to-js';
|
||||
export { darken } from './utils/colors';
|
||||
export { default as getFileExtension } from './utils/getFileExtension';
|
||||
export { default as getFilterType } from './utils/getFilterType';
|
||||
export { default as getQueryParameters } from './utils/getQueryParameters';
|
||||
export { default as validateInput } from './utils/inputsValidations';
|
||||
export { default as request } from './utils/request';
|
||||
export { default as storeData } from './utils/storeData';
|
||||
export { default as templateObject } from './utils/templateObject';
|
||||
export { default as hasPermissions } from './old/utils/hasPermissions';
|
||||
export { findMatchingPermissions } from './old/utils/hasPermissions';
|
||||
export { default as translatedErrors } from './old/utils/translatedErrors';
|
||||
export { darken } from './old/utils/colors';
|
||||
export { default as getFileExtension } from './old/utils/getFileExtension';
|
||||
export { default as getFilterType } from './old/utils/getFilterType';
|
||||
export { default as getQueryParameters } from './old/utils/getQueryParameters';
|
||||
export { default as validateInput } from './old/utils/inputsValidations';
|
||||
export { default as request } from './old/utils/request';
|
||||
export { default as storeData } from './old/utils/storeData';
|
||||
export { default as templateObject } from './old/utils/templateObject';
|
||||
export { getType };
|
||||
export { getOtherInfos };
|
||||
export { default as getYupInnerErrors } from './utils/getYupInnerErrors';
|
||||
export { default as generateFiltersFromSearch } from './utils/generateFiltersFromSearch';
|
||||
export { default as generateSearchFromFilters } from './utils/generateSearchFromFilters';
|
||||
export { default as generateSearchFromObject } from './utils/generateSearchFromObject';
|
||||
export { default as prefixFileUrlWithBackendUrl } from './utils/prefixFileUrlWithBackendUrl';
|
||||
export { default as prefixPluginTranslations } from './utils/prefixPluginTranslations';
|
||||
export { default as getYupInnerErrors } from './old/utils/getYupInnerErrors';
|
||||
export { default as generateFiltersFromSearch } from './old/utils/generateFiltersFromSearch';
|
||||
export { default as generateSearchFromFilters } from './old/utils/generateSearchFromFilters';
|
||||
export { default as generateSearchFromObject } from './old/utils/generateSearchFromObject';
|
||||
export { default as prefixFileUrlWithBackendUrl } from './old/utils/prefixFileUrlWithBackendUrl';
|
||||
export { default as prefixPluginTranslations } from './old/utils/prefixPluginTranslations';
|
||||
|
||||
export { default as pxToRem } from './utils/pxToRem';
|
||||
export { default as to } from './utils/await-to-js';
|
||||
|
||||
// SVGS
|
||||
export { default as LayoutIcon } from './old/svgs/Layout';
|
||||
|
||||
@ -11,7 +11,7 @@ import { map } from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
// Utils
|
||||
import { darken } from '../../../utils/colors';
|
||||
import { darken } from '../../utils/colors';
|
||||
import Wrapper from './Wrapper';
|
||||
|
||||
function HeaderNav({ links, style }) {
|
||||
|
||||
@ -10,7 +10,7 @@ import { isEmpty, isFunction } from 'lodash';
|
||||
import cn from 'classnames';
|
||||
|
||||
// Utils
|
||||
import validateInput from '../../../utils/inputsValidations';
|
||||
import validateInput from '../../utils/inputsValidations';
|
||||
|
||||
// Design
|
||||
import Label from '../Label';
|
||||
|
||||
@ -10,7 +10,7 @@ import { isEmpty, isFunction } from 'lodash';
|
||||
import cn from 'classnames';
|
||||
|
||||
// Utils
|
||||
import validateInput from '../../../utils/inputsValidations';
|
||||
import validateInput from '../../utils/inputsValidations';
|
||||
|
||||
// Design
|
||||
import Label from '../Label';
|
||||
|
||||
@ -4,7 +4,7 @@ import { isEmpty, isFunction } from 'lodash';
|
||||
import cn from 'classnames';
|
||||
|
||||
// Utils
|
||||
import validateInput from '../../../utils/inputsValidations';
|
||||
import validateInput from '../../utils/inputsValidations';
|
||||
|
||||
// Design
|
||||
import Label from '../Label';
|
||||
|
||||
@ -10,7 +10,7 @@ import { isEmpty, isFunction } from 'lodash';
|
||||
import cn from 'classnames';
|
||||
|
||||
// Utils
|
||||
import validateInput from '../../../utils/inputsValidations';
|
||||
import validateInput from '../../utils/inputsValidations';
|
||||
|
||||
// Design
|
||||
import Label from '../Label';
|
||||
|
||||
@ -10,7 +10,7 @@ import { isEmpty, isFunction } from 'lodash';
|
||||
import cn from 'classnames';
|
||||
|
||||
// Utils
|
||||
import validateInput from '../../../utils/inputsValidations';
|
||||
import validateInput from '../../utils/inputsValidations';
|
||||
|
||||
// Design
|
||||
import Label from '../Label';
|
||||
|
||||
@ -4,7 +4,7 @@ import { isEmpty, isFunction } from 'lodash';
|
||||
import cn from 'classnames';
|
||||
|
||||
// Utils
|
||||
import validateInput from '../../../utils/inputsValidations';
|
||||
import validateInput from '../../utils/inputsValidations';
|
||||
|
||||
// Design
|
||||
import Label from '../Label';
|
||||
|
||||
@ -4,7 +4,7 @@ import { isEmpty, isFunction } from 'lodash';
|
||||
import cn from 'classnames';
|
||||
|
||||
// Utils
|
||||
import validateInput from '../../../utils/inputsValidations';
|
||||
import validateInput from '../../utils/inputsValidations';
|
||||
|
||||
// Design
|
||||
import Label from '../Label';
|
||||
|
||||
@ -3,7 +3,7 @@ import { useIntl } from 'react-intl';
|
||||
import { Inputs } from '@buffetjs/custom';
|
||||
import PropTypes from 'prop-types';
|
||||
import { isObject } from 'lodash';
|
||||
import translatedErrors from '../../../utils/translatedErrors';
|
||||
import translatedErrors from '../../utils/translatedErrors';
|
||||
|
||||
const IntlInput = ({
|
||||
description,
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
<!--- await-to-js.stories.mdx --->
|
||||
|
||||
import { Meta } from '@storybook/addon-docs';
|
||||
|
||||
<Meta title="utils/await-to-js" />
|
||||
|
||||
# await-to-js
|
||||
|
||||
Async await wrapper for easy error handling
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
import { to } from '@strapi/helper-plugin';
|
||||
|
||||
const [err, response] = await to(promise);
|
||||
|
||||
if (err) {
|
||||
throw new Error(err)
|
||||
}
|
||||
|
||||
...else continue
|
||||
|
||||
```
|
||||
@ -0,0 +1,3 @@
|
||||
const pxToRem = px => `${px / 16}rem`;
|
||||
|
||||
export default pxToRem;
|
||||
@ -0,0 +1,27 @@
|
||||
<!--- pxToRem.stories.mdx --->
|
||||
|
||||
import { Meta } from '@storybook/addon-docs';
|
||||
|
||||
<Meta title="utils/pxToRem" />
|
||||
|
||||
# pxToRem
|
||||
|
||||
Converts px to rem.
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
import { pxToRem } from '@strapi/helper-plugin';
|
||||
import { Box } from '@strapi/parts';
|
||||
import styled from 'styled-components'
|
||||
|
||||
const StyledBox = styled(Box)`
|
||||
width: ${pxToRem}
|
||||
`
|
||||
|
||||
const HomePage = () =>
|
||||
return (
|
||||
<StyledBox>I'm a sized box</StyledBox>
|
||||
);
|
||||
};
|
||||
```
|
||||
Loading…
x
Reference in New Issue
Block a user