From 9196cc31675412d9e5aa924beb53ff3f34388cc4 Mon Sep 17 00:00:00 2001 From: Julie Wongbandue Date: Tue, 10 Oct 2023 10:20:21 -0400 Subject: [PATCH 1/4] Add useCharacterCount to create controlled components --- src/utils/hooks/useCharacterCount/Counter.tsx | 28 +++++++ .../useCharacterCount.state.ts | 42 ++++++++++ .../useCharacterCount/useCharacterCount.ts | 77 +++++++++++++++++++ src/utils/index.ts | 2 + 4 files changed, 149 insertions(+) create mode 100644 src/utils/hooks/useCharacterCount/Counter.tsx create mode 100644 src/utils/hooks/useCharacterCount/useCharacterCount.state.ts create mode 100644 src/utils/hooks/useCharacterCount/useCharacterCount.ts diff --git a/src/utils/hooks/useCharacterCount/Counter.tsx b/src/utils/hooks/useCharacterCount/Counter.tsx new file mode 100644 index 000000000..a2a1da6ef --- /dev/null +++ b/src/utils/hooks/useCharacterCount/Counter.tsx @@ -0,0 +1,28 @@ +import styled from 'styled-components'; + +import { red, yellow } from '../../../color'; +import { Paragraph } from '../../../typography'; + +interface MessageType { + warning: boolean; + error: boolean; +} + +interface Attrs { + theme: { name: string }; +} + +function attrs({ theme }: Attrs) { + return { + size: 3, + format: theme.name === 'dark' ? 'soft' : 'alternative', + }; +} + +export const Counter = styled(Paragraph).attrs(attrs)` + margin-top: 0.25rem; + margin-bottom: 0; + + ${(p) => p.warning && { fontWeight: 800, color: yellow(600) }}; + ${(p) => p.error && { fontWeight: 600, color: red(500) }}; +`; diff --git a/src/utils/hooks/useCharacterCount/useCharacterCount.state.ts b/src/utils/hooks/useCharacterCount/useCharacterCount.state.ts new file mode 100644 index 000000000..a99010527 --- /dev/null +++ b/src/utils/hooks/useCharacterCount/useCharacterCount.state.ts @@ -0,0 +1,42 @@ +export interface CharacterCountState { + error?: boolean; + warning?: boolean; + remainingCharacters?: number; +} + +export type UserAction = + | { type: 'SET_ERROR'; payload?: undefined } + | { type: 'SET_WARNING'; payload?: undefined } + | { type: 'RESET_STATUS'; payload?: undefined } + | { type: 'SET_REMAINING_CHARACTERS'; payload: number }; + +export function reducer( + state: CharacterCountState, + { type, payload }: UserAction +): CharacterCountState { + switch (type) { + case 'SET_ERROR': + return { + ...state, + error: true, + warning: false, + }; + case 'SET_WARNING': + return { + ...state, + warning: true, + error: false, + }; + case 'RESET_STATUS': + return { + ...state, + warning: false, + error: false, + }; + case 'SET_REMAINING_CHARACTERS': + return { + ...state, + remainingCharacters: payload, + }; + } +} diff --git a/src/utils/hooks/useCharacterCount/useCharacterCount.ts b/src/utils/hooks/useCharacterCount/useCharacterCount.ts new file mode 100644 index 000000000..1929999a1 --- /dev/null +++ b/src/utils/hooks/useCharacterCount/useCharacterCount.ts @@ -0,0 +1,77 @@ +import { useReducer, useCallback } from 'react'; + +import { + reducer, + CharacterCountState, + UserAction, +} from './useCharacterCount.state'; + +export interface UseCharacterCountInit { + value?: string; + /** Max number of characters allowed */ + maxCharacters?: number; + /** Shows warning color when threshold is met */ + warningThreshold?: number; +} + +export interface UseCharacterCount { + state: CharacterCountState; + dispatch: React.Dispatch; + handleChange: (value: string) => void; + clean: () => void; +} + +/** + * Based on withCharacterCount, this provides handlers for a character count message to create a controlled component. + * Helpful to use in conjuction with custom inputs that need more control of input messages + */ + +export function useCharacterCount({ + maxCharacters = 10, + warningThreshold = 5, +}: UseCharacterCountInit): UseCharacterCount { + const [state, dispatch] = useReducer(reducer, { + remainingCharacters: maxCharacters, + }); + + function handleError() { + dispatch({ + type: 'SET_ERROR', + }); + } + + function handleWarn() { + dispatch({ + type: 'SET_WARNING', + }); + } + + const clean = useCallback(() => { + dispatch({ + type: 'RESET_STATUS', + }); + }, []); + + const handleChange = useCallback( + (value: string) => { + const remaining = maxCharacters - value.length; + if (remaining <= warningThreshold && remaining > 0) + handleWarn(); + else if (remaining <= 0) handleError(); + else clean(); + + dispatch({ + type: 'SET_REMAINING_CHARACTERS', + payload: remaining, + }); + }, + [clean, maxCharacters, warningThreshold] + ); + + return { + state, + dispatch, + handleChange, + clean, + }; +} diff --git a/src/utils/index.ts b/src/utils/index.ts index e4cc72573..abac2d31e 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -28,6 +28,8 @@ export { usePortal_DEPRECATED, validate, ANCHOR_POINTS } from './hooks/usePortal export { useStateTransmorphic } from './hooks/useStateTransmorphic'; export { useStyleVars } from './hooks/useStyleVars'; export { withIris } from './HOCs/withIris'; +export { useCharacterCount } from './hooks/useCharacterCount/useCharacterCount'; +export { Counter } from './hooks/useCharacterCount/Counter'; export type { Attach, AttachAlias, SimpleAnimation } from './hooks/usePortal_DEPRECATED'; export type { onClose } from './events/onClose'; From 6799998124d16aa6153c024bd33f5370045f8d49 Mon Sep 17 00:00:00 2001 From: Julie Wongbandue Date: Tue, 10 Oct 2023 10:56:44 -0400 Subject: [PATCH 2/4] remove exported counter --- src/utils/hooks/useCharacterCount/Counter.tsx | 28 ------------------- src/utils/index.ts | 1 - 2 files changed, 29 deletions(-) delete mode 100644 src/utils/hooks/useCharacterCount/Counter.tsx diff --git a/src/utils/hooks/useCharacterCount/Counter.tsx b/src/utils/hooks/useCharacterCount/Counter.tsx deleted file mode 100644 index a2a1da6ef..000000000 --- a/src/utils/hooks/useCharacterCount/Counter.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import styled from 'styled-components'; - -import { red, yellow } from '../../../color'; -import { Paragraph } from '../../../typography'; - -interface MessageType { - warning: boolean; - error: boolean; -} - -interface Attrs { - theme: { name: string }; -} - -function attrs({ theme }: Attrs) { - return { - size: 3, - format: theme.name === 'dark' ? 'soft' : 'alternative', - }; -} - -export const Counter = styled(Paragraph).attrs(attrs)` - margin-top: 0.25rem; - margin-bottom: 0; - - ${(p) => p.warning && { fontWeight: 800, color: yellow(600) }}; - ${(p) => p.error && { fontWeight: 600, color: red(500) }}; -`; diff --git a/src/utils/index.ts b/src/utils/index.ts index abac2d31e..32e69cc8a 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -29,7 +29,6 @@ export { useStateTransmorphic } from './hooks/useStateTransmorphic'; export { useStyleVars } from './hooks/useStyleVars'; export { withIris } from './HOCs/withIris'; export { useCharacterCount } from './hooks/useCharacterCount/useCharacterCount'; -export { Counter } from './hooks/useCharacterCount/Counter'; export type { Attach, AttachAlias, SimpleAnimation } from './hooks/usePortal_DEPRECATED'; export type { onClose } from './events/onClose'; From 3b44f71932e46d2fa3f56878db502eeb442eb7b1 Mon Sep 17 00:00:00 2001 From: Julie Wongbandue Date: Tue, 10 Oct 2023 11:30:17 -0400 Subject: [PATCH 3/4] Skip themekit for lostpixel --- src/_labs/ThemeKit/ThemeKit.story.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/_labs/ThemeKit/ThemeKit.story.tsx b/src/_labs/ThemeKit/ThemeKit.story.tsx index 1d87995a6..ede3a77b2 100644 --- a/src/_labs/ThemeKit/ThemeKit.story.tsx +++ b/src/_labs/ThemeKit/ThemeKit.story.tsx @@ -23,7 +23,14 @@ import { Header as H, Paragraph as P } from '../../typography'; import { LoaderCircular as LC } from '../../motion'; import { Gear } from '../../icons'; -export default { title: 'Labs/Themekit' }; +export default { + title: 'Labs/Themekit', + parameters: { + lostpixel: { + disable: true, + }, + }, +}; export function Common() { return ; From 5dd5620c29ea968be216bca7fac52be4ef30585b Mon Sep 17 00:00:00 2001 From: Julie Wongbandue Date: Tue, 10 Oct 2023 12:00:45 -0400 Subject: [PATCH 4/4] Skip pronouns for lostpixel --- src/_labs/Pronouns/Pronouns.story.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/_labs/Pronouns/Pronouns.story.tsx b/src/_labs/Pronouns/Pronouns.story.tsx index 8dfe85501..9a4d213d0 100644 --- a/src/_labs/Pronouns/Pronouns.story.tsx +++ b/src/_labs/Pronouns/Pronouns.story.tsx @@ -10,7 +10,14 @@ import { AutoplayList } from './AutoplayList'; import { Header } from '../../typography'; -export default { title: 'labs/Pronouns' }; +export default { + title: 'labs/Pronouns', + parameters: { + lostpixel: { + disable: true, + }, + }, +}; const componentName = 'Comment';