@tutti-os/ui-react-hooks 0.0.17 → 0.0.19

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/index.js CHANGED
@@ -39,6 +39,7 @@ function useComposedInputValue({
39
39
  value
40
40
  }) {
41
41
  const pendingCommitRef = useRef(null);
42
+ const isComposingRef = useRef(false);
42
43
  const [localValue, setLocalValue] = useState(value);
43
44
  const [isComposing, setIsComposing] = useState(false);
44
45
  useEffect(() => {
@@ -72,17 +73,19 @@ function useComposedInputValue({
72
73
  },
73
74
  onChange: (event) => {
74
75
  const nextValue = event.currentTarget.value;
75
- if (!isComposing) {
76
+ if (!isComposingRef.current) {
76
77
  commitValue(nextValue);
77
78
  return;
78
79
  }
79
80
  setLocalValue(nextValue);
80
81
  },
81
82
  onCompositionEnd: (event) => {
83
+ isComposingRef.current = false;
82
84
  setIsComposing(false);
83
85
  commitValue(event.currentTarget.value);
84
86
  },
85
87
  onCompositionStart: () => {
88
+ isComposingRef.current = true;
86
89
  setIsComposing(true);
87
90
  },
88
91
  value: localValue
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/useComposedInputValue.ts","../src/useExternalStoreSelector.ts","../src/useExternalStoreSnapshot.ts"],"sourcesContent":["import {\n useEffect,\n useRef,\n useState,\n type ChangeEvent,\n type CompositionEvent,\n type FocusEvent\n} from \"react\";\n\nexport interface ComposedInputPendingCommit {\n committedValue: string;\n previousValue: string;\n}\n\nexport interface ComposedInputValueSyncInput {\n isComposing: boolean;\n localValue: string;\n pendingCommit: ComposedInputPendingCommit | null;\n value: string;\n}\n\nexport interface ComposedInputValueSyncResult {\n pendingCommit: ComposedInputPendingCommit | null;\n shouldSyncLocalValue: boolean;\n value: string;\n}\n\nexport interface UseComposedInputValueInput {\n onCommit: (value: string) => void;\n value: string;\n}\n\nexport interface UseComposedInputValueResult {\n clearValue: () => void;\n commitValue: (value: string) => void;\n isComposing: boolean;\n onBlur: (event: FocusEvent<HTMLInputElement>) => void;\n onChange: (event: ChangeEvent<HTMLInputElement>) => void;\n onCompositionEnd: (event: CompositionEvent<HTMLInputElement>) => void;\n onCompositionStart: () => void;\n value: string;\n}\n\nexport function resolveComposedInputValueSync(\n input: ComposedInputValueSyncInput\n): ComposedInputValueSyncResult {\n if (input.isComposing) {\n return {\n pendingCommit: input.pendingCommit,\n shouldSyncLocalValue: false,\n value: input.localValue\n };\n }\n\n if (input.pendingCommit !== null) {\n if (input.value === input.pendingCommit.committedValue) {\n return {\n pendingCommit: null,\n shouldSyncLocalValue: input.localValue !== input.value,\n value: input.value\n };\n }\n\n if (\n input.localValue === input.pendingCommit.committedValue &&\n input.value === input.pendingCommit.previousValue\n ) {\n return {\n pendingCommit: input.pendingCommit,\n shouldSyncLocalValue: false,\n value: input.localValue\n };\n }\n }\n\n return {\n pendingCommit: null,\n shouldSyncLocalValue: input.localValue !== input.value,\n value: input.value\n };\n}\n\nexport function useComposedInputValue({\n onCommit,\n value\n}: UseComposedInputValueInput): UseComposedInputValueResult {\n const pendingCommitRef = useRef<ComposedInputPendingCommit | null>(null);\n const [localValue, setLocalValue] = useState(value);\n const [isComposing, setIsComposing] = useState(false);\n\n useEffect(() => {\n const syncResult = resolveComposedInputValueSync({\n isComposing,\n localValue,\n pendingCommit: pendingCommitRef.current,\n value\n });\n\n pendingCommitRef.current = syncResult.pendingCommit;\n if (syncResult.shouldSyncLocalValue) {\n setLocalValue(syncResult.value);\n }\n }, [isComposing, localValue, value]);\n\n const commitValue = (nextValue: string) => {\n pendingCommitRef.current = {\n committedValue: nextValue,\n previousValue: value\n };\n setLocalValue(nextValue);\n onCommit(nextValue);\n };\n\n return {\n clearValue: () => {\n commitValue(\"\");\n },\n commitValue,\n isComposing,\n onBlur: (event: FocusEvent<HTMLInputElement>) => {\n commitValue(event.currentTarget.value);\n },\n onChange: (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = event.currentTarget.value;\n if (!isComposing) {\n commitValue(nextValue);\n return;\n }\n setLocalValue(nextValue);\n },\n onCompositionEnd: (event: CompositionEvent<HTMLInputElement>) => {\n setIsComposing(false);\n commitValue(event.currentTarget.value);\n },\n onCompositionStart: () => {\n setIsComposing(true);\n },\n value: localValue\n };\n}\n","import { useRef, useSyncExternalStore } from \"react\";\nimport type { ExternalStoreSnapshotSource } from \"./types.ts\";\n\nexport function useExternalStoreSelector<TSnapshot, TResult>(\n source: ExternalStoreSnapshotSource<TSnapshot>,\n selector: (snapshot: TSnapshot) => TResult\n): TResult {\n const selectedSnapshotRef = useRef<{\n selector: (snapshot: TSnapshot) => TResult;\n snapshot: TSnapshot;\n value: TResult;\n } | null>(null);\n\n const readSelection = (snapshot: TSnapshot) => {\n const selectedSnapshot = selectedSnapshotRef.current;\n if (\n selectedSnapshot?.snapshot === snapshot &&\n selectedSnapshot.selector === selector\n ) {\n return selectedSnapshot.value;\n }\n\n const value = selector(snapshot);\n selectedSnapshotRef.current = { selector, snapshot, value };\n return value;\n };\n\n return useSyncExternalStore(\n (listener) => source.subscribe(listener),\n () => readSelection(source.getSnapshot()),\n () => readSelection((source.getServerSnapshot ?? source.getSnapshot)())\n );\n}\n","import { useSyncExternalStore } from \"react\";\nimport type { ExternalStoreSnapshotSource } from \"./types.ts\";\n\nexport function useExternalStoreSnapshot<TSnapshot>(\n source: ExternalStoreSnapshotSource<TSnapshot>\n): TSnapshot {\n return useSyncExternalStore(\n (listener) => source.subscribe(listener),\n () => source.getSnapshot(),\n () => (source.getServerSnapshot ?? source.getSnapshot)()\n );\n}\n"],"mappings":";AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,OAIK;AAoCA,SAAS,8BACd,OAC8B;AAC9B,MAAI,MAAM,aAAa;AACrB,WAAO;AAAA,MACL,eAAe,MAAM;AAAA,MACrB,sBAAsB;AAAA,MACtB,OAAO,MAAM;AAAA,IACf;AAAA,EACF;AAEA,MAAI,MAAM,kBAAkB,MAAM;AAChC,QAAI,MAAM,UAAU,MAAM,cAAc,gBAAgB;AACtD,aAAO;AAAA,QACL,eAAe;AAAA,QACf,sBAAsB,MAAM,eAAe,MAAM;AAAA,QACjD,OAAO,MAAM;AAAA,MACf;AAAA,IACF;AAEA,QACE,MAAM,eAAe,MAAM,cAAc,kBACzC,MAAM,UAAU,MAAM,cAAc,eACpC;AACA,aAAO;AAAA,QACL,eAAe,MAAM;AAAA,QACrB,sBAAsB;AAAA,QACtB,OAAO,MAAM;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,eAAe;AAAA,IACf,sBAAsB,MAAM,eAAe,MAAM;AAAA,IACjD,OAAO,MAAM;AAAA,EACf;AACF;AAEO,SAAS,sBAAsB;AAAA,EACpC;AAAA,EACA;AACF,GAA4D;AAC1D,QAAM,mBAAmB,OAA0C,IAAI;AACvE,QAAM,CAAC,YAAY,aAAa,IAAI,SAAS,KAAK;AAClD,QAAM,CAAC,aAAa,cAAc,IAAI,SAAS,KAAK;AAEpD,YAAU,MAAM;AACd,UAAM,aAAa,8BAA8B;AAAA,MAC/C;AAAA,MACA;AAAA,MACA,eAAe,iBAAiB;AAAA,MAChC;AAAA,IACF,CAAC;AAED,qBAAiB,UAAU,WAAW;AACtC,QAAI,WAAW,sBAAsB;AACnC,oBAAc,WAAW,KAAK;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,aAAa,YAAY,KAAK,CAAC;AAEnC,QAAM,cAAc,CAAC,cAAsB;AACzC,qBAAiB,UAAU;AAAA,MACzB,gBAAgB;AAAA,MAChB,eAAe;AAAA,IACjB;AACA,kBAAc,SAAS;AACvB,aAAS,SAAS;AAAA,EACpB;AAEA,SAAO;AAAA,IACL,YAAY,MAAM;AAChB,kBAAY,EAAE;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA,QAAQ,CAAC,UAAwC;AAC/C,kBAAY,MAAM,cAAc,KAAK;AAAA,IACvC;AAAA,IACA,UAAU,CAAC,UAAyC;AAClD,YAAM,YAAY,MAAM,cAAc;AACtC,UAAI,CAAC,aAAa;AAChB,oBAAY,SAAS;AACrB;AAAA,MACF;AACA,oBAAc,SAAS;AAAA,IACzB;AAAA,IACA,kBAAkB,CAAC,UAA8C;AAC/D,qBAAe,KAAK;AACpB,kBAAY,MAAM,cAAc,KAAK;AAAA,IACvC;AAAA,IACA,oBAAoB,MAAM;AACxB,qBAAe,IAAI;AAAA,IACrB;AAAA,IACA,OAAO;AAAA,EACT;AACF;;;AC3IA,SAAS,UAAAA,SAAQ,4BAA4B;AAGtC,SAAS,yBACd,QACA,UACS;AACT,QAAM,sBAAsBA,QAIlB,IAAI;AAEd,QAAM,gBAAgB,CAAC,aAAwB;AAC7C,UAAM,mBAAmB,oBAAoB;AAC7C,QACE,kBAAkB,aAAa,YAC/B,iBAAiB,aAAa,UAC9B;AACA,aAAO,iBAAiB;AAAA,IAC1B;AAEA,UAAM,QAAQ,SAAS,QAAQ;AAC/B,wBAAoB,UAAU,EAAE,UAAU,UAAU,MAAM;AAC1D,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL,CAAC,aAAa,OAAO,UAAU,QAAQ;AAAA,IACvC,MAAM,cAAc,OAAO,YAAY,CAAC;AAAA,IACxC,MAAM,eAAe,OAAO,qBAAqB,OAAO,aAAa,CAAC;AAAA,EACxE;AACF;;;AChCA,SAAS,wBAAAC,6BAA4B;AAG9B,SAAS,yBACd,QACW;AACX,SAAOA;AAAA,IACL,CAAC,aAAa,OAAO,UAAU,QAAQ;AAAA,IACvC,MAAM,OAAO,YAAY;AAAA,IACzB,OAAO,OAAO,qBAAqB,OAAO,aAAa;AAAA,EACzD;AACF;","names":["useRef","useSyncExternalStore"]}
1
+ {"version":3,"sources":["../src/useComposedInputValue.ts","../src/useExternalStoreSelector.ts","../src/useExternalStoreSnapshot.ts"],"sourcesContent":["import {\n useEffect,\n useRef,\n useState,\n type ChangeEvent,\n type CompositionEvent,\n type FocusEvent\n} from \"react\";\n\nexport interface ComposedInputPendingCommit {\n committedValue: string;\n previousValue: string;\n}\n\nexport interface ComposedInputValueSyncInput {\n isComposing: boolean;\n localValue: string;\n pendingCommit: ComposedInputPendingCommit | null;\n value: string;\n}\n\nexport interface ComposedInputValueSyncResult {\n pendingCommit: ComposedInputPendingCommit | null;\n shouldSyncLocalValue: boolean;\n value: string;\n}\n\nexport interface UseComposedInputValueInput {\n onCommit: (value: string) => void;\n value: string;\n}\n\nexport interface UseComposedInputValueResult {\n clearValue: () => void;\n commitValue: (value: string) => void;\n isComposing: boolean;\n onBlur: (event: FocusEvent<HTMLInputElement>) => void;\n onChange: (event: ChangeEvent<HTMLInputElement>) => void;\n onCompositionEnd: (event: CompositionEvent<HTMLInputElement>) => void;\n onCompositionStart: () => void;\n value: string;\n}\n\nexport function resolveComposedInputValueSync(\n input: ComposedInputValueSyncInput\n): ComposedInputValueSyncResult {\n if (input.isComposing) {\n return {\n pendingCommit: input.pendingCommit,\n shouldSyncLocalValue: false,\n value: input.localValue\n };\n }\n\n if (input.pendingCommit !== null) {\n if (input.value === input.pendingCommit.committedValue) {\n return {\n pendingCommit: null,\n shouldSyncLocalValue: input.localValue !== input.value,\n value: input.value\n };\n }\n\n if (\n input.localValue === input.pendingCommit.committedValue &&\n input.value === input.pendingCommit.previousValue\n ) {\n return {\n pendingCommit: input.pendingCommit,\n shouldSyncLocalValue: false,\n value: input.localValue\n };\n }\n }\n\n return {\n pendingCommit: null,\n shouldSyncLocalValue: input.localValue !== input.value,\n value: input.value\n };\n}\n\nexport function useComposedInputValue({\n onCommit,\n value\n}: UseComposedInputValueInput): UseComposedInputValueResult {\n const pendingCommitRef = useRef<ComposedInputPendingCommit | null>(null);\n const isComposingRef = useRef(false);\n const [localValue, setLocalValue] = useState(value);\n const [isComposing, setIsComposing] = useState(false);\n\n useEffect(() => {\n const syncResult = resolveComposedInputValueSync({\n isComposing,\n localValue,\n pendingCommit: pendingCommitRef.current,\n value\n });\n\n pendingCommitRef.current = syncResult.pendingCommit;\n if (syncResult.shouldSyncLocalValue) {\n setLocalValue(syncResult.value);\n }\n }, [isComposing, localValue, value]);\n\n const commitValue = (nextValue: string) => {\n pendingCommitRef.current = {\n committedValue: nextValue,\n previousValue: value\n };\n setLocalValue(nextValue);\n onCommit(nextValue);\n };\n\n return {\n clearValue: () => {\n commitValue(\"\");\n },\n commitValue,\n isComposing,\n onBlur: (event: FocusEvent<HTMLInputElement>) => {\n commitValue(event.currentTarget.value);\n },\n onChange: (event: ChangeEvent<HTMLInputElement>) => {\n const nextValue = event.currentTarget.value;\n if (!isComposingRef.current) {\n commitValue(nextValue);\n return;\n }\n setLocalValue(nextValue);\n },\n onCompositionEnd: (event: CompositionEvent<HTMLInputElement>) => {\n isComposingRef.current = false;\n setIsComposing(false);\n commitValue(event.currentTarget.value);\n },\n onCompositionStart: () => {\n isComposingRef.current = true;\n setIsComposing(true);\n },\n value: localValue\n };\n}\n","import { useRef, useSyncExternalStore } from \"react\";\nimport type { ExternalStoreSnapshotSource } from \"./types.ts\";\n\nexport function useExternalStoreSelector<TSnapshot, TResult>(\n source: ExternalStoreSnapshotSource<TSnapshot>,\n selector: (snapshot: TSnapshot) => TResult\n): TResult {\n const selectedSnapshotRef = useRef<{\n selector: (snapshot: TSnapshot) => TResult;\n snapshot: TSnapshot;\n value: TResult;\n } | null>(null);\n\n const readSelection = (snapshot: TSnapshot) => {\n const selectedSnapshot = selectedSnapshotRef.current;\n if (\n selectedSnapshot?.snapshot === snapshot &&\n selectedSnapshot.selector === selector\n ) {\n return selectedSnapshot.value;\n }\n\n const value = selector(snapshot);\n selectedSnapshotRef.current = { selector, snapshot, value };\n return value;\n };\n\n return useSyncExternalStore(\n (listener) => source.subscribe(listener),\n () => readSelection(source.getSnapshot()),\n () => readSelection((source.getServerSnapshot ?? source.getSnapshot)())\n );\n}\n","import { useSyncExternalStore } from \"react\";\nimport type { ExternalStoreSnapshotSource } from \"./types.ts\";\n\nexport function useExternalStoreSnapshot<TSnapshot>(\n source: ExternalStoreSnapshotSource<TSnapshot>\n): TSnapshot {\n return useSyncExternalStore(\n (listener) => source.subscribe(listener),\n () => source.getSnapshot(),\n () => (source.getServerSnapshot ?? source.getSnapshot)()\n );\n}\n"],"mappings":"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","names":["useRef","useSyncExternalStore"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tutti-os/ui-react-hooks",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "types": "./dist/index.d.ts",