@toptal/picasso-form-label 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-package/src/FormControlLabel/FormControlLabel.d.ts +23 -0
- package/dist-package/src/FormControlLabel/FormControlLabel.d.ts.map +1 -0
- package/dist-package/src/FormControlLabel/FormControlLabel.js +26 -0
- package/dist-package/src/FormControlLabel/FormControlLabel.js.map +1 -0
- package/dist-package/src/FormControlLabel/index.d.ts +5 -0
- package/dist-package/src/FormControlLabel/index.d.ts.map +1 -0
- package/dist-package/src/FormControlLabel/index.js +2 -0
- package/dist-package/src/FormControlLabel/index.js.map +1 -0
- package/dist-package/src/FormLabel/FormLabel.d.ts +30 -0
- package/dist-package/src/FormLabel/FormLabel.d.ts.map +1 -0
- package/dist-package/src/FormLabel/FormLabel.js +37 -0
- package/dist-package/src/FormLabel/FormLabel.js.map +1 -0
- package/dist-package/src/FormLabel/index.d.ts +6 -0
- package/dist-package/src/FormLabel/index.d.ts.map +1 -0
- package/dist-package/src/FormLabel/index.js +2 -0
- package/dist-package/src/FormLabel/index.js.map +1 -0
- package/dist-package/src/FormLabel/styles.d.ts +12 -0
- package/dist-package/src/FormLabel/styles.d.ts.map +1 -0
- package/dist-package/src/FormLabel/styles.js +24 -0
- package/dist-package/src/FormLabel/styles.js.map +1 -0
- package/dist-package/src/index.d.ts +5 -0
- package/dist-package/src/index.d.ts.map +1 -0
- package/dist-package/src/index.js +3 -0
- package/dist-package/src/index.js.map +1 -0
- package/package.json +53 -0
- package/src/FormControlLabel/FormControlLabel.tsx +84 -0
- package/src/FormControlLabel/index.ts +6 -0
- package/src/FormLabel/FormLabel.tsx +106 -0
- package/src/FormLabel/__snapshots__/test.tsx.snap +146 -0
- package/src/FormLabel/index.ts +7 -0
- package/src/FormLabel/story/index.jsx +6 -0
- package/src/FormLabel/styles.ts +66 -0
- package/src/FormLabel/test.tsx +111 -0
- package/src/index.ts +5 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode, LabelHTMLAttributes } from 'react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import type { FormControlLabelProps } from '@material-ui/core/FormControlLabel';
|
|
4
|
+
import type { StandardProps, TextLabelProps } from '@toptal/picasso-shared';
|
|
5
|
+
import type { RequiredDecoration } from '../FormLabel';
|
|
6
|
+
export declare type FormControlLabelAttributesType = LabelHTMLAttributes<HTMLLabelElement> & Pick<FormControlLabelProps, 'onChange'>;
|
|
7
|
+
export interface Props extends StandardProps, TextLabelProps, FormControlLabelAttributesType {
|
|
8
|
+
/** A control element. For instance, it can be be a Radio or a Checkbox */
|
|
9
|
+
control: ReactElement;
|
|
10
|
+
/** The text to be used in an enclosing label element */
|
|
11
|
+
label?: ReactNode;
|
|
12
|
+
/** Shows whether label is disabled or not */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Whether to show asterisk or (optional) postfix as a 'required' decoration */
|
|
15
|
+
requiredDecoration?: RequiredDecoration;
|
|
16
|
+
classes?: {
|
|
17
|
+
root?: string;
|
|
18
|
+
label?: string;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
declare const FormControlLabel: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLLabelElement>>;
|
|
22
|
+
export default FormControlLabel;
|
|
23
|
+
//# sourceMappingURL=FormControlLabel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormControlLabel.d.ts","sourceRoot":"","sources":["../../../src/FormControlLabel/FormControlLabel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,MAAM,OAAO,CAAA;AACzE,OAAO,KAAqB,MAAM,OAAO,CAAA;AACzC,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAA;AAC/E,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAI3E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAGtD,oBAAY,8BAA8B,GACxC,mBAAmB,CAAC,gBAAgB,CAAC,GACnC,IAAI,CAAC,qBAAqB,EAAE,UAAU,CAAC,CAAA;AAE3C,MAAM,WAAW,KACf,SAAQ,aAAa,EACnB,cAAc,EACd,8BAA8B;IAChC,0EAA0E;IAC1E,OAAO,EAAE,YAAY,CAAA;IACrB,wDAAwD;IACxD,KAAK,CAAC,EAAE,SAAS,CAAA;IACjB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC,OAAO,CAAC,EAAE;QACR,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,KAAK,CAAC,EAAE,MAAM,CAAA;KACf,CAAA;CACF;AAED,QAAA,MAAM,gBAAgB,gFA+CrB,CAAA;AAID,eAAe,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import React, { forwardRef } from 'react';
|
|
13
|
+
import { twMerge } from '@toptal/picasso-tailwind-merge';
|
|
14
|
+
import { useFieldsLayoutContext } from '@toptal/picasso-form-layout';
|
|
15
|
+
import { FormLabel } from '../FormLabel';
|
|
16
|
+
const FormControlLabel = forwardRef(function FormControlLabel(props, ref) {
|
|
17
|
+
const { control, label, className, style, disabled, requiredDecoration, titleCase, classes } = props, rest = __rest(props, ["control", "label", "className", "style", "disabled", "requiredDecoration", "titleCase", "classes"]);
|
|
18
|
+
const { layout } = useFieldsLayoutContext();
|
|
19
|
+
const isHorizontalLayout = layout === 'horizontal';
|
|
20
|
+
return (React.createElement("label", Object.assign({}, rest, { ref: ref, className: twMerge('inline-flex items-center', 'max-w-full', 'align-middle', '-webkit-tap-highlight-color-transparent', 'mx-0', disabled ? 'cursor-default' : 'cursor-pointer', isHorizontalLayout && 'col-start-1 col-span-2', classes === null || classes === void 0 ? void 0 : classes.root, className), style: style }),
|
|
21
|
+
React.cloneElement(control, { disabled }),
|
|
22
|
+
React.createElement(FormLabel, { className: twMerge(disabled && 'pointer-events-auto', classes === null || classes === void 0 ? void 0 : classes.label), as: 'span', requiredDecoration: requiredDecoration, disabled: disabled, titleCase: titleCase }, label)));
|
|
23
|
+
});
|
|
24
|
+
FormControlLabel.displayName = 'FormControlLabel';
|
|
25
|
+
export default FormControlLabel;
|
|
26
|
+
//# sourceMappingURL=FormControlLabel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormControlLabel.js","sourceRoot":"","sources":["../../../src/FormControlLabel/FormControlLabel.tsx"],"names":[],"mappings":";;;;;;;;;;;AACA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAGzC,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAGpE,OAAO,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAwBxC,MAAM,gBAAgB,GAAG,UAAU,CACjC,SAAS,gBAAgB,CAAC,KAAK,EAAE,GAAG;IAClC,MAAM,EACJ,OAAO,EACP,KAAK,EACL,SAAS,EACT,KAAK,EACL,QAAQ,EACR,kBAAkB,EAClB,SAAS,EACT,OAAO,KAEL,KAAK,EADJ,IAAI,UACL,KAAK,EAVH,oGAUL,CAAQ,CAAA;IAET,MAAM,EAAE,MAAM,EAAE,GAAG,sBAAsB,EAAE,CAAA;IAC3C,MAAM,kBAAkB,GAAG,MAAM,KAAK,YAAY,CAAA;IAElD,OAAO,CACL,+CACM,IAAI,IACR,GAAG,EAAE,GAAG,EACR,SAAS,EAAE,OAAO,CAChB,0BAA0B,EAC1B,YAAY,EACZ,cAAc,EACd,yCAAyC,EACzC,MAAM,EACN,QAAQ,CAAC,CAAC,CAAC,gBAAgB,CAAC,CAAC,CAAC,gBAAgB,EAC9C,kBAAkB,IAAI,wBAAwB,EAC9C,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,IAAI,EACb,SAAS,CACV,EACD,KAAK,EAAE,KAAK;QAEX,KAAK,CAAC,YAAY,CAAC,OAAO,EAAE,EAAE,QAAQ,EAAE,CAAC;QAC1C,oBAAC,SAAS,IACR,SAAS,EAAE,OAAO,CAAC,QAAQ,IAAI,qBAAqB,EAAE,OAAO,aAAP,OAAO,uBAAP,OAAO,CAAE,KAAK,CAAC,EACrE,EAAE,EAAC,MAAM,EACT,kBAAkB,EAAE,kBAAkB,EACtC,QAAQ,EAAE,QAAQ,EAClB,SAAS,EAAE,SAAS,IAEnB,KAAK,CACI,CACN,CACT,CAAA;AACH,CAAC,CACF,CAAA;AAED,gBAAgB,CAAC,WAAW,GAAG,kBAAkB,CAAA;AAEjD,eAAe,gBAAgB,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { OmitInternalProps } from '@toptal/picasso-shared';
|
|
2
|
+
import type { Props } from './FormControlLabel';
|
|
3
|
+
export { default as FormControlLabel } from './FormControlLabel';
|
|
4
|
+
export declare type FormControlLabelProps = OmitInternalProps<Props>;
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/FormControlLabel/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAA;AAE/C,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAChE,oBAAY,qBAAqB,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/FormControlLabel/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import type { BaseProps, TextLabelProps, SizeType } from '@toptal/picasso-shared';
|
|
4
|
+
declare type ComponentType = 'label' | 'span';
|
|
5
|
+
export declare type RequiredDecoration = 'asterisk' | 'optional';
|
|
6
|
+
export declare type Size = SizeType<'medium' | 'large'>;
|
|
7
|
+
export declare type Alignment = 'top' | 'middle';
|
|
8
|
+
export interface Props extends BaseProps, TextLabelProps, HTMLAttributes<HTMLLabelElement | HTMLSpanElement> {
|
|
9
|
+
/** Content of the label */
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
/** Whether to show asterisk or (optional) postfix as a 'required' decoration */
|
|
12
|
+
requiredDecoration?: RequiredDecoration;
|
|
13
|
+
/** Is this label for disabled input or not */
|
|
14
|
+
disabled?: boolean;
|
|
15
|
+
/** Specifies an id of the input */
|
|
16
|
+
htmlFor?: string;
|
|
17
|
+
/** Whether label should act as inline element `display: inline-block` */
|
|
18
|
+
inline?: boolean;
|
|
19
|
+
/** Component used for the root node */
|
|
20
|
+
as?: ComponentType;
|
|
21
|
+
/** Component size */
|
|
22
|
+
size?: Size;
|
|
23
|
+
/** Whether label should be aligned to top of the container or not */
|
|
24
|
+
alignment?: Alignment;
|
|
25
|
+
/** Label's end adornment */
|
|
26
|
+
labelEndAdornment?: ReactNode;
|
|
27
|
+
}
|
|
28
|
+
export declare const FormLabel: React.ForwardRefExoticComponent<Props & React.RefAttributes<HTMLLabelElement>>;
|
|
29
|
+
export default FormLabel;
|
|
30
|
+
//# sourceMappingURL=FormLabel.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormLabel.d.ts","sourceRoot":"","sources":["../../../src/FormLabel/FormLabel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,OAAO,CAAA;AACtD,OAAO,KAAqB,MAAM,OAAO,CAAA;AACzC,OAAO,KAAK,EACV,SAAS,EACT,cAAc,EACd,QAAQ,EACT,MAAM,wBAAwB,CAAA;AAQ/B,aAAK,aAAa,GAAG,OAAO,GAAG,MAAM,CAAA;AACrC,oBAAY,kBAAkB,GAAG,UAAU,GAAG,UAAU,CAAA;AAExD,oBAAY,IAAI,GAAG,QAAQ,CAAC,QAAQ,GAAG,OAAO,CAAC,CAAA;AAC/C,oBAAY,SAAS,GAAG,KAAK,GAAG,QAAQ,CAAA;AAExC,MAAM,WAAW,KACf,SAAQ,SAAS,EACf,cAAc,EACd,cAAc,CAAC,gBAAgB,GAAG,eAAe,CAAC;IACpD,2BAA2B;IAC3B,QAAQ,EAAE,SAAS,CAAA;IACnB,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,kBAAkB,CAAA;IACvC,8CAA8C;IAC9C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,yEAAyE;IACzE,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,uCAAuC;IACvC,EAAE,CAAC,EAAE,aAAa,CAAA;IAClB,qBAAqB;IACrB,IAAI,CAAC,EAAE,IAAI,CAAA;IACX,qEAAqE;IACrE,SAAS,CAAC,EAAE,SAAS,CAAA;IACrB,4BAA4B;IAC5B,iBAAiB,CAAC,EAAE,SAAS,CAAA;CAC9B;AAED,eAAO,MAAM,SAAS,gFAmDpB,CAAA;AAUF,eAAe,SAAS,CAAA"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
var __rest = (this && this.__rest) || function (s, e) {
|
|
2
|
+
var t = {};
|
|
3
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
4
|
+
t[p] = s[p];
|
|
5
|
+
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
6
|
+
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
7
|
+
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
8
|
+
t[p[i]] = s[p[i]];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
import React, { forwardRef } from 'react';
|
|
13
|
+
import { useTitleCase } from '@toptal/picasso-shared';
|
|
14
|
+
import { toTitleCase } from '@toptal/picasso-utils';
|
|
15
|
+
import { twMerge } from '@toptal/picasso-tailwind-merge';
|
|
16
|
+
import { useFieldsLayoutContext } from '@toptal/picasso-form-layout';
|
|
17
|
+
import { classesBySize, getRootClasses } from './styles';
|
|
18
|
+
export const FormLabel = forwardRef(function FormLabel(props, ref) {
|
|
19
|
+
const { children, disabled, htmlFor, className, style, inline, as: Component = 'label', titleCase: propsTitleCase, requiredDecoration, size = 'medium', alignment = 'middle', labelEndAdornment } = props, rest = __rest(props, ["children", "disabled", "htmlFor", "className", "style", "inline", "as", "titleCase", "requiredDecoration", "size", "alignment", "labelEndAdornment"]);
|
|
20
|
+
const isInline = inline || Component === 'span';
|
|
21
|
+
const titleCase = useTitleCase(propsTitleCase);
|
|
22
|
+
const { layout } = useFieldsLayoutContext();
|
|
23
|
+
return (React.createElement(Component, Object.assign({}, rest, { ref: ref, htmlFor: htmlFor, className: twMerge(getRootClasses({ disabled, isInline, layout, alignment }), className), style: style }),
|
|
24
|
+
React.createElement("span", { className: isInline ? 'align-top text-[0.8125rem]' : classesBySize[size] },
|
|
25
|
+
requiredDecoration === 'asterisk' && (React.createElement("span", { className: 'align-top text-red-500 mr-[0.3125em]' }, "*")),
|
|
26
|
+
titleCase ? toTitleCase(children) : children,
|
|
27
|
+
requiredDecoration === 'optional' && ' (optional)',
|
|
28
|
+
labelEndAdornment)));
|
|
29
|
+
});
|
|
30
|
+
FormLabel.defaultProps = {
|
|
31
|
+
as: 'label',
|
|
32
|
+
inline: false,
|
|
33
|
+
size: 'medium',
|
|
34
|
+
};
|
|
35
|
+
FormLabel.displayName = 'FormLabel';
|
|
36
|
+
export default FormLabel;
|
|
37
|
+
//# sourceMappingURL=FormLabel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FormLabel.js","sourceRoot":"","sources":["../../../src/FormLabel/FormLabel.tsx"],"names":[],"mappings":";;;;;;;;;;;AACA,OAAO,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,OAAO,CAAA;AAMzC,OAAO,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAA;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAA;AACnD,OAAO,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,6BAA6B,CAAA;AAEpE,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,UAAU,CAAA;AAgCxD,MAAM,CAAC,MAAM,SAAS,GAAG,UAAU,CAA0B,SAAS,SAAS,CAC7E,KAAK,EACL,GAAG;IAEH,MAAM,EACJ,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,SAAS,EACT,KAAK,EACL,MAAM,EACN,EAAE,EAAE,SAAS,GAAG,OAAO,EACvB,SAAS,EAAE,cAAc,EACzB,kBAAkB,EAClB,IAAI,GAAG,QAAQ,EACf,SAAS,GAAG,QAAQ,EACpB,iBAAiB,KAEf,KAAK,EADJ,IAAI,UACL,KAAK,EAdH,sJAcL,CAAQ,CAAA;IACT,MAAM,QAAQ,GAAG,MAAM,IAAI,SAAS,KAAK,MAAM,CAAA;IAC/C,MAAM,SAAS,GAAG,YAAY,CAAC,cAAc,CAAC,CAAA;IAC9C,MAAM,EAAE,MAAM,EAAE,GAAG,sBAAsB,EAAE,CAAA;IAE3C,OAAO,CACL,oBAAC,SAAS,oBACJ,IAAI,IACR,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,OAAO,EAChB,SAAS,EAAE,OAAO,CAChB,cAAc,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EACzD,SAAS,CACV,EACD,KAAK,EAAE,KAAK;QAEZ,8BACE,SAAS,EACP,QAAQ,CAAC,CAAC,CAAC,4BAA4B,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC;YAG9D,kBAAkB,KAAK,UAAU,IAAI,CACpC,8BAAM,SAAS,EAAC,sCAAsC,QAAS,CAChE;YAEA,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ;YAE5C,kBAAkB,KAAK,UAAU,IAAI,aAAa;YAElD,iBAAiB,CACb,CACG,CACb,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,SAAS,CAAC,YAAY,GAAG;IACvB,EAAE,EAAE,OAAO;IACX,MAAM,EAAE,KAAK;IACb,IAAI,EAAE,QAAQ;CACf,CAAA;AAED,SAAS,CAAC,WAAW,GAAG,WAAW,CAAA;AAEnC,eAAe,SAAS,CAAA"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { OmitInternalProps } from '@toptal/picasso-shared';
|
|
2
|
+
import type { Props } from './FormLabel';
|
|
3
|
+
export { default as FormLabel } from './FormLabel';
|
|
4
|
+
export type { RequiredDecoration } from './FormLabel';
|
|
5
|
+
export declare type FormLabelProps = OmitInternalProps<Props>;
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/FormLabel/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAE/D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAExC,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAA;AAClD,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrD,oBAAY,cAAc,GAAG,iBAAiB,CAAC,KAAK,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/FormLabel/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { FieldLayout } from '@toptal/picasso-form-layout';
|
|
2
|
+
import type { Alignment, Size } from './FormLabel';
|
|
3
|
+
export declare const classesBySize: Record<Size, string>;
|
|
4
|
+
declare type GetRootClassesOptions = {
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
isInline: boolean;
|
|
7
|
+
layout: FieldLayout;
|
|
8
|
+
alignment: Alignment;
|
|
9
|
+
};
|
|
10
|
+
export declare const getRootClasses: ({ disabled, isInline, layout, alignment, }: GetRootClassesOptions) => string;
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=styles.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.d.ts","sourceRoot":"","sources":["../../../src/FormLabel/styles.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAA;AAE9D,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAElD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,IAAI,EAAE,MAAM,CAG9C,CAAA;AAED,aAAK,qBAAqB,GAAG;IAC3B,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,EAAE,WAAW,CAAA;IACnB,SAAS,EAAE,SAAS,CAAA;CACrB,CAAA;AAqCD,eAAO,MAAM,cAAc,+CAKxB,qBAAqB,WAQvB,CAAA"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { twJoin } from '@toptal/picasso-tailwind-merge';
|
|
2
|
+
export const classesBySize = {
|
|
3
|
+
medium: 'text-[0.875rem]',
|
|
4
|
+
large: 'text-[1rem]',
|
|
5
|
+
};
|
|
6
|
+
const getDisplayClasses = ({ isInline, layout, alignment, }) => {
|
|
7
|
+
if (layout === 'horizontal' && alignment === 'top') {
|
|
8
|
+
return 'flex items-start';
|
|
9
|
+
}
|
|
10
|
+
if (layout === 'horizontal') {
|
|
11
|
+
return 'flex items-center';
|
|
12
|
+
}
|
|
13
|
+
if (isInline) {
|
|
14
|
+
return 'inline-block';
|
|
15
|
+
}
|
|
16
|
+
return 'block';
|
|
17
|
+
};
|
|
18
|
+
const getMarginClasses = ({ layout, isInline, }) => layout === 'horizontal' || isInline ? 'mb-0' : 'mb-[0.5em]';
|
|
19
|
+
const getPaddingsClasses = ({ layout, alignment, }) => layout === 'horizontal' && alignment === 'top' ? 'pt-2' : '';
|
|
20
|
+
const getColorClasses = ({ disabled }) => disabled ? 'text-graphite-700/[0.48]' : 'text-graphite-700';
|
|
21
|
+
export const getRootClasses = ({ disabled, isInline, layout, alignment, }) => {
|
|
22
|
+
return twJoin(getDisplayClasses({ isInline, layout, alignment }), 'leading-[1em]', getMarginClasses({ layout, isInline }), getColorClasses({ disabled }), getPaddingsClasses({ layout, alignment }));
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=styles.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"styles.js","sourceRoot":"","sources":["../../../src/FormLabel/styles.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,gCAAgC,CAAA;AAKvD,MAAM,CAAC,MAAM,aAAa,GAAyB;IACjD,MAAM,EAAE,iBAAiB;IACzB,KAAK,EAAE,aAAa;CACrB,CAAA;AASD,MAAM,iBAAiB,GAAG,CAAC,EACzB,QAAQ,EACR,MAAM,EACN,SAAS,GACsB,EAAE,EAAE;IACnC,IAAI,MAAM,KAAK,YAAY,IAAI,SAAS,KAAK,KAAK,EAAE;QAClD,OAAO,kBAAkB,CAAA;KAC1B;IAED,IAAI,MAAM,KAAK,YAAY,EAAE;QAC3B,OAAO,mBAAmB,CAAA;KAC3B;IAED,IAAI,QAAQ,EAAE;QACZ,OAAO,cAAc,CAAA;KACtB;IAED,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAED,MAAM,gBAAgB,GAAG,CAAC,EACxB,MAAM,EACN,QAAQ,GACuB,EAAE,EAAE,CACnC,MAAM,KAAK,YAAY,IAAI,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAA;AAE7D,MAAM,kBAAkB,GAAG,CAAC,EAC1B,MAAM,EACN,SAAS,GACsB,EAAE,EAAE,CACnC,MAAM,KAAK,YAAY,IAAI,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAA;AAE9D,MAAM,eAAe,GAAG,CAAC,EAAE,QAAQ,EAAkC,EAAE,EAAE,CACvE,QAAQ,CAAC,CAAC,CAAC,0BAA0B,CAAC,CAAC,CAAC,mBAAmB,CAAA;AAE7D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,EAC7B,QAAQ,EACR,QAAQ,EACR,MAAM,EACN,SAAS,GACa,EAAE,EAAE;IAC1B,OAAO,MAAM,CACX,iBAAiB,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,EAClD,eAAe,EACf,gBAAgB,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EACtC,eAAe,CAAC,EAAE,QAAQ,EAAE,CAAC,EAC7B,kBAAkB,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC,CAC1C,CAAA;AACH,CAAC,CAAA"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { FormControlLabelProps } from './FormControlLabel';
|
|
2
|
+
export { FormControlLabel } from './FormControlLabel';
|
|
3
|
+
export type { FormLabelProps, RequiredDecoration } from './FormLabel';
|
|
4
|
+
export { FormLabel } from './FormLabel';
|
|
5
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAA;AAC/D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAErD,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACrE,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAGrD,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@toptal/picasso-form-label",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "Toptal UI components library - Form Label",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"main": "./dist-package/src/index.js",
|
|
9
|
+
"module": "./dist-package/src/index.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"build:package": "tsc -b tsconfig.json",
|
|
12
|
+
"prepublishOnly": "yarn build:package"
|
|
13
|
+
},
|
|
14
|
+
"repository": {
|
|
15
|
+
"type": "git",
|
|
16
|
+
"url": "git+https://github.com/toptal/picasso.git"
|
|
17
|
+
},
|
|
18
|
+
"author": "Toptal",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://github.com/toptal/picasso/issues"
|
|
22
|
+
},
|
|
23
|
+
"homepage": "https://github.com/toptal/picasso/tree/master/packages/picasso#readme",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@toptal/picasso-form-layout": "1.0.1",
|
|
26
|
+
"@toptal/picasso-shared": "15.0.0",
|
|
27
|
+
"@toptal/picasso-utils": "3.0.0",
|
|
28
|
+
"ap-style-title-case": "^1.1.2"
|
|
29
|
+
},
|
|
30
|
+
"sideEffects": [
|
|
31
|
+
"**/styles.ts",
|
|
32
|
+
"**/styles.js"
|
|
33
|
+
],
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"@material-ui/core": "4.12.4",
|
|
36
|
+
"@toptal/picasso-tailwind": ">=2.7",
|
|
37
|
+
"@toptal/picasso-tailwind-merge": "^2.0.0",
|
|
38
|
+
"react": ">=16.12.0 < 19.0.0"
|
|
39
|
+
},
|
|
40
|
+
"exports": {
|
|
41
|
+
".": "./dist-package/src/index.js",
|
|
42
|
+
"./src/FormLabel/story": "./src/FormLabel/story"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@toptal/picasso-tailwind-merge": "2.0.2",
|
|
46
|
+
"@toptal/picasso-test-utils": "1.1.1"
|
|
47
|
+
},
|
|
48
|
+
"files": [
|
|
49
|
+
"dist-package/**",
|
|
50
|
+
"!dist-package/tsconfig.tsbuildinfo",
|
|
51
|
+
"src"
|
|
52
|
+
]
|
|
53
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { ReactElement, ReactNode, LabelHTMLAttributes } from 'react'
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
|
+
import type { FormControlLabelProps } from '@material-ui/core/FormControlLabel'
|
|
4
|
+
import type { StandardProps, TextLabelProps } from '@toptal/picasso-shared'
|
|
5
|
+
import { twMerge } from '@toptal/picasso-tailwind-merge'
|
|
6
|
+
import { useFieldsLayoutContext } from '@toptal/picasso-form-layout'
|
|
7
|
+
|
|
8
|
+
import type { RequiredDecoration } from '../FormLabel'
|
|
9
|
+
import { FormLabel } from '../FormLabel'
|
|
10
|
+
|
|
11
|
+
export type FormControlLabelAttributesType =
|
|
12
|
+
LabelHTMLAttributes<HTMLLabelElement> &
|
|
13
|
+
Pick<FormControlLabelProps, 'onChange'>
|
|
14
|
+
|
|
15
|
+
export interface Props
|
|
16
|
+
extends StandardProps,
|
|
17
|
+
TextLabelProps,
|
|
18
|
+
FormControlLabelAttributesType {
|
|
19
|
+
/** A control element. For instance, it can be be a Radio or a Checkbox */
|
|
20
|
+
control: ReactElement
|
|
21
|
+
/** The text to be used in an enclosing label element */
|
|
22
|
+
label?: ReactNode
|
|
23
|
+
/** Shows whether label is disabled or not */
|
|
24
|
+
disabled?: boolean
|
|
25
|
+
/** Whether to show asterisk or (optional) postfix as a 'required' decoration */
|
|
26
|
+
requiredDecoration?: RequiredDecoration
|
|
27
|
+
classes?: {
|
|
28
|
+
root?: string
|
|
29
|
+
label?: string
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const FormControlLabel = forwardRef<HTMLLabelElement, Props>(
|
|
34
|
+
function FormControlLabel(props, ref) {
|
|
35
|
+
const {
|
|
36
|
+
control,
|
|
37
|
+
label,
|
|
38
|
+
className,
|
|
39
|
+
style,
|
|
40
|
+
disabled,
|
|
41
|
+
requiredDecoration,
|
|
42
|
+
titleCase,
|
|
43
|
+
classes,
|
|
44
|
+
...rest
|
|
45
|
+
} = props
|
|
46
|
+
|
|
47
|
+
const { layout } = useFieldsLayoutContext()
|
|
48
|
+
const isHorizontalLayout = layout === 'horizontal'
|
|
49
|
+
|
|
50
|
+
return (
|
|
51
|
+
<label
|
|
52
|
+
{...rest}
|
|
53
|
+
ref={ref}
|
|
54
|
+
className={twMerge(
|
|
55
|
+
'inline-flex items-center',
|
|
56
|
+
'max-w-full',
|
|
57
|
+
'align-middle',
|
|
58
|
+
'-webkit-tap-highlight-color-transparent',
|
|
59
|
+
'mx-0',
|
|
60
|
+
disabled ? 'cursor-default' : 'cursor-pointer',
|
|
61
|
+
isHorizontalLayout && 'col-start-1 col-span-2',
|
|
62
|
+
classes?.root,
|
|
63
|
+
className
|
|
64
|
+
)}
|
|
65
|
+
style={style}
|
|
66
|
+
>
|
|
67
|
+
{React.cloneElement(control, { disabled })}
|
|
68
|
+
<FormLabel
|
|
69
|
+
className={twMerge(disabled && 'pointer-events-auto', classes?.label)}
|
|
70
|
+
as='span'
|
|
71
|
+
requiredDecoration={requiredDecoration}
|
|
72
|
+
disabled={disabled}
|
|
73
|
+
titleCase={titleCase}
|
|
74
|
+
>
|
|
75
|
+
{label}
|
|
76
|
+
</FormLabel>
|
|
77
|
+
</label>
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
FormControlLabel.displayName = 'FormControlLabel'
|
|
83
|
+
|
|
84
|
+
export default FormControlLabel
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { HTMLAttributes, ReactNode } from 'react'
|
|
2
|
+
import React, { forwardRef } from 'react'
|
|
3
|
+
import type {
|
|
4
|
+
BaseProps,
|
|
5
|
+
TextLabelProps,
|
|
6
|
+
SizeType,
|
|
7
|
+
} from '@toptal/picasso-shared'
|
|
8
|
+
import { useTitleCase } from '@toptal/picasso-shared'
|
|
9
|
+
import { toTitleCase } from '@toptal/picasso-utils'
|
|
10
|
+
import { twMerge } from '@toptal/picasso-tailwind-merge'
|
|
11
|
+
import { useFieldsLayoutContext } from '@toptal/picasso-form-layout'
|
|
12
|
+
|
|
13
|
+
import { classesBySize, getRootClasses } from './styles'
|
|
14
|
+
|
|
15
|
+
type ComponentType = 'label' | 'span'
|
|
16
|
+
export type RequiredDecoration = 'asterisk' | 'optional'
|
|
17
|
+
|
|
18
|
+
export type Size = SizeType<'medium' | 'large'>
|
|
19
|
+
export type Alignment = 'top' | 'middle'
|
|
20
|
+
|
|
21
|
+
export interface Props
|
|
22
|
+
extends BaseProps,
|
|
23
|
+
TextLabelProps,
|
|
24
|
+
HTMLAttributes<HTMLLabelElement | HTMLSpanElement> {
|
|
25
|
+
/** Content of the label */
|
|
26
|
+
children: ReactNode
|
|
27
|
+
/** Whether to show asterisk or (optional) postfix as a 'required' decoration */
|
|
28
|
+
requiredDecoration?: RequiredDecoration
|
|
29
|
+
/** Is this label for disabled input or not */
|
|
30
|
+
disabled?: boolean
|
|
31
|
+
/** Specifies an id of the input */
|
|
32
|
+
htmlFor?: string
|
|
33
|
+
/** Whether label should act as inline element `display: inline-block` */
|
|
34
|
+
inline?: boolean
|
|
35
|
+
/** Component used for the root node */
|
|
36
|
+
as?: ComponentType
|
|
37
|
+
/** Component size */
|
|
38
|
+
size?: Size
|
|
39
|
+
/** Whether label should be aligned to top of the container or not */
|
|
40
|
+
alignment?: Alignment
|
|
41
|
+
/** Label's end adornment */
|
|
42
|
+
labelEndAdornment?: ReactNode
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const FormLabel = forwardRef<HTMLLabelElement, Props>(function FormLabel(
|
|
46
|
+
props,
|
|
47
|
+
ref
|
|
48
|
+
) {
|
|
49
|
+
const {
|
|
50
|
+
children,
|
|
51
|
+
disabled,
|
|
52
|
+
htmlFor,
|
|
53
|
+
className,
|
|
54
|
+
style,
|
|
55
|
+
inline,
|
|
56
|
+
as: Component = 'label',
|
|
57
|
+
titleCase: propsTitleCase,
|
|
58
|
+
requiredDecoration,
|
|
59
|
+
size = 'medium',
|
|
60
|
+
alignment = 'middle',
|
|
61
|
+
labelEndAdornment,
|
|
62
|
+
...rest
|
|
63
|
+
} = props
|
|
64
|
+
const isInline = inline || Component === 'span'
|
|
65
|
+
const titleCase = useTitleCase(propsTitleCase)
|
|
66
|
+
const { layout } = useFieldsLayoutContext()
|
|
67
|
+
|
|
68
|
+
return (
|
|
69
|
+
<Component
|
|
70
|
+
{...rest}
|
|
71
|
+
ref={ref}
|
|
72
|
+
htmlFor={htmlFor}
|
|
73
|
+
className={twMerge(
|
|
74
|
+
getRootClasses({ disabled, isInline, layout, alignment }),
|
|
75
|
+
className
|
|
76
|
+
)}
|
|
77
|
+
style={style}
|
|
78
|
+
>
|
|
79
|
+
<span
|
|
80
|
+
className={
|
|
81
|
+
isInline ? 'align-top text-[0.8125rem]' : classesBySize[size]
|
|
82
|
+
}
|
|
83
|
+
>
|
|
84
|
+
{requiredDecoration === 'asterisk' && (
|
|
85
|
+
<span className='align-top text-red-500 mr-[0.3125em]'>*</span>
|
|
86
|
+
)}
|
|
87
|
+
|
|
88
|
+
{titleCase ? toTitleCase(children) : children}
|
|
89
|
+
|
|
90
|
+
{requiredDecoration === 'optional' && ' (optional)'}
|
|
91
|
+
|
|
92
|
+
{labelEndAdornment}
|
|
93
|
+
</span>
|
|
94
|
+
</Component>
|
|
95
|
+
)
|
|
96
|
+
})
|
|
97
|
+
|
|
98
|
+
FormLabel.defaultProps = {
|
|
99
|
+
as: 'label',
|
|
100
|
+
inline: false,
|
|
101
|
+
size: 'medium',
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
FormLabel.displayName = 'FormLabel'
|
|
105
|
+
|
|
106
|
+
export default FormLabel
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`FormLabel disabled 1`] = `
|
|
4
|
+
<div>
|
|
5
|
+
<div
|
|
6
|
+
class="Picasso-root"
|
|
7
|
+
>
|
|
8
|
+
<form
|
|
9
|
+
class=""
|
|
10
|
+
>
|
|
11
|
+
<div
|
|
12
|
+
class="text-[1rem] [&+&]:mt-4"
|
|
13
|
+
data-field-has-error="false"
|
|
14
|
+
>
|
|
15
|
+
<label
|
|
16
|
+
class="block leading-[1em] mb-[0.5em] text-graphite"
|
|
17
|
+
>
|
|
18
|
+
<span
|
|
19
|
+
class="text-[0.875rem]"
|
|
20
|
+
>
|
|
21
|
+
Label
|
|
22
|
+
</span>
|
|
23
|
+
</label>
|
|
24
|
+
</div>
|
|
25
|
+
</form>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
`;
|
|
29
|
+
|
|
30
|
+
exports[`FormLabel renders 1`] = `
|
|
31
|
+
<div>
|
|
32
|
+
<div
|
|
33
|
+
class="Picasso-root"
|
|
34
|
+
>
|
|
35
|
+
<form
|
|
36
|
+
class=""
|
|
37
|
+
>
|
|
38
|
+
<div
|
|
39
|
+
class="text-[1rem] [&+&]:mt-4"
|
|
40
|
+
data-field-has-error="false"
|
|
41
|
+
>
|
|
42
|
+
<label
|
|
43
|
+
class="block leading-[1em] mb-[0.5em] text-graphite"
|
|
44
|
+
>
|
|
45
|
+
<span
|
|
46
|
+
class="text-[0.875rem]"
|
|
47
|
+
>
|
|
48
|
+
Label
|
|
49
|
+
</span>
|
|
50
|
+
</label>
|
|
51
|
+
</div>
|
|
52
|
+
</form>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
`;
|
|
56
|
+
|
|
57
|
+
exports[`FormLabel required with (optional) 1`] = `
|
|
58
|
+
<div>
|
|
59
|
+
<div
|
|
60
|
+
class="Picasso-root"
|
|
61
|
+
>
|
|
62
|
+
<form
|
|
63
|
+
class=""
|
|
64
|
+
>
|
|
65
|
+
<div
|
|
66
|
+
class="text-[1rem] [&+&]:mt-4"
|
|
67
|
+
data-field-has-error="false"
|
|
68
|
+
>
|
|
69
|
+
<label
|
|
70
|
+
class="block leading-[1em] mb-[0.5em] text-graphite"
|
|
71
|
+
>
|
|
72
|
+
<span
|
|
73
|
+
class="text-[0.875rem]"
|
|
74
|
+
>
|
|
75
|
+
Label
|
|
76
|
+
(optional)
|
|
77
|
+
</span>
|
|
78
|
+
</label>
|
|
79
|
+
</div>
|
|
80
|
+
</form>
|
|
81
|
+
</div>
|
|
82
|
+
</div>
|
|
83
|
+
`;
|
|
84
|
+
|
|
85
|
+
exports[`FormLabel required with (optional) and with \`labelEndAdornment\` 1`] = `
|
|
86
|
+
<div>
|
|
87
|
+
<div
|
|
88
|
+
class="Picasso-root"
|
|
89
|
+
>
|
|
90
|
+
<form
|
|
91
|
+
class=""
|
|
92
|
+
>
|
|
93
|
+
<div
|
|
94
|
+
class="text-[1rem] [&+&]:mt-4"
|
|
95
|
+
data-field-has-error="false"
|
|
96
|
+
>
|
|
97
|
+
<label
|
|
98
|
+
class="block leading-[1em] mb-[0.5em] text-graphite"
|
|
99
|
+
>
|
|
100
|
+
<span
|
|
101
|
+
class="text-[0.875rem]"
|
|
102
|
+
>
|
|
103
|
+
Label
|
|
104
|
+
(optional)
|
|
105
|
+
<span>
|
|
106
|
+
label end adornment
|
|
107
|
+
</span>
|
|
108
|
+
</span>
|
|
109
|
+
</label>
|
|
110
|
+
</div>
|
|
111
|
+
</form>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
`;
|
|
115
|
+
|
|
116
|
+
exports[`FormLabel required with asterisk 1`] = `
|
|
117
|
+
<div>
|
|
118
|
+
<div
|
|
119
|
+
class="Picasso-root"
|
|
120
|
+
>
|
|
121
|
+
<form
|
|
122
|
+
class=""
|
|
123
|
+
>
|
|
124
|
+
<div
|
|
125
|
+
class="text-[1rem] [&+&]:mt-4"
|
|
126
|
+
data-field-has-error="false"
|
|
127
|
+
>
|
|
128
|
+
<label
|
|
129
|
+
class="block leading-[1em] mb-[0.5em] text-graphite"
|
|
130
|
+
>
|
|
131
|
+
<span
|
|
132
|
+
class="text-[0.875rem]"
|
|
133
|
+
>
|
|
134
|
+
<span
|
|
135
|
+
class="align-top text-red mr-[0.3125em]"
|
|
136
|
+
>
|
|
137
|
+
*
|
|
138
|
+
</span>
|
|
139
|
+
Label
|
|
140
|
+
</span>
|
|
141
|
+
</label>
|
|
142
|
+
</div>
|
|
143
|
+
</form>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
`;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { OmitInternalProps } from '@toptal/picasso-shared'
|
|
2
|
+
|
|
3
|
+
import type { Props } from './FormLabel'
|
|
4
|
+
|
|
5
|
+
export { default as FormLabel } from './FormLabel'
|
|
6
|
+
export type { RequiredDecoration } from './FormLabel'
|
|
7
|
+
export type FormLabelProps = OmitInternalProps<Props>
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { twJoin } from '@toptal/picasso-tailwind-merge'
|
|
2
|
+
import type { FieldLayout } from '@toptal/picasso-form-layout'
|
|
3
|
+
|
|
4
|
+
import type { Alignment, Size } from './FormLabel'
|
|
5
|
+
|
|
6
|
+
export const classesBySize: Record<Size, string> = {
|
|
7
|
+
medium: 'text-[0.875rem]',
|
|
8
|
+
large: 'text-[1rem]',
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type GetRootClassesOptions = {
|
|
12
|
+
disabled?: boolean
|
|
13
|
+
isInline: boolean
|
|
14
|
+
layout: FieldLayout
|
|
15
|
+
alignment: Alignment
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const getDisplayClasses = ({
|
|
19
|
+
isInline,
|
|
20
|
+
layout,
|
|
21
|
+
alignment,
|
|
22
|
+
}: Partial<GetRootClassesOptions>) => {
|
|
23
|
+
if (layout === 'horizontal' && alignment === 'top') {
|
|
24
|
+
return 'flex items-start'
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (layout === 'horizontal') {
|
|
28
|
+
return 'flex items-center'
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (isInline) {
|
|
32
|
+
return 'inline-block'
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return 'block'
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const getMarginClasses = ({
|
|
39
|
+
layout,
|
|
40
|
+
isInline,
|
|
41
|
+
}: Partial<GetRootClassesOptions>) =>
|
|
42
|
+
layout === 'horizontal' || isInline ? 'mb-0' : 'mb-[0.5em]'
|
|
43
|
+
|
|
44
|
+
const getPaddingsClasses = ({
|
|
45
|
+
layout,
|
|
46
|
+
alignment,
|
|
47
|
+
}: Partial<GetRootClassesOptions>) =>
|
|
48
|
+
layout === 'horizontal' && alignment === 'top' ? 'pt-2' : ''
|
|
49
|
+
|
|
50
|
+
const getColorClasses = ({ disabled }: Partial<GetRootClassesOptions>) =>
|
|
51
|
+
disabled ? 'text-graphite-700/[0.48]' : 'text-graphite-700'
|
|
52
|
+
|
|
53
|
+
export const getRootClasses = ({
|
|
54
|
+
disabled,
|
|
55
|
+
isInline,
|
|
56
|
+
layout,
|
|
57
|
+
alignment,
|
|
58
|
+
}: GetRootClassesOptions) => {
|
|
59
|
+
return twJoin(
|
|
60
|
+
getDisplayClasses({ isInline, layout, alignment }),
|
|
61
|
+
'leading-[1em]',
|
|
62
|
+
getMarginClasses({ layout, isInline }),
|
|
63
|
+
getColorClasses({ disabled }),
|
|
64
|
+
getPaddingsClasses({ layout, alignment })
|
|
65
|
+
)
|
|
66
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import React from 'react'
|
|
2
|
+
import { render } from '@toptal/picasso-test-utils'
|
|
3
|
+
import type { OmitInternalProps } from '@toptal/picasso-shared'
|
|
4
|
+
import * as titleCaseModule from 'ap-style-title-case'
|
|
5
|
+
import { FormCompound as Form } from '@toptal/picasso-form'
|
|
6
|
+
|
|
7
|
+
import type { Props } from './FormLabel'
|
|
8
|
+
import { FormLabel } from './FormLabel'
|
|
9
|
+
|
|
10
|
+
jest.mock('ap-style-title-case')
|
|
11
|
+
|
|
12
|
+
const TestFormLabel = ({
|
|
13
|
+
children,
|
|
14
|
+
requiredDecoration,
|
|
15
|
+
disabled,
|
|
16
|
+
titleCase,
|
|
17
|
+
htmlFor,
|
|
18
|
+
inline,
|
|
19
|
+
labelEndAdornment,
|
|
20
|
+
}: OmitInternalProps<Props>) => {
|
|
21
|
+
return (
|
|
22
|
+
<Form>
|
|
23
|
+
<Form.Field>
|
|
24
|
+
<FormLabel
|
|
25
|
+
requiredDecoration={requiredDecoration}
|
|
26
|
+
disabled={disabled}
|
|
27
|
+
titleCase={titleCase}
|
|
28
|
+
htmlFor={htmlFor}
|
|
29
|
+
inline={inline}
|
|
30
|
+
labelEndAdornment={labelEndAdornment}
|
|
31
|
+
>
|
|
32
|
+
{children}
|
|
33
|
+
</FormLabel>
|
|
34
|
+
</Form.Field>
|
|
35
|
+
</Form>
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let spiedOnTitleCase: jest.SpyInstance
|
|
40
|
+
|
|
41
|
+
describe('FormLabel', () => {
|
|
42
|
+
beforeEach(() => {
|
|
43
|
+
spiedOnTitleCase = jest.spyOn(titleCaseModule, 'default')
|
|
44
|
+
})
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
spiedOnTitleCase.mockReset()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('renders', () => {
|
|
50
|
+
const { container } = render(<TestFormLabel>Label</TestFormLabel>)
|
|
51
|
+
|
|
52
|
+
expect(container).toMatchSnapshot()
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
it('disabled', () => {
|
|
56
|
+
const { container } = render(<TestFormLabel disabled>Label</TestFormLabel>)
|
|
57
|
+
|
|
58
|
+
expect(container).toMatchSnapshot()
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('required with (optional)', () => {
|
|
62
|
+
const { container } = render(
|
|
63
|
+
<TestFormLabel requiredDecoration='optional'>Label</TestFormLabel>
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
expect(container).toMatchSnapshot()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('required with (optional) and with `labelEndAdornment`', () => {
|
|
70
|
+
const { container } = render(
|
|
71
|
+
<TestFormLabel
|
|
72
|
+
labelEndAdornment={<span>label end adornment</span>}
|
|
73
|
+
requiredDecoration='optional'
|
|
74
|
+
>
|
|
75
|
+
Label
|
|
76
|
+
</TestFormLabel>
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
expect(container).toMatchSnapshot()
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
it('required with asterisk', () => {
|
|
83
|
+
const { container } = render(
|
|
84
|
+
<TestFormLabel requiredDecoration='asterisk'>Label</TestFormLabel>
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
expect(container).toMatchSnapshot()
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('should transform text to title case when Picasso titleCase property is true', () => {
|
|
91
|
+
const TEXT_CONTENT = 'Test kb8'
|
|
92
|
+
|
|
93
|
+
render(<TestFormLabel>{TEXT_CONTENT}</TestFormLabel>, undefined, {
|
|
94
|
+
titleCase: true,
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
expect(spiedOnTitleCase).toHaveBeenCalledWith(TEXT_CONTENT)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('should not transform text to title case when Picasso titleCase property is true but the component property overrides it', () => {
|
|
101
|
+
render(
|
|
102
|
+
<TestFormLabel titleCase={false}>
|
|
103
|
+
some text with-the-edge case for TEST
|
|
104
|
+
</TestFormLabel>,
|
|
105
|
+
undefined,
|
|
106
|
+
{ titleCase: true }
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
expect(spiedOnTitleCase).toHaveBeenCalledTimes(0)
|
|
110
|
+
})
|
|
111
|
+
})
|