@grazziotin/react-components-next 1.0.1 → 2.1.0

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.
@@ -0,0 +1,136 @@
1
+ import react__default from 'react';
2
+
3
+ type SayFeedbackType = "info" | "success" | "warning" | "error" | "default";
4
+ interface SayNotifyOptions {
5
+ type?: SayFeedbackType;
6
+ autoClose?: number;
7
+ }
8
+ interface SayCallOptions {
9
+ /**
10
+ * Tipo de feedback. desativa notificação.
11
+ * Padrão: (via do hook).
12
+ */
13
+ type?: SayFeedbackType | false;
14
+ /**
15
+ * Exibe notificação via .
16
+ * Padrão: .
17
+ */
18
+ notify?: boolean;
19
+ /**
20
+ * Dispara vibração conforme .
21
+ * Padrão: .
22
+ */
23
+ vibrate?: boolean;
24
+ /** Duração da notificação em ms (repasse para ). */
25
+ autoClose?: number;
26
+ }
27
+ interface UseSayOptions {
28
+ /**
29
+ * Callback de notificação visual (ex.: toast).
30
+ * Omitir para não exibir notificação.
31
+ */
32
+ onNotify?: (text: string, options: SayNotifyOptions) => void;
33
+ /**
34
+ * Tipo padrão da notificação.
35
+ * Padrão: .
36
+ */
37
+ defaultNotifyType?: SayFeedbackType;
38
+ /**
39
+ * Auto-close padrão da notificação em ms.
40
+ * Padrão: .
41
+ */
42
+ defaultNotifyAutoClose?: number;
43
+ /**
44
+ * Duração padrão da vibração em ms.
45
+ * Padrão: .
46
+ */
47
+ vibrateDuration?: number;
48
+ /**
49
+ * Define se deve vibrar para o informado.
50
+ * Padrão: ( quando é omitido ou ).
51
+ */
52
+ shouldVibrate?: (type?: SayFeedbackType | false) => boolean;
53
+ }
54
+ interface UseSayReturn {
55
+ say: (text: string, options?: SayCallOptions) => void;
56
+ isSpeaking: boolean;
57
+ textSpeaking: string;
58
+ setIsSpeaking: React.Dispatch<React.SetStateAction<boolean>>;
59
+ }
60
+ interface SayProps {
61
+ isSpeaking: boolean;
62
+ text: string;
63
+ setIsSpeaking: React.Dispatch<React.SetStateAction<boolean>>;
64
+ /**
65
+ * Nome da voz do .
66
+ * Padrão: .
67
+ */
68
+ voice?: string;
69
+ /**
70
+ * Velocidade da fala.
71
+ * Padrão: .
72
+ */
73
+ rate?: number;
74
+ /**
75
+ * Tom da voz.
76
+ * Padrão: .
77
+ */
78
+ pitch?: number;
79
+ /**
80
+ * Volume da fala.
81
+ * Padrão: .
82
+ */
83
+ volume?: number;
84
+ onEnd?: () => void;
85
+ onStart?: () => void;
86
+ }
87
+
88
+ /**
89
+ * Hook para disparar fala, notificação e vibração de forma configurável.
90
+ *
91
+ * @example
92
+ * ```tsx
93
+ * const { say, isSpeaking, textSpeaking, setIsSpeaking } = useSay({
94
+ * onNotify: (text, { type }) => toast(text, { type }),
95
+ * });
96
+ *
97
+ * <Say
98
+ * isSpeaking={isSpeaking}
99
+ * text={textSpeaking}
100
+ * setIsSpeaking={setIsSpeaking}
101
+ * />
102
+ *
103
+ * <button type="button" onClick={() => say("Operação concluída")}>
104
+ * Falar
105
+ * </button>
106
+ * ```
107
+ */
108
+ declare function useSay({ onNotify, defaultNotifyType, vibrateDuration, defaultNotifyAutoClose, shouldVibrate, }?: UseSayOptions): UseSayReturn;
109
+
110
+ /**
111
+ * Sintetiza texto em fala via Web Speech API (`react-say`).
112
+ * Use com {@link useSay} para controlar `isSpeaking`, `text` e `setIsSpeaking`.
113
+ *
114
+ * @example
115
+ * ```tsx
116
+ * const { say, isSpeaking, textSpeaking, setIsSpeaking } = useSay({
117
+ * onNotify: (text, { type }) => toast(text, { type }),
118
+ * });
119
+ *
120
+ * return (
121
+ * <>
122
+ * <Say
123
+ * isSpeaking={isSpeaking}
124
+ * text={textSpeaking}
125
+ * setIsSpeaking={setIsSpeaking}
126
+ * voice="Google português do Brasil"
127
+ * rate={1.4}
128
+ * />
129
+ * <button type="button" onClick={() => say("Pronto")}>Falar</button>
130
+ * </>
131
+ * );
132
+ * ```
133
+ */
134
+ declare function Say({ text, onEnd, onStart, isSpeaking, setIsSpeaking, rate, voice, pitch, volume, }: Readonly<SayProps>): react__default.ReactElement | null;
135
+
136
+ export { Say, type SayCallOptions, type SayFeedbackType, type SayNotifyOptions, type SayProps, type UseSayOptions, type UseSayReturn, useSay };
@@ -0,0 +1,136 @@
1
+ import react__default from 'react';
2
+
3
+ type SayFeedbackType = "info" | "success" | "warning" | "error" | "default";
4
+ interface SayNotifyOptions {
5
+ type?: SayFeedbackType;
6
+ autoClose?: number;
7
+ }
8
+ interface SayCallOptions {
9
+ /**
10
+ * Tipo de feedback. desativa notificação.
11
+ * Padrão: (via do hook).
12
+ */
13
+ type?: SayFeedbackType | false;
14
+ /**
15
+ * Exibe notificação via .
16
+ * Padrão: .
17
+ */
18
+ notify?: boolean;
19
+ /**
20
+ * Dispara vibração conforme .
21
+ * Padrão: .
22
+ */
23
+ vibrate?: boolean;
24
+ /** Duração da notificação em ms (repasse para ). */
25
+ autoClose?: number;
26
+ }
27
+ interface UseSayOptions {
28
+ /**
29
+ * Callback de notificação visual (ex.: toast).
30
+ * Omitir para não exibir notificação.
31
+ */
32
+ onNotify?: (text: string, options: SayNotifyOptions) => void;
33
+ /**
34
+ * Tipo padrão da notificação.
35
+ * Padrão: .
36
+ */
37
+ defaultNotifyType?: SayFeedbackType;
38
+ /**
39
+ * Auto-close padrão da notificação em ms.
40
+ * Padrão: .
41
+ */
42
+ defaultNotifyAutoClose?: number;
43
+ /**
44
+ * Duração padrão da vibração em ms.
45
+ * Padrão: .
46
+ */
47
+ vibrateDuration?: number;
48
+ /**
49
+ * Define se deve vibrar para o informado.
50
+ * Padrão: ( quando é omitido ou ).
51
+ */
52
+ shouldVibrate?: (type?: SayFeedbackType | false) => boolean;
53
+ }
54
+ interface UseSayReturn {
55
+ say: (text: string, options?: SayCallOptions) => void;
56
+ isSpeaking: boolean;
57
+ textSpeaking: string;
58
+ setIsSpeaking: React.Dispatch<React.SetStateAction<boolean>>;
59
+ }
60
+ interface SayProps {
61
+ isSpeaking: boolean;
62
+ text: string;
63
+ setIsSpeaking: React.Dispatch<React.SetStateAction<boolean>>;
64
+ /**
65
+ * Nome da voz do .
66
+ * Padrão: .
67
+ */
68
+ voice?: string;
69
+ /**
70
+ * Velocidade da fala.
71
+ * Padrão: .
72
+ */
73
+ rate?: number;
74
+ /**
75
+ * Tom da voz.
76
+ * Padrão: .
77
+ */
78
+ pitch?: number;
79
+ /**
80
+ * Volume da fala.
81
+ * Padrão: .
82
+ */
83
+ volume?: number;
84
+ onEnd?: () => void;
85
+ onStart?: () => void;
86
+ }
87
+
88
+ /**
89
+ * Hook para disparar fala, notificação e vibração de forma configurável.
90
+ *
91
+ * @example
92
+ * ```tsx
93
+ * const { say, isSpeaking, textSpeaking, setIsSpeaking } = useSay({
94
+ * onNotify: (text, { type }) => toast(text, { type }),
95
+ * });
96
+ *
97
+ * <Say
98
+ * isSpeaking={isSpeaking}
99
+ * text={textSpeaking}
100
+ * setIsSpeaking={setIsSpeaking}
101
+ * />
102
+ *
103
+ * <button type="button" onClick={() => say("Operação concluída")}>
104
+ * Falar
105
+ * </button>
106
+ * ```
107
+ */
108
+ declare function useSay({ onNotify, defaultNotifyType, vibrateDuration, defaultNotifyAutoClose, shouldVibrate, }?: UseSayOptions): UseSayReturn;
109
+
110
+ /**
111
+ * Sintetiza texto em fala via Web Speech API (`react-say`).
112
+ * Use com {@link useSay} para controlar `isSpeaking`, `text` e `setIsSpeaking`.
113
+ *
114
+ * @example
115
+ * ```tsx
116
+ * const { say, isSpeaking, textSpeaking, setIsSpeaking } = useSay({
117
+ * onNotify: (text, { type }) => toast(text, { type }),
118
+ * });
119
+ *
120
+ * return (
121
+ * <>
122
+ * <Say
123
+ * isSpeaking={isSpeaking}
124
+ * text={textSpeaking}
125
+ * setIsSpeaking={setIsSpeaking}
126
+ * voice="Google português do Brasil"
127
+ * rate={1.4}
128
+ * />
129
+ * <button type="button" onClick={() => say("Pronto")}>Falar</button>
130
+ * </>
131
+ * );
132
+ * ```
133
+ */
134
+ declare function Say({ text, onEnd, onStart, isSpeaking, setIsSpeaking, rate, voice, pitch, volume, }: Readonly<SayProps>): react__default.ReactElement | null;
135
+
136
+ export { Say, type SayCallOptions, type SayFeedbackType, type SayNotifyOptions, type SayProps, type UseSayOptions, type UseSayReturn, useSay };
@@ -0,0 +1,138 @@
1
+ 'use strict';
2
+
3
+ var SayEngine = require('react-say');
4
+ var react = require('react');
5
+ var jsxRuntime = require('react/jsx-runtime');
6
+
7
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
8
+
9
+ var SayEngine__default = /*#__PURE__*/_interopDefault(SayEngine);
10
+
11
+ // src/components/accessibility/say/utils/constants.ts
12
+ var SPEECH_APIS = ["speechSynthesis", "SpeechSynthesisUtterance"];
13
+ function hasSpeechSupport() {
14
+ return SPEECH_APIS.every((api) => api in globalThis);
15
+ }
16
+ function voicesAreEqual(current, next) {
17
+ if (current.length !== next.length) return false;
18
+ return current.every(
19
+ (v, i) => {
20
+ var _a, _b;
21
+ return v.name === ((_a = next[i]) == null ? void 0 : _a.name) && v.lang === ((_b = next[i]) == null ? void 0 : _b.lang);
22
+ }
23
+ );
24
+ }
25
+ function getSpeechSupport() {
26
+ if (!hasSpeechSupport()) return null;
27
+ return {
28
+ speechSynthesis: globalThis.speechSynthesis,
29
+ SpeechSynthesisUtterance: globalThis.SpeechSynthesisUtterance
30
+ };
31
+ }
32
+ var DEFAULT_SAY_VOICE = "Google portugu\xEAs do Brasil";
33
+ var DEFAULT_SAY_RATE = 1.4;
34
+ var DEFAULT_SAY_PITCH = 0.8;
35
+ var DEFAULT_SAY_VOLUME = 1;
36
+ var DEFAULT_SAY_NOTIFY_AUTO_CLOSE = 1500;
37
+ var DEFAULT_SAY_VIBRATE_DURATION = 500;
38
+ function defaultShouldVibrate(type) {
39
+ return !type || type === "warning";
40
+ }
41
+
42
+ // src/functions/nvl/nvl.ts
43
+ function nvl(value, defaultValue) {
44
+ return value != null ? value : defaultValue;
45
+ }
46
+ function useSay({
47
+ onNotify,
48
+ defaultNotifyType = "success",
49
+ vibrateDuration = DEFAULT_SAY_VIBRATE_DURATION,
50
+ defaultNotifyAutoClose = DEFAULT_SAY_NOTIFY_AUTO_CLOSE,
51
+ shouldVibrate = defaultShouldVibrate
52
+ } = {}) {
53
+ const [isSpeaking, setIsSpeaking] = react.useState(false);
54
+ const [textSpeaking, setTextSpeaking] = react.useState("");
55
+ const say = react.useCallback(
56
+ (text, options) => {
57
+ const type = options == null ? void 0 : options.type;
58
+ const notify = nvl(options == null ? void 0 : options.notify, true);
59
+ const vibrate = nvl(options == null ? void 0 : options.vibrate, true);
60
+ setIsSpeaking(true);
61
+ setTextSpeaking(text);
62
+ if (notify && type !== false && onNotify) {
63
+ onNotify(text, {
64
+ type: nvl(type, defaultNotifyType),
65
+ autoClose: nvl(options == null ? void 0 : options.autoClose, defaultNotifyAutoClose)
66
+ });
67
+ }
68
+ if (vibrate && shouldVibrate(type) && navigator.vibrate) {
69
+ navigator.vibrate(vibrateDuration);
70
+ }
71
+ },
72
+ [
73
+ onNotify,
74
+ shouldVibrate,
75
+ vibrateDuration,
76
+ defaultNotifyType,
77
+ defaultNotifyAutoClose
78
+ ]
79
+ );
80
+ return { say, isSpeaking, textSpeaking, setIsSpeaking };
81
+ }
82
+ function useSpeechPonyfill() {
83
+ const ponyfill = react.useMemo(() => getSpeechSupport(), []);
84
+ const [voices, setVoices] = react.useState([]);
85
+ react.useEffect(() => {
86
+ if (!hasSpeechSupport()) return;
87
+ const synthesis = globalThis.speechSynthesis;
88
+ const updateVoices = () => {
89
+ setVoices((current) => {
90
+ const next = synthesis.getVoices();
91
+ return voicesAreEqual(current, next) ? current : next;
92
+ });
93
+ };
94
+ synthesis.onvoiceschanged = updateVoices;
95
+ updateVoices();
96
+ return () => {
97
+ synthesis.onvoiceschanged = null;
98
+ };
99
+ }, []);
100
+ return { voices, ponyfill };
101
+ }
102
+ function Say({
103
+ text,
104
+ onEnd,
105
+ onStart,
106
+ isSpeaking,
107
+ setIsSpeaking,
108
+ rate = DEFAULT_SAY_RATE,
109
+ voice = DEFAULT_SAY_VOICE,
110
+ pitch = DEFAULT_SAY_PITCH,
111
+ volume = DEFAULT_SAY_VOLUME
112
+ }) {
113
+ const { voices, ponyfill } = useSpeechPonyfill();
114
+ const handleEnd = react.useCallback(() => {
115
+ setIsSpeaking(false);
116
+ onEnd == null ? void 0 : onEnd();
117
+ }, [setIsSpeaking, onEnd]);
118
+ if (!isSpeaking || voices.length === 0 || !ponyfill) return null;
119
+ return /* @__PURE__ */ jsxRuntime.jsx(
120
+ SayEngine__default.default,
121
+ {
122
+ text,
123
+ rate,
124
+ pitch,
125
+ volume,
126
+ onEnd: handleEnd,
127
+ onStart,
128
+ ponyfill,
129
+ voice: voices.find((v) => v.name === voice)
130
+ }
131
+ );
132
+ }
133
+ var say_default = Say;
134
+
135
+ exports.Say = say_default;
136
+ exports.useSay = useSay;
137
+ //# sourceMappingURL=index.js.map
138
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/accessibility/say/utils/constants.ts","../../src/functions/nvl/nvl.ts","../../src/components/accessibility/say/use-say.ts","../../src/components/accessibility/say/use-speech-ponyfill.ts","../../src/components/accessibility/say/index.tsx"],"names":["useState","useCallback","useMemo","useEffect","jsx","SayEngine"],"mappings":"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","file":"index.js","sourcesContent":["import type { SpeechPonyfill } from \"./interface\";\r\n\r\nexport const SPEECH_APIS = [\"speechSynthesis\", \"SpeechSynthesisUtterance\"];\r\n\r\nexport function hasSpeechSupport(): boolean {\r\n return SPEECH_APIS.every((api) => api in globalThis);\r\n}\r\n\r\nexport function voicesAreEqual(\r\n current: SpeechSynthesisVoice[],\r\n next: SpeechSynthesisVoice[],\r\n): boolean {\r\n if (current.length !== next.length) return false;\r\n\r\n return current.every(\r\n (v, i) => v.name === next[i]?.name && v.lang === next[i]?.lang,\r\n );\r\n}\r\n\r\nexport function getSpeechSupport(): SpeechPonyfill | null {\r\n if (!hasSpeechSupport()) return null;\r\n\r\n return {\r\n speechSynthesis: globalThis.speechSynthesis,\r\n SpeechSynthesisUtterance: globalThis.SpeechSynthesisUtterance,\r\n };\r\n}\r\n\r\nexport const DEFAULT_SAY_VOICE = \"Google português do Brasil\";\r\nexport const DEFAULT_SAY_RATE = 1.4;\r\nexport const DEFAULT_SAY_PITCH = 0.8;\r\nexport const DEFAULT_SAY_VOLUME = 1;\r\nexport const DEFAULT_SAY_NOTIFY_AUTO_CLOSE = 1500;\r\nexport const DEFAULT_SAY_VIBRATE_DURATION = 500;\r\n\r\nexport function defaultShouldVibrate(\r\n type?: import(\"./interface\").SayFeedbackType | false,\r\n): boolean {\r\n return !type || type === \"warning\";\r\n}\r\n\r\nconst sayConstants = `\r\nSintetiza texto em fala via Web Speech API (\\`react-say\\`), com hook \\`useSay\\` para notificação e vibração.\r\n\r\n**Importação:**\r\n\\`\\`\\`tsx\r\nimport { Say, useSay } from \"@grazziotin/react-components-next/accessibility\";\r\n\\`\\`\\`\r\n\r\n**Uso básico:**\r\n\\`\\`\\`tsx\r\nconst { say, isSpeaking, textSpeaking, setIsSpeaking } = useSay({\r\n onNotify: (text, { type }) => toast(text, { type }),\r\n});\r\n\r\n<>\r\n <Say\r\n isSpeaking={isSpeaking}\r\n text={textSpeaking}\r\n setIsSpeaking={setIsSpeaking}\r\n />\r\n <button type=\"button\" onClick={() => say(\"Operação concluída\")}>\r\n Falar\r\n </button>\r\n</>\r\n\\`\\`\\`\r\n\r\nRequer suporte a \\`speechSynthesis\\` no navegador. A voz padrão é \\`Google português do Brasil\\`.\r\n`;\r\n\r\nexport default sayConstants;\r\n","/**\r\n * Função NVL (Null Value Logic) - retorna valor padrão se o valor for null/undefined\r\n * @param {T | null | undefined} value - Valor a ser verificado\r\n * @param {T} defaultValue - Valor padrão a ser retornado se value for null/undefined\r\n * @returns {T} Value se não for null/undefined, senão defaultValue\r\n * @template T - Tipo do valor\r\n * @example\r\n * nvl(null, 'padrão') // Retorna: 'padrão'\r\n * nvl('valor', 'padrão') // Retorna: 'valor'\r\n */\r\nexport function nvl<T>(value: T | null | undefined, defaultValue: T): T {\r\n return value ?? defaultValue;\r\n}\r\n","import {\r\n defaultShouldVibrate,\r\n DEFAULT_SAY_NOTIFY_AUTO_CLOSE,\r\n DEFAULT_SAY_VIBRATE_DURATION,\r\n} from \"./utils/constants\";\r\nimport type {\r\n UseSayReturn,\r\n UseSayOptions,\r\n SayCallOptions,\r\n} from \"./utils/interface\";\r\nimport { nvl } from \"@/functions\";\r\nimport { useCallback, useState } from \"react\";\r\n\r\n/**\r\n * Hook para disparar fala, notificação e vibração de forma configurável.\r\n *\r\n * @example\r\n * ```tsx\r\n * const { say, isSpeaking, textSpeaking, setIsSpeaking } = useSay({\r\n * onNotify: (text, { type }) => toast(text, { type }),\r\n * });\r\n *\r\n * <Say\r\n * isSpeaking={isSpeaking}\r\n * text={textSpeaking}\r\n * setIsSpeaking={setIsSpeaking}\r\n * />\r\n *\r\n * <button type=\"button\" onClick={() => say(\"Operação concluída\")}>\r\n * Falar\r\n * </button>\r\n * ```\r\n */\r\nexport function useSay({\r\n onNotify,\r\n defaultNotifyType = \"success\",\r\n vibrateDuration = DEFAULT_SAY_VIBRATE_DURATION,\r\n defaultNotifyAutoClose = DEFAULT_SAY_NOTIFY_AUTO_CLOSE,\r\n shouldVibrate = defaultShouldVibrate,\r\n}: UseSayOptions = {}): UseSayReturn {\r\n const [isSpeaking, setIsSpeaking] = useState(false);\r\n const [textSpeaking, setTextSpeaking] = useState(\"\");\r\n\r\n const say = useCallback(\r\n (text: string, options?: SayCallOptions) => {\r\n const type = options?.type;\r\n const notify = nvl(options?.notify, true);\r\n const vibrate = nvl(options?.vibrate, true);\r\n\r\n setIsSpeaking(true);\r\n setTextSpeaking(text);\r\n\r\n if (notify && type !== false && onNotify) {\r\n onNotify(text, {\r\n type: nvl(type, defaultNotifyType),\r\n autoClose: nvl(options?.autoClose, defaultNotifyAutoClose),\r\n });\r\n }\r\n\r\n if (vibrate && shouldVibrate(type) && navigator.vibrate) {\r\n navigator.vibrate(vibrateDuration);\r\n }\r\n },\r\n [\r\n onNotify,\r\n shouldVibrate,\r\n vibrateDuration,\r\n defaultNotifyType,\r\n defaultNotifyAutoClose,\r\n ],\r\n );\r\n\r\n return { say, isSpeaking, textSpeaking, setIsSpeaking };\r\n}\r\n","import {\r\n getSpeechSupport,\r\n hasSpeechSupport,\r\n voicesAreEqual,\r\n} from \"./utils/constants\";\r\nimport { useEffect, useMemo, useState } from \"react\";\r\n\r\nexport function useSpeechPonyfill() {\r\n const ponyfill = useMemo(() => getSpeechSupport(), []);\r\n const [voices, setVoices] = useState<SpeechSynthesisVoice[]>([]);\r\n\r\n useEffect(() => {\r\n if (!hasSpeechSupport()) return;\r\n\r\n const synthesis = globalThis.speechSynthesis;\r\n\r\n const updateVoices = () => {\r\n setVoices((current) => {\r\n const next = synthesis.getVoices();\r\n return voicesAreEqual(current, next) ? current : next;\r\n });\r\n };\r\n\r\n synthesis.onvoiceschanged = updateVoices;\r\n updateVoices();\r\n\r\n return () => {\r\n synthesis.onvoiceschanged = null;\r\n };\r\n }, []);\r\n\r\n return { voices, ponyfill };\r\n}\r\n","\"use client\";\r\n\r\nimport {\r\n DEFAULT_SAY_PITCH,\r\n DEFAULT_SAY_RATE,\r\n DEFAULT_SAY_VOICE,\r\n DEFAULT_SAY_VOLUME,\r\n} from \"./utils/constants\";\r\nimport SayEngine from \"react-say\";\r\nexport { useSay } from \"./use-say\";\r\nimport React, { useCallback } from \"react\";\r\nimport type { SayProps } from \"./utils/interface\";\r\nimport { useSpeechPonyfill } from \"./use-speech-ponyfill\";\r\n\r\n/**\r\n * Sintetiza texto em fala via Web Speech API (`react-say`).\r\n * Use com {@link useSay} para controlar `isSpeaking`, `text` e `setIsSpeaking`.\r\n *\r\n * @example\r\n * ```tsx\r\n * const { say, isSpeaking, textSpeaking, setIsSpeaking } = useSay({\r\n * onNotify: (text, { type }) => toast(text, { type }),\r\n * });\r\n *\r\n * return (\r\n * <>\r\n * <Say\r\n * isSpeaking={isSpeaking}\r\n * text={textSpeaking}\r\n * setIsSpeaking={setIsSpeaking}\r\n * voice=\"Google português do Brasil\"\r\n * rate={1.4}\r\n * />\r\n * <button type=\"button\" onClick={() => say(\"Pronto\")}>Falar</button>\r\n * </>\r\n * );\r\n * ```\r\n */\r\nfunction Say({\r\n text,\r\n onEnd,\r\n onStart,\r\n isSpeaking,\r\n setIsSpeaking,\r\n rate = DEFAULT_SAY_RATE,\r\n voice = DEFAULT_SAY_VOICE,\r\n pitch = DEFAULT_SAY_PITCH,\r\n volume = DEFAULT_SAY_VOLUME,\r\n}: Readonly<SayProps>): React.ReactElement | null {\r\n const { voices, ponyfill } = useSpeechPonyfill();\r\n\r\n const handleEnd = useCallback(() => {\r\n setIsSpeaking(false);\r\n onEnd?.();\r\n }, [setIsSpeaking, onEnd]);\r\n\r\n if (!isSpeaking || voices.length === 0 || !ponyfill) return null;\r\n\r\n return (\r\n <SayEngine\r\n text={text}\r\n rate={rate}\r\n pitch={pitch}\r\n volume={volume}\r\n onEnd={handleEnd}\r\n onStart={onStart}\r\n ponyfill={ponyfill}\r\n voice={voices.find((v) => v.name === voice)}\r\n />\r\n );\r\n}\r\n\r\nexport default Say;\r\n"]}
@@ -0,0 +1,127 @@
1
+ import { nvl } from '../chunk-BWW3F4R4.mjs';
2
+ import SayEngine from 'react-say';
3
+ import { useState, useCallback, useMemo, useEffect } from 'react';
4
+ import { jsx } from 'react/jsx-runtime';
5
+
6
+ // src/components/accessibility/say/utils/constants.ts
7
+ var SPEECH_APIS = ["speechSynthesis", "SpeechSynthesisUtterance"];
8
+ function hasSpeechSupport() {
9
+ return SPEECH_APIS.every((api) => api in globalThis);
10
+ }
11
+ function voicesAreEqual(current, next) {
12
+ if (current.length !== next.length) return false;
13
+ return current.every(
14
+ (v, i) => {
15
+ var _a, _b;
16
+ return v.name === ((_a = next[i]) == null ? void 0 : _a.name) && v.lang === ((_b = next[i]) == null ? void 0 : _b.lang);
17
+ }
18
+ );
19
+ }
20
+ function getSpeechSupport() {
21
+ if (!hasSpeechSupport()) return null;
22
+ return {
23
+ speechSynthesis: globalThis.speechSynthesis,
24
+ SpeechSynthesisUtterance: globalThis.SpeechSynthesisUtterance
25
+ };
26
+ }
27
+ var DEFAULT_SAY_VOICE = "Google portugu\xEAs do Brasil";
28
+ var DEFAULT_SAY_RATE = 1.4;
29
+ var DEFAULT_SAY_PITCH = 0.8;
30
+ var DEFAULT_SAY_VOLUME = 1;
31
+ var DEFAULT_SAY_NOTIFY_AUTO_CLOSE = 1500;
32
+ var DEFAULT_SAY_VIBRATE_DURATION = 500;
33
+ function defaultShouldVibrate(type) {
34
+ return !type || type === "warning";
35
+ }
36
+ function useSay({
37
+ onNotify,
38
+ defaultNotifyType = "success",
39
+ vibrateDuration = DEFAULT_SAY_VIBRATE_DURATION,
40
+ defaultNotifyAutoClose = DEFAULT_SAY_NOTIFY_AUTO_CLOSE,
41
+ shouldVibrate = defaultShouldVibrate
42
+ } = {}) {
43
+ const [isSpeaking, setIsSpeaking] = useState(false);
44
+ const [textSpeaking, setTextSpeaking] = useState("");
45
+ const say = useCallback(
46
+ (text, options) => {
47
+ const type = options == null ? void 0 : options.type;
48
+ const notify = nvl(options == null ? void 0 : options.notify, true);
49
+ const vibrate = nvl(options == null ? void 0 : options.vibrate, true);
50
+ setIsSpeaking(true);
51
+ setTextSpeaking(text);
52
+ if (notify && type !== false && onNotify) {
53
+ onNotify(text, {
54
+ type: nvl(type, defaultNotifyType),
55
+ autoClose: nvl(options == null ? void 0 : options.autoClose, defaultNotifyAutoClose)
56
+ });
57
+ }
58
+ if (vibrate && shouldVibrate(type) && navigator.vibrate) {
59
+ navigator.vibrate(vibrateDuration);
60
+ }
61
+ },
62
+ [
63
+ onNotify,
64
+ shouldVibrate,
65
+ vibrateDuration,
66
+ defaultNotifyType,
67
+ defaultNotifyAutoClose
68
+ ]
69
+ );
70
+ return { say, isSpeaking, textSpeaking, setIsSpeaking };
71
+ }
72
+ function useSpeechPonyfill() {
73
+ const ponyfill = useMemo(() => getSpeechSupport(), []);
74
+ const [voices, setVoices] = useState([]);
75
+ useEffect(() => {
76
+ if (!hasSpeechSupport()) return;
77
+ const synthesis = globalThis.speechSynthesis;
78
+ const updateVoices = () => {
79
+ setVoices((current) => {
80
+ const next = synthesis.getVoices();
81
+ return voicesAreEqual(current, next) ? current : next;
82
+ });
83
+ };
84
+ synthesis.onvoiceschanged = updateVoices;
85
+ updateVoices();
86
+ return () => {
87
+ synthesis.onvoiceschanged = null;
88
+ };
89
+ }, []);
90
+ return { voices, ponyfill };
91
+ }
92
+ function Say({
93
+ text,
94
+ onEnd,
95
+ onStart,
96
+ isSpeaking,
97
+ setIsSpeaking,
98
+ rate = DEFAULT_SAY_RATE,
99
+ voice = DEFAULT_SAY_VOICE,
100
+ pitch = DEFAULT_SAY_PITCH,
101
+ volume = DEFAULT_SAY_VOLUME
102
+ }) {
103
+ const { voices, ponyfill } = useSpeechPonyfill();
104
+ const handleEnd = useCallback(() => {
105
+ setIsSpeaking(false);
106
+ onEnd == null ? void 0 : onEnd();
107
+ }, [setIsSpeaking, onEnd]);
108
+ if (!isSpeaking || voices.length === 0 || !ponyfill) return null;
109
+ return /* @__PURE__ */ jsx(
110
+ SayEngine,
111
+ {
112
+ text,
113
+ rate,
114
+ pitch,
115
+ volume,
116
+ onEnd: handleEnd,
117
+ onStart,
118
+ ponyfill,
119
+ voice: voices.find((v) => v.name === voice)
120
+ }
121
+ );
122
+ }
123
+ var say_default = Say;
124
+
125
+ export { say_default as Say, useSay };
126
+ //# sourceMappingURL=index.mjs.map
127
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/components/accessibility/say/utils/constants.ts","../../src/components/accessibility/say/use-say.ts","../../src/components/accessibility/say/use-speech-ponyfill.ts","../../src/components/accessibility/say/index.tsx"],"names":["useState","useCallback"],"mappings":"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","file":"index.mjs","sourcesContent":["import type { SpeechPonyfill } from \"./interface\";\r\n\r\nexport const SPEECH_APIS = [\"speechSynthesis\", \"SpeechSynthesisUtterance\"];\r\n\r\nexport function hasSpeechSupport(): boolean {\r\n return SPEECH_APIS.every((api) => api in globalThis);\r\n}\r\n\r\nexport function voicesAreEqual(\r\n current: SpeechSynthesisVoice[],\r\n next: SpeechSynthesisVoice[],\r\n): boolean {\r\n if (current.length !== next.length) return false;\r\n\r\n return current.every(\r\n (v, i) => v.name === next[i]?.name && v.lang === next[i]?.lang,\r\n );\r\n}\r\n\r\nexport function getSpeechSupport(): SpeechPonyfill | null {\r\n if (!hasSpeechSupport()) return null;\r\n\r\n return {\r\n speechSynthesis: globalThis.speechSynthesis,\r\n SpeechSynthesisUtterance: globalThis.SpeechSynthesisUtterance,\r\n };\r\n}\r\n\r\nexport const DEFAULT_SAY_VOICE = \"Google português do Brasil\";\r\nexport const DEFAULT_SAY_RATE = 1.4;\r\nexport const DEFAULT_SAY_PITCH = 0.8;\r\nexport const DEFAULT_SAY_VOLUME = 1;\r\nexport const DEFAULT_SAY_NOTIFY_AUTO_CLOSE = 1500;\r\nexport const DEFAULT_SAY_VIBRATE_DURATION = 500;\r\n\r\nexport function defaultShouldVibrate(\r\n type?: import(\"./interface\").SayFeedbackType | false,\r\n): boolean {\r\n return !type || type === \"warning\";\r\n}\r\n\r\nconst sayConstants = `\r\nSintetiza texto em fala via Web Speech API (\\`react-say\\`), com hook \\`useSay\\` para notificação e vibração.\r\n\r\n**Importação:**\r\n\\`\\`\\`tsx\r\nimport { Say, useSay } from \"@grazziotin/react-components-next/accessibility\";\r\n\\`\\`\\`\r\n\r\n**Uso básico:**\r\n\\`\\`\\`tsx\r\nconst { say, isSpeaking, textSpeaking, setIsSpeaking } = useSay({\r\n onNotify: (text, { type }) => toast(text, { type }),\r\n});\r\n\r\n<>\r\n <Say\r\n isSpeaking={isSpeaking}\r\n text={textSpeaking}\r\n setIsSpeaking={setIsSpeaking}\r\n />\r\n <button type=\"button\" onClick={() => say(\"Operação concluída\")}>\r\n Falar\r\n </button>\r\n</>\r\n\\`\\`\\`\r\n\r\nRequer suporte a \\`speechSynthesis\\` no navegador. A voz padrão é \\`Google português do Brasil\\`.\r\n`;\r\n\r\nexport default sayConstants;\r\n","import {\r\n defaultShouldVibrate,\r\n DEFAULT_SAY_NOTIFY_AUTO_CLOSE,\r\n DEFAULT_SAY_VIBRATE_DURATION,\r\n} from \"./utils/constants\";\r\nimport type {\r\n UseSayReturn,\r\n UseSayOptions,\r\n SayCallOptions,\r\n} from \"./utils/interface\";\r\nimport { nvl } from \"@/functions\";\r\nimport { useCallback, useState } from \"react\";\r\n\r\n/**\r\n * Hook para disparar fala, notificação e vibração de forma configurável.\r\n *\r\n * @example\r\n * ```tsx\r\n * const { say, isSpeaking, textSpeaking, setIsSpeaking } = useSay({\r\n * onNotify: (text, { type }) => toast(text, { type }),\r\n * });\r\n *\r\n * <Say\r\n * isSpeaking={isSpeaking}\r\n * text={textSpeaking}\r\n * setIsSpeaking={setIsSpeaking}\r\n * />\r\n *\r\n * <button type=\"button\" onClick={() => say(\"Operação concluída\")}>\r\n * Falar\r\n * </button>\r\n * ```\r\n */\r\nexport function useSay({\r\n onNotify,\r\n defaultNotifyType = \"success\",\r\n vibrateDuration = DEFAULT_SAY_VIBRATE_DURATION,\r\n defaultNotifyAutoClose = DEFAULT_SAY_NOTIFY_AUTO_CLOSE,\r\n shouldVibrate = defaultShouldVibrate,\r\n}: UseSayOptions = {}): UseSayReturn {\r\n const [isSpeaking, setIsSpeaking] = useState(false);\r\n const [textSpeaking, setTextSpeaking] = useState(\"\");\r\n\r\n const say = useCallback(\r\n (text: string, options?: SayCallOptions) => {\r\n const type = options?.type;\r\n const notify = nvl(options?.notify, true);\r\n const vibrate = nvl(options?.vibrate, true);\r\n\r\n setIsSpeaking(true);\r\n setTextSpeaking(text);\r\n\r\n if (notify && type !== false && onNotify) {\r\n onNotify(text, {\r\n type: nvl(type, defaultNotifyType),\r\n autoClose: nvl(options?.autoClose, defaultNotifyAutoClose),\r\n });\r\n }\r\n\r\n if (vibrate && shouldVibrate(type) && navigator.vibrate) {\r\n navigator.vibrate(vibrateDuration);\r\n }\r\n },\r\n [\r\n onNotify,\r\n shouldVibrate,\r\n vibrateDuration,\r\n defaultNotifyType,\r\n defaultNotifyAutoClose,\r\n ],\r\n );\r\n\r\n return { say, isSpeaking, textSpeaking, setIsSpeaking };\r\n}\r\n","import {\r\n getSpeechSupport,\r\n hasSpeechSupport,\r\n voicesAreEqual,\r\n} from \"./utils/constants\";\r\nimport { useEffect, useMemo, useState } from \"react\";\r\n\r\nexport function useSpeechPonyfill() {\r\n const ponyfill = useMemo(() => getSpeechSupport(), []);\r\n const [voices, setVoices] = useState<SpeechSynthesisVoice[]>([]);\r\n\r\n useEffect(() => {\r\n if (!hasSpeechSupport()) return;\r\n\r\n const synthesis = globalThis.speechSynthesis;\r\n\r\n const updateVoices = () => {\r\n setVoices((current) => {\r\n const next = synthesis.getVoices();\r\n return voicesAreEqual(current, next) ? current : next;\r\n });\r\n };\r\n\r\n synthesis.onvoiceschanged = updateVoices;\r\n updateVoices();\r\n\r\n return () => {\r\n synthesis.onvoiceschanged = null;\r\n };\r\n }, []);\r\n\r\n return { voices, ponyfill };\r\n}\r\n","\"use client\";\r\n\r\nimport {\r\n DEFAULT_SAY_PITCH,\r\n DEFAULT_SAY_RATE,\r\n DEFAULT_SAY_VOICE,\r\n DEFAULT_SAY_VOLUME,\r\n} from \"./utils/constants\";\r\nimport SayEngine from \"react-say\";\r\nexport { useSay } from \"./use-say\";\r\nimport React, { useCallback } from \"react\";\r\nimport type { SayProps } from \"./utils/interface\";\r\nimport { useSpeechPonyfill } from \"./use-speech-ponyfill\";\r\n\r\n/**\r\n * Sintetiza texto em fala via Web Speech API (`react-say`).\r\n * Use com {@link useSay} para controlar `isSpeaking`, `text` e `setIsSpeaking`.\r\n *\r\n * @example\r\n * ```tsx\r\n * const { say, isSpeaking, textSpeaking, setIsSpeaking } = useSay({\r\n * onNotify: (text, { type }) => toast(text, { type }),\r\n * });\r\n *\r\n * return (\r\n * <>\r\n * <Say\r\n * isSpeaking={isSpeaking}\r\n * text={textSpeaking}\r\n * setIsSpeaking={setIsSpeaking}\r\n * voice=\"Google português do Brasil\"\r\n * rate={1.4}\r\n * />\r\n * <button type=\"button\" onClick={() => say(\"Pronto\")}>Falar</button>\r\n * </>\r\n * );\r\n * ```\r\n */\r\nfunction Say({\r\n text,\r\n onEnd,\r\n onStart,\r\n isSpeaking,\r\n setIsSpeaking,\r\n rate = DEFAULT_SAY_RATE,\r\n voice = DEFAULT_SAY_VOICE,\r\n pitch = DEFAULT_SAY_PITCH,\r\n volume = DEFAULT_SAY_VOLUME,\r\n}: Readonly<SayProps>): React.ReactElement | null {\r\n const { voices, ponyfill } = useSpeechPonyfill();\r\n\r\n const handleEnd = useCallback(() => {\r\n setIsSpeaking(false);\r\n onEnd?.();\r\n }, [setIsSpeaking, onEnd]);\r\n\r\n if (!isSpeaking || voices.length === 0 || !ponyfill) return null;\r\n\r\n return (\r\n <SayEngine\r\n text={text}\r\n rate={rate}\r\n pitch={pitch}\r\n volume={volume}\r\n onEnd={handleEnd}\r\n onStart={onStart}\r\n ponyfill={ponyfill}\r\n voice={voices.find((v) => v.name === voice)}\r\n />\r\n );\r\n}\r\n\r\nexport default Say;\r\n"]}
@@ -45,6 +45,12 @@ function nvl(value, defaultValue) {
45
45
  function removeDigits(value) {
46
46
  return value.replace(/\D/g, "");
47
47
  }
48
+ function removeNonDigits(value) {
49
+ return value.replaceAll(/\d/g, "");
50
+ }
51
+ function removeTextOnly(value) {
52
+ return value.replaceAll(/[^\p{L}]/gu, "");
53
+ }
48
54
 
49
55
  // src/functions/format-cpf-cnpj/format-cpf-cnpj.ts
50
56
  function formatCpfCnpj(data) {
@@ -74,6 +80,39 @@ function formatPhoneBr(phone) {
74
80
  return digits.replace(/(\d{2})(\d{5})(\d+)/, "($1) $2-$3");
75
81
  }
76
82
 
77
- export { __objRest, __spreadProps, __spreadValues, cn, formatCpfCnpj, formatPhoneBr, nvl };
78
- //# sourceMappingURL=chunk-4DIPDYEU.mjs.map
79
- //# sourceMappingURL=chunk-4DIPDYEU.mjs.map
83
+ // src/functions/format-price-brl/format-price-brl.ts
84
+ function formatPriceBrl(value) {
85
+ if (value === void 0 || value === null) return "";
86
+ if (typeof value === "string") {
87
+ const digits = removeDigits(value);
88
+ if (!digits) return "";
89
+ const price = Number(digits) / 100;
90
+ if (Number.isNaN(price)) return "";
91
+ return price.toLocaleString("pt-BR", {
92
+ style: "currency",
93
+ currency: "BRL"
94
+ });
95
+ }
96
+ if (Number.isNaN(value)) return "";
97
+ return value.toLocaleString("pt-BR", { style: "currency", currency: "BRL" });
98
+ }
99
+
100
+ // src/functions/format-item-170/format-item-170.ts
101
+ function formatItem170(item) {
102
+ if (!item) return "";
103
+ const digits = removeDigits(item).slice(0, 12);
104
+ if (!digits) return "";
105
+ return digits.replace(/(\d{2})(\d)/, "$1.$2").replace(/(\d{2})(\d)/, "$1.$2").replace(/(\d{2})(\d)/, "$1.$2").replace(/(\d{2})(\d)/, "$1.$2").replace(/(\d{2})\.(\d)(\d{1,3})$/, "$1.$2.$3");
106
+ }
107
+
108
+ // src/functions/format-item-150/format-item-150.ts
109
+ function formatItem150(item) {
110
+ if (!item) return "";
111
+ const digits = removeDigits(item).slice(0, 10);
112
+ if (!digits) return "";
113
+ return digits.replace(/(\d{2})(\d)/, "$1.$2").replace(/(\d{2})(\d)/, "$1.$2").replace(/(\d{2})(\d)/, "$1.$2").replace(/(\d{2})\.(\d)(\d{1,3})$/, "$1.$2.$3");
114
+ }
115
+
116
+ export { __objRest, __spreadProps, __spreadValues, cn, formatCpfCnpj, formatItem150, formatItem170, formatPhoneBr, formatPriceBrl, nvl, removeDigits, removeNonDigits, removeTextOnly };
117
+ //# sourceMappingURL=chunk-BWW3F4R4.mjs.map
118
+ //# sourceMappingURL=chunk-BWW3F4R4.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/functions/cn/cn.ts","../src/functions/nvl/nvl.ts","../src/core/remove-digits.ts","../src/functions/format-cpf-cnpj/format-cpf-cnpj.ts","../src/functions/format-phone-br/format-phone-br.ts","../src/functions/format-price-brl/format-price-brl.ts","../src/functions/format-item-170/format-item-170.ts","../src/functions/format-item-150/format-item-150.ts"],"names":[],"mappings":"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","file":"chunk-BWW3F4R4.mjs","sourcesContent":["import { twMerge } from \"tailwind-merge\";\r\nimport { clsx } from \"clsx\";\r\nimport type { ClassValue } from \"./utils/interfaces\";\r\n\r\nexport function cn(...values: ClassValue[]): string {\r\n return twMerge(clsx(values));\r\n}\r\n","/**\r\n * Função NVL (Null Value Logic) - retorna valor padrão se o valor for null/undefined\r\n * @param {T | null | undefined} value - Valor a ser verificado\r\n * @param {T} defaultValue - Valor padrão a ser retornado se value for null/undefined\r\n * @returns {T} Value se não for null/undefined, senão defaultValue\r\n * @template T - Tipo do valor\r\n * @example\r\n * nvl(null, 'padrão') // Retorna: 'padrão'\r\n * nvl('valor', 'padrão') // Retorna: 'valor'\r\n */\r\nexport function nvl<T>(value: T | null | undefined, defaultValue: T): T {\r\n return value ?? defaultValue;\r\n}\r\n","/** Remove tudo que não for dígito. */\r\nexport function removeDigits(value: string): string {\r\n return value.replace(/\\D/g, \"\");\r\n}\r\n\r\n/** Remove tudo que não for número. */\r\nexport function removeNonDigits(value: string) {\r\n return value.replaceAll(/\\d/g, \"\");\r\n}\r\n\r\n/** Remove tudo que não for letra. */\r\nexport function removeTextOnly(value: string) {\r\n return value.replaceAll(/[^\\p{L}]/gu, \"\");\r\n}\r\n","import { removeDigits } from \"../../core/remove-digits\";\r\n\r\n/**\r\n * Formata CPF (até 11 dígitos) ou CNPJ (12–14 dígitos) conforme o tamanho.\r\n * @param data - Valor com ou sem formatação\r\n * @returns CPF `000.000.000-00` ou CNPJ `00.000.000/0000-00`; string vazia se ausente\r\n * @example\r\n * formatCpfCnpj(\"12345678901\") // \"123.456.789-01\"\r\n * formatCpfCnpj(\"12345678000199\") // \"12.345.678/0001-99\"\r\n */\r\nexport function formatCpfCnpj(data?: string): string {\r\n if (!data) return \"\";\r\n const value = removeDigits(data);\r\n\r\n if (!value) return \"\";\r\n if (value.length <= 11) {\r\n const cpf = value.slice(0, 11);\r\n return cpf\r\n .replace(/(\\d{3})(\\d)/, \"$1.$2\")\r\n .replace(/(\\d{3})(\\d)/, \"$1.$2\")\r\n .replace(/(\\d{3})(\\d{1,2})$/, \"$1-$2\");\r\n }\r\n\r\n const cnpj = value.slice(0, 14);\r\n return cnpj\r\n .replace(/^(\\d{2})(\\d)/, \"$1.$2\")\r\n .replace(/^(\\d{2})\\.(\\d{3})(\\d)/, \"$1.$2.$3\")\r\n .replace(/\\.(\\d{3})(\\d)/, \".$1/$2\")\r\n .replace(/(\\d{4})(\\d)/, \"$1-$2\");\r\n}\r\n","import { removeDigits } from \"../../core/remove-digits\";\r\n\r\n/**\r\n * Formata telefone brasileiro (até 11 dígitos): fixo `(00) 0000-0000` ou celular `(00) 00000-0000`.\r\n * @param phone - Valor com ou sem formatação\r\n * @returns Telefone formatado ou string vazia se ausente\r\n * @example\r\n * formatPhoneBr(\"11987654321\") // \"(11) 98765-4321\"\r\n * formatPhoneBr(\"1133334444\") // \"(11) 3333-4444\"\r\n */\r\nexport function formatPhoneBr(phone?: string): string {\r\n if (!phone) return \"\";\r\n const digits = removeDigits(phone).slice(0, 11);\r\n\r\n if (!digits) return \"\";\r\n if (digits.length <= 2) return digits;\r\n if (digits.length <= 6) {\r\n return digits.replace(/(\\d{2})(\\d+)/, \"($1) $2\");\r\n }\r\n if (digits.length <= 10) {\r\n return digits.replace(/(\\d{2})(\\d{4})(\\d+)/, \"($1) $2-$3\");\r\n }\r\n return digits.replace(/(\\d{2})(\\d{5})(\\d+)/, \"($1) $2-$3\");\r\n}\r\n","import { removeDigits } from \"../../core/remove-digits\";\r\n\r\n/**\r\n * Formata um valor como moeda brasileira (BRL).\r\n *\r\n * - **string** — máscara de input: remove não dígitos, divide por 100 (centavos)\r\n * - **number** — valor já em reais\r\n *\r\n * @param value - Valor digitado ou numérico em reais\r\n * @returns Valor formatado (ex.: `R$ 1.234,56`) ou string vazia se ausente\r\n * @example\r\n * formatPriceBrl(\"123456\") // \"R$ 1.234,56\" (input)\r\n * formatPriceBrl(1234.56) // \"R$ 1.234,56\" (número)\r\n * formatPriceBrl(0) // \"R$ 0,00\"\r\n */\r\nexport function formatPriceBrl(value?: string | number | null): string {\r\n if (value === undefined || value === null) return \"\";\r\n\r\n if (typeof value === \"string\") {\r\n const digits = removeDigits(value);\r\n if (!digits) return \"\";\r\n const price = Number(digits) / 100;\r\n if (Number.isNaN(price)) return \"\";\r\n return price.toLocaleString(\"pt-BR\", {\r\n style: \"currency\",\r\n currency: \"BRL\",\r\n });\r\n }\r\n\r\n if (Number.isNaN(value)) return \"\";\r\n return value.toLocaleString(\"pt-BR\", { style: \"currency\", currency: \"BRL\" });\r\n}\r\n","import { removeDigits } from \"../../core/remove-digits\";\r\n\r\n/**\r\n * Formata máscara de item 170 (até 12 dígitos) no padrão `00.00.00.00.0.000`.\r\n * Remove caracteres não numéricos antes de formatar.\r\n * @param item - Valor com ou sem formatação\r\n * @returns Item formatado ou string vazia se ausente\r\n * @example\r\n * formatItem170(\"123456789012\") // \"12.34.56.78.9.012\"\r\n */\r\nexport function formatItem170(item?: string): string {\r\n if (!item) return \"\";\r\n const digits = removeDigits(item).slice(0, 12);\r\n if (!digits) return \"\";\r\n\r\n return digits\r\n .replace(/(\\d{2})(\\d)/, \"$1.$2\")\r\n .replace(/(\\d{2})(\\d)/, \"$1.$2\")\r\n .replace(/(\\d{2})(\\d)/, \"$1.$2\")\r\n .replace(/(\\d{2})(\\d)/, \"$1.$2\")\r\n .replace(/(\\d{2})\\.(\\d)(\\d{1,3})$/, \"$1.$2.$3\");\r\n}\r\n","import { removeDigits } from \"../../core/remove-digits\";\r\n\r\n/**\r\n * Formata máscara de item 150 (até 10 dígitos) no padrão `00.00.00.0.000`.\r\n * Remove caracteres não numéricos antes de formatar.\r\n * @param item - Valor com ou sem formatação\r\n * @returns Item formatado ou string vazia se ausente\r\n * @example\r\n * formatItem150(\"1234567890\") // \"12.34.56.7.890\"\r\n */\r\nexport function formatItem150(item?: string): string {\r\n if (!item) return \"\";\r\n const digits = removeDigits(item).slice(0, 10);\r\n if (!digits) return \"\";\r\n\r\n return digits\r\n .replace(/(\\d{2})(\\d)/, \"$1.$2\")\r\n .replace(/(\\d{2})(\\d)/, \"$1.$2\")\r\n .replace(/(\\d{2})(\\d)/, \"$1.$2\")\r\n .replace(/(\\d{2})\\.(\\d)(\\d{1,3})$/, \"$1.$2.$3\");\r\n}\r\n"]}