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';
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 ;
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..32e69cc8a 100644
--- a/src/utils/index.ts
+++ b/src/utils/index.ts
@@ -28,6 +28,7 @@ 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 type { Attach, AttachAlias, SimpleAnimation } from './hooks/usePortal_DEPRECATED';
export type { onClose } from './events/onClose';