From e053eab170b832945ffbfab7eac6e56509a8a8c8 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 6 Mar 2026 15:16:27 -0800 Subject: [PATCH 01/10] fix type errors with strict builds --- .../src/component-patterns/phasedComponent.ts | 30 ++--- .../src/component-patterns/render.ts | 11 +- .../src/immutable-merge/Merge.test.ts | 37 +++---- .../src/immutable-merge/Merge.ts | 87 +++++---------- packages/framework-base/src/index.ts | 7 +- .../src/memo-cache/getCacheEntry.test.ts | 12 +- .../src/memo-cache/getCacheEntry.ts | 10 +- .../src/memo-cache/getMemoCache.test.ts | 4 +- .../src/memo-cache/getMemoCache.ts | 8 +- .../framework-base/src/merge-props/index.ts | 1 - .../src/merge-props/mergeProps.ts | 5 +- .../src/merge-props/mergeStyles.test.ts | 2 +- .../src/merge-props/mergeStyles.ts | 65 ++--------- .../src/merge-props/mergeStyles.types.ts | 9 -- .../framework-base/src/utilities/baseTypes.ts | 28 +++++ .../src/utilities/baseTypes.validate.ts | 104 ++++++++++++++++++ .../src/utilities/filterProps.ts | 7 +- .../src/utilities/mergeTypes.ts | 55 +++++++++ .../framework-base/src/utilities/typeUtils.ts | 53 +++++++++ 19 files changed, 347 insertions(+), 188 deletions(-) delete mode 100644 packages/framework-base/src/merge-props/mergeStyles.types.ts create mode 100644 packages/framework-base/src/utilities/baseTypes.ts create mode 100644 packages/framework-base/src/utilities/baseTypes.validate.ts create mode 100644 packages/framework-base/src/utilities/mergeTypes.ts create mode 100644 packages/framework-base/src/utilities/typeUtils.ts diff --git a/packages/framework-base/src/component-patterns/phasedComponent.ts b/packages/framework-base/src/component-patterns/phasedComponent.ts index 6193707cd27..8614211e5d9 100644 --- a/packages/framework-base/src/component-patterns/phasedComponent.ts +++ b/packages/framework-base/src/component-patterns/phasedComponent.ts @@ -17,20 +17,22 @@ export function getPhasedRender(component: React.ComponentType): // if this has a phased render function, return it if ((component as PhasedComponent)._phasedRender) { return (component as PhasedComponent)._phasedRender; - } else if ((component as ComposableFunction)._staged) { + } else { // for backward compatibility check for staged render and return a wrapper that maps the signature const staged = (component as ComposableFunction)._staged; - return (props: TProps) => { - const { children, ...rest } = props as React.PropsWithChildren; - const inner = staged(rest as TProps, ...React.Children.toArray(children)); - // staged render functions were not consistently marking contents as composable, though they were treated - // as such in useHook. To maintain compatibility we mark the returned function as composable here. This was - // dangerous, but this shim is necessary for backward compatibility. The newer pattern is explicit about this. - if (typeof inner === 'function' && !(inner as LegacyDirectComponent)._canCompose) { - return Object.assign(inner, { _canCompose: true }); - } - return inner; - }; + if (staged) { + return (props: TProps) => { + const { children, ...rest } = props as React.PropsWithChildren; + const inner = staged(rest as TProps, ...React.Children.toArray(children)); + // staged render functions were not consistently marking contents as composable, though they were treated + // as such in useHook. To maintain compatibility we mark the returned function as composable here. This was + // dangerous, but this shim is necessary for backward compatibility. The newer pattern is explicit about this. + if (typeof inner === 'function' && !(inner as LegacyDirectComponent)._canCompose) { + return Object.assign(inner, { _canCompose: true }); + } + return inner; + }; + } } } return undefined; @@ -43,9 +45,9 @@ export function getPhasedRender(component: React.ComponentType): */ export function phasedComponent(getInnerPhase: PhasedRender): FunctionComponent { return Object.assign( - (props: React.PropsWithChildren) => { + (props: TProps) => { // pull out children from props - const { children, ...outerProps } = props; + const { children, ...outerProps } = props as React.PropsWithChildren; const Inner = getInnerPhase(outerProps as TProps); return renderForJsxRuntime(Inner, { children }); }, diff --git a/packages/framework-base/src/component-patterns/render.ts b/packages/framework-base/src/component-patterns/render.ts index 22358450714..ceef1ad405e 100644 --- a/packages/framework-base/src/component-patterns/render.ts +++ b/packages/framework-base/src/component-patterns/render.ts @@ -1,6 +1,7 @@ import React from 'react'; import * as ReactJSX from 'react/jsx-runtime'; import type { RenderType, RenderResult, DirectComponent, LegacyDirectComponent } from './render.types.ts'; +import { extractChildren, splitPropsAndChildren } from '../utilities/typeUtils.ts'; export type CustomRender = () => RenderResult; @@ -20,13 +21,13 @@ function asLegacyDirectComponent(type: RenderType): LegacyDirectComponen export function renderForJsxRuntime( type: React.ElementType, - props: React.PropsWithChildren, + props: TProps, key?: React.Key, - jsxFn: typeof ReactJSX.jsx = undefined, + jsxFn?: typeof ReactJSX.jsx, ): RenderResult { const legacyDirect = asLegacyDirectComponent(type); if (legacyDirect) { - const { children, ...rest } = props; + const [rest, children] = splitPropsAndChildren(props); const newProps = { ...rest, key }; return legacyDirect(newProps, ...React.Children.toArray(children)) as RenderResult; } @@ -38,14 +39,14 @@ export function renderForJsxRuntime( // auto-detect whether to use jsx or jsxs based on number of children, 0 or 1 = jsx, more than 1 = jsxs if (!jsxFn) { - if (React.Children.count(props.children) > 1) { + if (React.Children.count(extractChildren(props)) > 1) { jsxFn = ReactJSX.jsxs; } else { jsxFn = ReactJSX.jsx; } } // Extract key from props to avoid React 19 warning about spreading key prop - // eslint-disable-next-line @typescript-eslint/no-explicit-any + const { key: propsKey, ...propsWithoutKey } = props as any; // Use explicitly passed key, or fall back to key from props const finalKey = key ?? propsKey; diff --git a/packages/framework-base/src/immutable-merge/Merge.test.ts b/packages/framework-base/src/immutable-merge/Merge.test.ts index 4985beecbc9..0f579e34916 100644 --- a/packages/framework-base/src/immutable-merge/Merge.test.ts +++ b/packages/framework-base/src/immutable-merge/Merge.test.ts @@ -99,11 +99,6 @@ const mergeOptions: MergeOptions = { }, }; -interface IDeepObj { - a: { b: { c: number } }; - b: { c: { d: { d: string } } }; -} - const deep1 = { a: { b: { c: 1 } }, b: { c: { d: { d: 'foo' } } }, @@ -183,9 +178,9 @@ describe('Immutable merge unit tests', () => { const obj1 = { a: 'a', b: 1 }; const obj2 = { b: 2, c: true }; const merged = { a: 'a', b: 2, c: true }; - expect(immutableMerge(obj1, obj2)).toEqual(merged); - expect(immutableMergeCore(0, obj1, obj2)).toEqual(merged); - expect(immutableMergeCore(true, obj1, obj2)).toEqual(merged); + expect(immutableMerge(obj1, obj2)).toEqual(merged); + expect(immutableMergeCore(0, obj1, obj2)).toEqual(merged); + expect(immutableMergeCore(true, obj1, obj2)).toEqual(merged); }); const dm1 = { @@ -199,14 +194,14 @@ describe('Immutable merge unit tests', () => { }; test('deep merge', () => { - expect(immutableMerge(dm1, dm2)).toEqual({ + expect(immutableMerge(dm1, dm2)).toEqual({ a: { b: { c: { foo: 'foo', bar: 'bar2', baz: 'baz' } }, i: 'world' }, d: { e: 1, f: { g: 'hello', h: 2 }, j: 4 }, }); }); test('merge zero levels', () => { - expect(immutableMergeCore(0, dm1, dm2)).toEqual(dm2); + expect(immutableMergeCore(0, dm1, dm2)).toEqual(dm2); }); test('merge one level deep', () => { @@ -214,8 +209,8 @@ describe('Immutable merge unit tests', () => { a: dm2.a, d: { ...dm1.d, ...dm2.d }, }; - expect(immutableMergeCore(1, dm1, dm2)).toEqual(result); - expect(immutableMergeCore({ object: 0 }, dm1, dm2)).toEqual(result); + expect(immutableMergeCore(1, dm1, dm2)).toEqual(result); + expect(immutableMergeCore({ object: 0 }, dm1, dm2)).toEqual(result); }); test('merge with empty object', () => { @@ -226,14 +221,14 @@ describe('Immutable merge unit tests', () => { }); test('merge sett1 and sett2', () => { - const merged = immutableMergeCore(mergeOptions, sett1, sett2) as IFakeSettings; + const merged = immutableMergeCore(mergeOptions, sett1, sett2); expect(merged).toEqual(sett1plus2); - expect(merged!.root.style).toBe(sett1.root.style); + expect(merged!.root!.style).toBe(sett1.root!.style); expect(merged!.fakeSlot!.style).toBe(sett2.fakeSlot!.style); }); test('merge sett1 and sett3', () => { - const merged = immutableMergeCore(mergeOptions, sett1, sett3) as IFakeSettings; + const merged = immutableMergeCore(mergeOptions, sett1, sett3); expect(merged).toEqual(sett1plus3); expect(merged!.fakeSlot).toBe(sett1.fakeSlot); }); @@ -244,7 +239,7 @@ describe('Immutable merge unit tests', () => { }); test('deepMerge', () => { - const merged = immutableMergeCore(-1, deep1, deep2) as IDeepObj; + const merged = immutableMergeCore(-1, deep1, deep2); expect(merged).toEqual(deepMerged); expect(merged.b.c.d).toBe(deep1.b.c.d); expect(merged.a.b).not.toBe(deep2.a.b); @@ -259,14 +254,14 @@ describe('Immutable merge unit tests', () => { const merged = processImmutable(changeMeOption1, singleToChange); expect(merged).toEqual(singleWithChanges); expect(merged).not.toBe(singleToChange); - expect((merged as any).b).toBe(singleToChange.b); + expect(merged.b).toBe(singleToChange.b); }); test('single process with change - alternative', () => { const merged = processImmutable(changeMeOption2, singleToChange); expect(merged).toEqual(singleWithChanges); expect(merged).not.toBe(singleToChange); - expect((merged as any).b).toBe(singleToChange.b); + expect(merged.b).toBe(singleToChange.b); }); const withArray1 = { @@ -296,15 +291,15 @@ describe('Immutable merge unit tests', () => { }; test('last writer wins for objects and non-objects', () => { - const merged = immutableMerge(withObj, withNonObj); + const merged = immutableMerge(withObj, withNonObj); expect(merged).toEqual(withNonObj); - const merged2 = immutableMerge(withNonObj, withObj); + const merged2 = immutableMerge(withNonObj, withObj); expect(merged2).toEqual(withObj); }); const arrayMerger = (...targets: any[]) => { const arrays = targets.filter((t) => Array.isArray(t)); - let result = []; + let result: any[] = []; for (const v of arrays) { if (v.length > 0) { result = result.concat(...v); diff --git a/packages/framework-base/src/immutable-merge/Merge.ts b/packages/framework-base/src/immutable-merge/Merge.ts index b77d9577d0a..804b93d2919 100644 --- a/packages/framework-base/src/immutable-merge/Merge.ts +++ b/packages/framework-base/src/immutable-merge/Merge.ts @@ -1,3 +1,6 @@ +import { getEntityType, isObject } from '../utilities/typeUtils.ts'; +import type { ObjectMerger, ObjectMergerWithOptions } from '../utilities/mergeTypes.ts'; + /** * The basic options for recursion at a given level. Two types for two behaviors: * @@ -28,19 +31,6 @@ export type BuiltinRecursionHandlers = 'appendArray'; */ export type RecursionHandler = BuiltinRecursionHandlers | CustomRecursionHandler; -/** - * Base object type for merges, avoids using object since that is too broad. In particular things like null and arrays - * are not valid object types for the purposes of this library. - */ -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -export type ObjectBase = {}; - -/** - * - */ -export type TypeofResult = 'undefined' | 'object' | 'boolean' | 'number' | 'string' | 'symbol' | 'bigint' | 'function'; -export type ExpandedTypeof = TypeofResult | 'array' | 'null'; - /** * configuration object for the merge, key names are matched with a few exceptions: * - object: matches non-array object types @@ -51,6 +41,12 @@ export interface MergeOptions { [objectTypeOrKeyName: string]: RecursionOption | RecursionHandler | MergeOptions; } +/** + * Union type for the options parameter of the merge core function, this allows for either a simple recursion option + * that applies to all keys and types, or a full configuration object for more control. + */ +export type MergeCoreOptions = RecursionOption | MergeOptions; + /** * built in handlers for the module */ @@ -72,25 +68,6 @@ function normalizeOptions(options: RecursionOption | MergeOptions): [MergeOption : [options, true]; } -/** - * Provide a more sensible type result that expands upon the built in typeof operator - * In particular this will differentiate arrays and nulls from standard objects - * @param val - value to check type - */ -function getEntityType(val: unknown): ExpandedTypeof { - switch (typeof val) { - case 'object': - if (val === null) { - return 'null'; - } else if (Array.isArray(val)) { - return 'array'; - } - return 'object'; - default: - return typeof val as TypeofResult; - } -} - /** resolve custom handlers if they are applicable */ function resolveIfHandler(option: RecursionHandler | RecursionOption | MergeOptions): CustomRecursionHandler | MergeOptions | undefined { return typeof option === 'function' ? option : typeof option === 'string' ? _builtinHandlers[option] : undefined; @@ -141,22 +118,13 @@ function getHandlerForPropertyOfType( return result; } -/** - * Assign properties of source objects to a new target object. This is just a type wrapper around Object.assign - * @param objs - array of objects to merge - * @returns the result of object assign on the objects, typed to T - */ -function assignToNewObject(...objs: T[]): T { - return Object.assign({}, ...objs); -} - /** * Filter a set of unknown values to only include those that extend ObjectBase * @param values - array of values to filter * @returns the filtered set of values */ -export function filterToObjects(values: unknown[]): T[] { - return values.filter((v) => v && getEntityType(v) === 'object' && Object.getOwnPropertyNames(v).length > 0) as T[]; +export function filterToObjects>(values: unknown[]): T[] { + return values.filter((v) => v && isObject(v) && Object.getOwnPropertyNames(v).length > 0) as T[]; } /** @@ -172,15 +140,19 @@ export function filterToObjects(values: unkno * is true the routine will progress through all branches of the hierarchy. Useful if using a processor function that needs to be run. * @param objs - an array of objects to merge together */ -function immutableMergeWorker(mergeOptions: RecursionOption | MergeOptions, singleMode: boolean, ...objs: T[]): T { - const setToMerge = filterToObjects(objs); +function immutableMergeWorker( + mergeOptions: RecursionOption | MergeOptions, + singleMode: boolean, + ...objs: unknown[] +): Record | undefined { + const setToMerge = filterToObjects(objs); const [options, mightRecurse] = normalizeOptions(mergeOptions); const processSingle = singleMode && setToMerge.length === 1; // there is work to do if there is more than one object to merge or if we are processing single objects if (setToMerge.length > 1 || (processSingle && setToMerge.length === 1)) { // now assign everything to get the normal property precedence (and merge all the keys) - let result = processSingle ? undefined : assignToNewObject(...setToMerge); + let result = processSingle ? undefined : Object.assign({}, ...setToMerge); const processSet = result || setToMerge[0]; for (const key in processSet) { @@ -193,11 +165,9 @@ function immutableMergeWorker(mergeOptions: RecursionOptio if (handler !== undefined) { const values = setToMerge.map((set) => set[key]).filter((v) => v !== undefined); const updatedVal = - typeof handler === 'function' - ? handler(...values) - : immutableMergeWorker(handler, singleMode, ...filterToObjects(values)); + typeof handler === 'function' ? handler(...values) : immutableMergeWorker(handler, singleMode, ...filterToObjects(values)); if (updatedVal !== originalVal) { - result = result || assignToNewObject(...setToMerge); + result = result || Object.assign({}, ...setToMerge); result[key] = updatedVal; } } @@ -222,9 +192,7 @@ function immutableMergeWorker(mergeOptions: RecursionOptio * * @param objs - variable input array of typed objects to merge */ -export function immutableMerge(...objs: (T | undefined)[]): T | undefined { - return immutableMergeWorker(true, false, ...objs); -} +export const immutableMerge: ObjectMerger = (...objs: unknown[]) => immutableMergeWorker(false, false, ...objs); /** * Version of immutable merge that can be configured to behave in a variety of manners. See the documentation for details. @@ -232,12 +200,8 @@ export function immutableMerge(...objs: (T | undefined)[]) * @param options - configuration options for the merge, this dictates what keys will be handled in what way * @param objs - set of objects to merge together */ -export function immutableMergeCore( - options: RecursionOption | MergeOptions, - ...objs: (T | undefined)[] -): T | undefined { - return immutableMergeWorker(options, false, ...objs); -} +export const immutableMergeCore: ObjectMergerWithOptions = (options: MergeCoreOptions, ...objs: unknown[]) => + immutableMergeWorker(options, false, ...objs); /** * Process one or more immutable objects ensuring that handlers are called on every entry that applies. If a single object @@ -250,6 +214,5 @@ export function immutableMergeCore( * @param processors - set of processor functions for handling keys * @param objs - one or more objects to process. If multiple objects are passed they will be merged */ -export function processImmutable(options: MergeOptions, ...objs: (T | undefined)[]): T | undefined { - return immutableMergeWorker(options, true, ...objs); -} +export const processImmutable: ObjectMergerWithOptions = (options: MergeOptions, ...objs: unknown[]) => + immutableMergeWorker(options, true, ...objs); diff --git a/packages/framework-base/src/index.ts b/packages/framework-base/src/index.ts index 58f5af762e7..ee17d8e0fd9 100644 --- a/packages/framework-base/src/index.ts +++ b/packages/framework-base/src/index.ts @@ -4,7 +4,6 @@ export type { BuiltinRecursionHandlers, CustomRecursionHandler, MergeOptions, - ObjectBase, RecursionHandler, RecursionOption, } from './immutable-merge/Merge.ts'; @@ -15,7 +14,6 @@ export { getMemoCache, getTypedMemoCache } from './memo-cache/getMemoCache.ts'; export { memoize } from './memo-cache/memoize.ts'; // merge-props exports -export type { StyleProp } from './merge-props/mergeStyles.types.ts'; export { mergeStyles } from './merge-props/mergeStyles.ts'; export { mergeProps } from './merge-props/mergeProps.ts'; @@ -58,3 +56,8 @@ export type { FurnJSX } from './jsx-namespace.ts'; // general utilities export { filterProps } from './utilities/filterProps.ts'; export type { PropsFilter } from './utilities/filterProps.ts'; + +// core type utilities exports +export type { StyleProp, ObjectBase, ObjectFallback } from './utilities/baseTypes.ts'; +export type { ObjectMerger, ObjectMergerWithOptions, StyleMerger } from './utilities/mergeTypes.ts'; +export type { ExpandedTypeof, TypeofResult } from './utilities/typeUtils.ts'; diff --git a/packages/framework-base/src/memo-cache/getCacheEntry.test.ts b/packages/framework-base/src/memo-cache/getCacheEntry.test.ts index eaf12873a47..ca74351f4c7 100644 --- a/packages/framework-base/src/memo-cache/getCacheEntry.test.ts +++ b/packages/framework-base/src/memo-cache/getCacheEntry.test.ts @@ -40,34 +40,34 @@ describe('Memo cache unit tests', () => { test('string gets keyed correctly', () => { const base: TestEntry = {}; const key = 'foo'; - expect(getCacheEntry(base, [key])).toBe(base.str[key]); + expect(getCacheEntry(base, [key])).toBe(base.str![key]); }); test('number gets keyed correctly', () => { const base: TestEntry = {}; const val = 235; const key = val + ''; - expect(getCacheEntry(base, [val])).toBe(base.str[key]); + expect(getCacheEntry(base, [val])).toBe(base.str![key]); }); test('bool gets keyed correctly', () => { const base: TestEntry = {}; const val = true; const key = val + ''; - expect(getCacheEntry(base, [val])).toBe(base.str[key]); + expect(getCacheEntry(base, [val])).toBe(base.str![key]); }); test('false bool gets keyed correctly', () => { const base: TestEntry = {}; const val = false; const key = val + ''; - expect(getCacheEntry(base, [val])).toBe(base.str[key]); + expect(getCacheEntry(base, [val])).toBe(base.str![key]); }); test('object gets keyed correctly', () => { const base: TestEntry = {}; const key = {}; - expect(getCacheEntry(base, [key])).toBe(base.obj.get(key)); + expect(getCacheEntry(base, [key])).toBe(base.obj!.get(key)); }); test('function gets keyed correctly', () => { @@ -75,7 +75,7 @@ describe('Memo cache unit tests', () => { const key = () => { return 'hello world'; }; - expect(getCacheEntry(base, [key])).toBe(base.obj.get(key)); + expect(getCacheEntry(base, [key])).toBe(base.obj!.get(key)); }); test('basic string retrieval', () => { diff --git a/packages/framework-base/src/memo-cache/getCacheEntry.ts b/packages/framework-base/src/memo-cache/getCacheEntry.ts index 5d7b6206458..c8f9f16db79 100644 --- a/packages/framework-base/src/memo-cache/getCacheEntry.ts +++ b/packages/framework-base/src/memo-cache/getCacheEntry.ts @@ -35,7 +35,13 @@ function jumpToCacheEntry(entry: CacheEntry, val: any): CacheEntry { if (typeof val === 'object' || typeof val === 'function') { // objects and functions will be treated as key values in a WeakMap const byObj = (entry.obj ??= new WeakMap()); - return byObj.get(val) || byObj.set(val, {}).get(val); + + let newEntry = byObj.get(val); + if (!newEntry) { + newEntry = {}; + byObj.set(val, newEntry); + } + return newEntry; } // otherwise convert everything to a string and store it in the str object (using it as a map) const key = val + ''; @@ -49,7 +55,7 @@ function jumpToCacheEntry(entry: CacheEntry, val: any): CacheEntry { * @param entry - entry to use as the base of the cache walk * @param args - array of arguments to use to progress deeper into the cache */ -export function getCacheEntry(entry: CacheEntry, args: unknown[]): CacheEntry { +export function getCacheEntry(entry: CacheEntry, args?: unknown[]): CacheEntry { // in the case where the args array exists and is > 0 length: // - walk the cache from entry, like a linked list, jumping to the next entry by key, building it up as you go // - otherwise if there are no args just use the noargs branch diff --git a/packages/framework-base/src/memo-cache/getMemoCache.test.ts b/packages/framework-base/src/memo-cache/getMemoCache.test.ts index a43b1ab8bc8..934e432b298 100644 --- a/packages/framework-base/src/memo-cache/getMemoCache.test.ts +++ b/packages/framework-base/src/memo-cache/getMemoCache.test.ts @@ -58,8 +58,8 @@ describe('getMemoCache unit tests', () => { test('memo calls function only once for empty inputs', () => { const memoValue = getMemoCache(); const fn = getObjFactory(); - const [o1] = memoValue(fn, undefined); - const [o2] = memoValue(fn, undefined); + const [o1] = memoValue(fn, []); + const [o2] = memoValue(fn, []); expect(o2).toBe(o1); }); diff --git a/packages/framework-base/src/memo-cache/getMemoCache.ts b/packages/framework-base/src/memo-cache/getMemoCache.ts index ae656cc8dde..b02cfd52675 100644 --- a/packages/framework-base/src/memo-cache/getMemoCache.ts +++ b/packages/framework-base/src/memo-cache/getMemoCache.ts @@ -8,8 +8,8 @@ export type ValueFactory = () => T; * - Typed: the cache will enforce the type of both the factory and returned value * - Untyped: the cache will infer the type on each call from the factory return value */ -export type GetTypedMemoValue = (factory: T | ValueFactory, keys: unknown[]) => [T, GetTypedMemoValue]; -export type GetMemoValue = (factory: T | ValueFactory, keys: unknown[]) => [T, GetMemoValue]; +export type GetTypedMemoValue = (factory: T | ValueFactory, keys?: unknown[]) => [T, GetTypedMemoValue]; +export type GetMemoValue = (factory: T | ValueFactory, keys?: unknown[]) => [T, GetMemoValue]; /** base node used to remember references when a globalKey is set */ const _baseEntry: CacheEntry = {}; @@ -21,13 +21,13 @@ const _baseEntry: CacheEntry = {}; * @param factory - generally a function who's results will be cached, and returned via the set of keys * @param keys - an ordered array of values of any type, used as keys to look up the entry */ -function getMemoValueWorker(entry: CacheEntry, factory: T | ValueFactory, keys: unknown[]): [T, GetMemoValue] { +function getMemoValueWorker(entry: CacheEntry, factory: T | ValueFactory, keys?: unknown[]): [T, GetMemoValue] { const foundEntry = getCacheEntry(entry, keys); // check the key being set, not the value to disambiguate an undefined factory result/value from never having run the factory if (!Object.prototype.hasOwnProperty.call(foundEntry, 'value')) { foundEntry.value = typeof factory === 'function' ? (factory as ValueFactory)() : factory; } - return [foundEntry.value as T, (fact: U | ValueFactory, args: unknown[]) => getMemoValueWorker(foundEntry, fact, args)]; + return [foundEntry.value as T, (fact: U | ValueFactory, args?: unknown[]) => getMemoValueWorker(foundEntry, fact, args)]; } /** diff --git a/packages/framework-base/src/merge-props/index.ts b/packages/framework-base/src/merge-props/index.ts index e8a4571f2a9..ddc67901d81 100644 --- a/packages/framework-base/src/merge-props/index.ts +++ b/packages/framework-base/src/merge-props/index.ts @@ -1,3 +1,2 @@ -export type { StyleProp } from './mergeStyles.types.ts'; export { mergeStyles } from './mergeStyles.ts'; export { mergeProps } from './mergeProps.ts'; diff --git a/packages/framework-base/src/merge-props/mergeProps.ts b/packages/framework-base/src/merge-props/mergeProps.ts index 2332b5037d4..0bd62a3f20e 100644 --- a/packages/framework-base/src/merge-props/mergeProps.ts +++ b/packages/framework-base/src/merge-props/mergeProps.ts @@ -1,5 +1,6 @@ import type { MergeOptions } from '../immutable-merge/Merge.ts'; import { immutableMergeCore, filterToObjects } from '../immutable-merge/Merge.ts'; +import type { ObjectMerger } from '../utilities/mergeTypes.ts'; import { mergeStyles } from './mergeStyles.ts'; @@ -15,6 +16,4 @@ const mergePropsOptions: MergeOptions = { * Merge props together, flattening and merging styles as appropriate * @param props - props to merge together */ -export function mergeProps(...props: (TProps | undefined)[]): TProps { - return immutableMergeCore(mergePropsOptions, ...filterToObjects(props)); -} +export const mergeProps: ObjectMerger = (...props: unknown[]) => immutableMergeCore(mergePropsOptions, ...filterToObjects(props)); diff --git a/packages/framework-base/src/merge-props/mergeStyles.test.ts b/packages/framework-base/src/merge-props/mergeStyles.test.ts index 3642e18910e..52201117741 100644 --- a/packages/framework-base/src/merge-props/mergeStyles.test.ts +++ b/packages/framework-base/src/merge-props/mergeStyles.test.ts @@ -1,5 +1,5 @@ import { flattenStyle, mergeAndFlattenStyles, mergeStyles } from './mergeStyles.ts'; -import type { StyleProp } from './mergeStyles.types.ts'; +import type { StyleProp } from '../utilities/baseTypes.ts'; type OpaqueColorValue = symbol & { __TYPE__: 'Color' }; type ColorValue = string | OpaqueColorValue; diff --git a/packages/framework-base/src/merge-props/mergeStyles.ts b/packages/framework-base/src/merge-props/mergeStyles.ts index 75f1bc2d5d7..46b4c611a63 100644 --- a/packages/framework-base/src/merge-props/mergeStyles.ts +++ b/packages/framework-base/src/merge-props/mergeStyles.ts @@ -1,16 +1,18 @@ import { immutableMerge } from '../immutable-merge/Merge.ts'; import { getMemoCache } from '../memo-cache/getMemoCache.ts'; +import type { StyleMerger } from '../utilities/mergeTypes.ts'; -import type { StyleProp } from './mergeStyles.types.ts'; +import type { StyleProp } from '../utilities/baseTypes.ts'; /** * Take a react-native style, which may be a recursive array, and return as a flattened - * style. This is analagous to the flatten routine that is part of the style sheet API + * style. This is analogous to the flatten routine that is part of the style sheet API * * @param style - StyleProp to flatten, this can be a TStyle or an array + * @internal */ -export function flattenStyle(style: StyleProp): T { - return Array.isArray(style) ? immutableMerge(...style.map((v) => flattenStyle(v))) : ((style || {}) as T); +export function flattenStyle(style: StyleProp): object { + return Array.isArray(style) ? (immutableMerge(...style.map((v) => flattenStyle(v))) as object) : style || {}; } /** @@ -19,31 +21,14 @@ export function flattenStyle(style: StyleProp): T { * @param styles - array of styles to merge together. The styles will be flattened as part of the process */ -// Overload for 2 arguments with potentially different types -export function mergeAndFlattenStyles( - style1: StyleProp, - style2: StyleProp, -): (T1 & T2) | undefined; - -// Overload for 3 arguments with potentially different types -export function mergeAndFlattenStyles( - style1: StyleProp, - style2: StyleProp, - style3: StyleProp, -): (T1 & T2 & T3) | undefined; - -// General fallback for any number of arguments of the same type -export function mergeAndFlattenStyles(...styles: StyleProp[]): TStyle | undefined; - -// Implementation -export function mergeAndFlattenStyles(...styles: StyleProp[]): object | undefined { +export const mergeAndFlattenStyles: StyleMerger = (...styles: StyleProp[]) => { // baseline merge and flatten the objects return immutableMerge( - ...styles.map((styleProp: StyleProp) => { + ...styles.map((styleProp: StyleProp) => { return flattenStyle(styleProp); }), ); -} +}; const _styleCache = getMemoCache(); @@ -51,38 +36,12 @@ const _styleCache = getMemoCache(); * Function overloads to allow merging styles of different types. * This is useful when merging token-based styles with React Native StyleProp types. */ - -// Overload for 1 argument, forces flattening of sub arrays -export function mergeStyles(style1: StyleProp): T1 | undefined; - -// Overload for 2 arguments with potentially different types -export function mergeStyles(style1: StyleProp, style2: StyleProp): (T1 & T2) | undefined; - -// Overload for 3 arguments with potentially different types -export function mergeStyles( - style1: StyleProp, - style2: StyleProp, - style3: StyleProp, -): (T1 & T2 & T3) | undefined; - -// Overload for 4 arguments with potentially different types -export function mergeStyles( - style1: StyleProp, - style2: StyleProp, - style3: StyleProp, - style4: StyleProp, -): (T1 & T2 & T3 & T4) | undefined; - -// General fallback for any number of arguments of the same type -export function mergeStyles(...styles: StyleProp[]): TStyle | undefined; - -// Implementation -export function mergeStyles(...styles: StyleProp[]): object | undefined { +export const mergeStyles: StyleMerger = (...styles: StyleProp[]) => { // filter the style set to just objects (which might be arrays or plain style objects) - const inputs = styles.filter((s) => typeof s === 'object') as object[]; + const inputs = styles.filter((s) => s !== null && typeof s === 'object'); // now memo the results if there is more than one element or if the one element is an array return inputs.length > 1 || (inputs.length === 1 && Array.isArray(inputs[0])) ? _styleCache(() => mergeAndFlattenStyles(undefined, ...inputs), inputs)[0] : inputs[0] || {}; -} +}; diff --git a/packages/framework-base/src/merge-props/mergeStyles.types.ts b/packages/framework-base/src/merge-props/mergeStyles.types.ts deleted file mode 100644 index 5a2e3b38560..00000000000 --- a/packages/framework-base/src/merge-props/mergeStyles.types.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * This is a copy of the react-native style prop type, copied here to avoid RN dependencies for web clients - */ -type Falsy = undefined | null | false | '' | 0; -type RecursiveArray = readonly (T | RecursiveArray)[] | (T | RecursiveArray)[]; -/** Keep a brand of 'T' so that calls to `StyleSheet.flatten` can take `RegisteredStyle` and return `T`. */ -type RegisteredStyle = number & { __registeredStyleBrand: T }; - -export type StyleProp = T | RegisteredStyle | RecursiveArray | Falsy> | Falsy; diff --git a/packages/framework-base/src/utilities/baseTypes.ts b/packages/framework-base/src/utilities/baseTypes.ts new file mode 100644 index 00000000000..38cefe36f53 --- /dev/null +++ b/packages/framework-base/src/utilities/baseTypes.ts @@ -0,0 +1,28 @@ +/** + * This is a copy of the react-native style prop type, copied here to avoid RN dependencies this early in the dependency tree. + */ +type Falsy = undefined | null | false | ''; +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +interface RecursiveArray extends Array | RecursiveArray> {} +/** Keep a brand of 'T' so that calls to `StyleSheet.flatten` can take `RegisteredStyle` and return `T`. */ +type RegisteredStyle = number & { __registeredStyleBrand: T }; +export type StyleProp = T | RegisteredStyle | RecursiveArray | Falsy> | Falsy; + +/** + * This is the baseline for acceptance object types, meaning for T extends ObjectBase. The options here + * are: + * - {} an empty object, which works but is a bit too loose for general use + * - Record which is fine with types but doesn't work with + * interfaces as they have no implicit index signature + * - object which is the built in object type, slightly stricter than {} but still allows for interfaces + * + * There's no perfect option here but object is the best overall choice. + */ +export type ObjectBase = object; + +/** + * For fallback object types it is better to use the stricter Record type, as it + * is more likely to catch issues with unexpected properties and is still compatible with the + * ObjectBase type. + */ +export type ObjectFallback = Record; diff --git a/packages/framework-base/src/utilities/baseTypes.validate.ts b/packages/framework-base/src/utilities/baseTypes.validate.ts new file mode 100644 index 00000000000..3c5d6ae9d62 --- /dev/null +++ b/packages/framework-base/src/utilities/baseTypes.validate.ts @@ -0,0 +1,104 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +/** + * Type validation that the base types behave as expected. This code is never run and is not included + * in other files, but will cause build breaks if the types no longer behave as expected. + */ + +import type { StyleProp, ObjectBase, ObjectFallback } from './baseTypes.ts'; +import type { StyleProp as RNStyleProp } from 'react-native'; + +/** + * Validate that StyleProp is compatible with React Native's StyleProp type, as this is a critical part of our type system for styles and we want to ensure it remains compatible with RN's types. + */ +export type ValidateStyleProp = StyleProp extends RNStyleProp ? true : never; + +type StyleBase = { + color?: string; + fontSize?: number; +}; + +type TestProps = { + p1?: string; + p2?: number; + p3?: boolean; + style?: StyleProp; +}; + +const typeProps: TestProps = { + p1: 'string', + p2: 123, + p3: true, + style: { + color: 'red', + fontSize: 16, + }, +}; + +interface IStyleBase { + color?: string; + fontSize?: number; +} + +interface ITestProps { + p1?: string; + p2?: number; + p3?: boolean; + style?: StyleProp; +} + +const interfaceProps: ITestProps = { + p1: 'string', + p2: 123, + p3: true, + style: { + color: 'red', + fontSize: 16, + }, +}; + +export function validateBaseTypes() { + // This function is never called, but if the types of the base types change in a way that breaks compatibility with expected types, this will cause a build error and alert us to the issue. + + // Test that StyleProp is compatible with React Native's StyleProp type + const stylePropTest: ValidateStyleProp = true; + const stylePropTest2: ValidateStyleProp = true; + + // just using the values to stop typescript complaints + if (!stylePropTest || !stylePropTest2) { + throw new Error("StyleProp is not compatible with React Native's StyleProp type"); + } + + // Test that ObjectBase is compatible with object and Record + + const objectBaseTest1: ObjectBase = {}; + const objectBaseTest2: ObjectBase = { key: 'value' }; + const objectBaseTest3: ObjectBase = new Date(); + const objectBaseTest4: ObjectBase = typeProps; + const objectBaseTest5: ObjectBase = interfaceProps; + const objectBaseTest6: ObjectFallback = {}; + const objectBaseTest7: ObjectFallback = { key: 'value' }; + // @ts-expect-error - this should error because Date is not compatible with Record due to its properties not being string keys and unknown values + const objectBaseTest8: ObjectFallback = new Date(); + const objectBaseTest9: ObjectFallback = typeProps; + // @ts-expect-error - this should error because interfaceProps is not compatible with Record due to the style property being a StyleProp type which is not compatible with Record + const objectBaseTest10: ObjectFallback = interfaceProps; + + // cross assignment + const baseFromFallback: ObjectBase = objectBaseTest7; + // @ts-expect-error - this should error because ObjectFallback is not compatible with ObjectBase due to ObjectBase allowing for more types of objects than ObjectFallback + const fallbackFromBase: ObjectFallback = objectBaseTest2; + + return { + ...objectBaseTest1, + ...objectBaseTest2, + ...objectBaseTest3, + ...objectBaseTest4, + ...objectBaseTest5, + ...objectBaseTest6, + ...objectBaseTest7, + ...objectBaseTest8, + ...objectBaseTest9, + ...objectBaseTest10, + ...baseFromFallback, + }; +} diff --git a/packages/framework-base/src/utilities/filterProps.ts b/packages/framework-base/src/utilities/filterProps.ts index c1c86435ab5..d78c5c003f4 100644 --- a/packages/framework-base/src/utilities/filterProps.ts +++ b/packages/framework-base/src/utilities/filterProps.ts @@ -1,13 +1,14 @@ import { mergeProps } from '../merge-props/mergeProps.ts'; +import { isObject } from './typeUtils.ts'; export type PropsFilter = (propName: string) => boolean; export function filterProps(props: TProps, filter?: PropsFilter): TProps { - if (filter && typeof props === 'object' && !Array.isArray(props)) { - const propsToRemove = filter ? Object.keys(props).filter((key) => !filter(key)) : undefined; + if (filter && isObject(props)) { + const propsToRemove = filter ? Object.keys(props).filter((key) => !filter(key)) : []; if (propsToRemove?.length > 0) { const propsToRemoveObj = Object.fromEntries(propsToRemove.map((prop) => [prop, undefined])) as TProps; - return mergeProps(props, propsToRemoveObj); + return mergeProps(props, propsToRemoveObj); } } return props; diff --git a/packages/framework-base/src/utilities/mergeTypes.ts b/packages/framework-base/src/utilities/mergeTypes.ts new file mode 100644 index 00000000000..ae9d67e9b84 --- /dev/null +++ b/packages/framework-base/src/utilities/mergeTypes.ts @@ -0,0 +1,55 @@ +import type { StyleProp, ObjectFallback } from './baseTypes.ts'; + +/** + * Overloaded function types for an object merger, similar to Object.assign but with better type inference and support for + * undefined values. + */ +export type ObjectMerger = { + // T1 defined overloads + (o1: T1, ...objs: undefined[]): T1; + (o1: T1, o2: T2, ...objs: undefined[]): T1 & T2; + (o1: T1, o2: T2, o3: T3, ...objs: undefined[]): T1 & T2 & T3; + // T1 undefined overloads + (o1: undefined, o2: T2, ...objs: undefined[]): T2; + (o1: undefined, o2: T2, o3: T3, ...objs: undefined[]): T2 & T3; + // T2 undefined overload + (o1: T1, o2: undefined, o3: T3, ...objs: undefined[]): T1 & T3; + // rest overloads + (...objs: unknown[]): T | undefined; +}; + +/** + * Overloaded function types for an object merger that takes options, similar to Object.assign but with better type inference and support for + * undefined values, and with an options parameter to control merge behavior. + */ +export type ObjectMergerWithOptions = { + // T1 defined overloads + (opt: TOptions, o1: T1, ...objs: undefined[]): T1; + (opt: TOptions, o1: T1, o2: T2, ...objs: undefined[]): T1 & T2; + (opt: TOptions, o1: T1, o2: T2, o3: T3, ...objs: undefined[]): T1 & T2 & T3; + // T1 undefined overloads + (opt: TOptions, o1: undefined, o2: T2, ...objs: undefined[]): T2; + (opt: TOptions, o1: undefined, o2: T2, o3: T3, ...objs: undefined[]): T2 & T3; + // T2 undefined overload + (opt: TOptions, o1: T1, o2: undefined, o3: T3, ...objs: undefined[]): T1 & T3; + // rest overloads + (opt: TOptions, ...objs: unknown[]): T | undefined; +}; + +/** + * Overloaded function types for a style merger, which is similar to an object merger but specifically for merging styles that may be in the form of StyleProp types. + * This includes support for merging styles of different types, which is useful when merging token-based styles with React Native StyleProp types. + */ +export type StyleMerger = { + // T1 defined overloads + (o1: StyleProp, ...objs: undefined[]): T1; + (o1: StyleProp, o2: StyleProp, ...objs: undefined[]): T1 & T2; + (o1: StyleProp, o2: StyleProp, o3: StyleProp, ...objs: undefined[]): T1 & T2 & T3; + // T1 undefined overloads + (o1: StyleProp, o2: StyleProp, ...objs: undefined[]): T2; + (o1: StyleProp, o2: StyleProp, o3: StyleProp, ...objs: undefined[]): T2 & T3; + // T2 undefined overload + (o1: StyleProp, o2: StyleProp, o3: StyleProp, ...objs: undefined[]): T1 & T3; + // rest overloads + (...objs: unknown[]): T | undefined; +}; diff --git a/packages/framework-base/src/utilities/typeUtils.ts b/packages/framework-base/src/utilities/typeUtils.ts new file mode 100644 index 00000000000..02850270f2b --- /dev/null +++ b/packages/framework-base/src/utilities/typeUtils.ts @@ -0,0 +1,53 @@ +/** + * + */ +export type TypeofResult = 'undefined' | 'object' | 'boolean' | 'number' | 'string' | 'symbol' | 'bigint' | 'function'; +export type ExpandedTypeof = TypeofResult | 'array' | 'null'; + +/** + * Provide a more sensible type result that expands upon the built in typeof operator + * In particular this will differentiate arrays and nulls from standard objects + * @param val - value to check type + */ +export function getEntityType(val: unknown): ExpandedTypeof { + switch (typeof val) { + case 'object': + if (val === null) { + return 'null'; + } else if (Array.isArray(val)) { + return 'array'; + } + return 'object'; + default: + return typeof val as TypeofResult; + } +} + +/** + * Assertion function for types related to objects (objects with string keys and some value types). + * This is used to narrow down types in situations where we want to ensure we are working with a plain + * object and not something else (like an array or null). + * @param value some value of unknown type + * @returns an assertion that the value is an object with string keys and unknown values (not an array or null) + */ +export function isObject>(value: unknown): value is T { + return typeof value === 'object' && value !== null && !Array.isArray(value); +} + +/** + * Helper to split props into children and non-children props. + * @param props unknown props type object to split + * @returns a tuple of the non-children props and the children + */ +export function splitPropsAndChildren(props: TProps): [Omit, React.ReactNode] { + const { children, ...rest } = props as React.PropsWithChildren; + return [rest as Omit, children]; +} + +/** + * Helper to get the children from an unknown props type object. + */ +export function extractChildren(props: TProps): React.ReactNode { + const { children } = props as React.PropsWithChildren; + return children; +} From 0e45ca13bcd95887a9edf49052694bf5c98d764f Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 6 Mar 2026 15:21:45 -0800 Subject: [PATCH 02/10] fix bug in merge from rework --- .../src/immutable-merge/Merge.ts | 2 +- packages/framework-base/tsconfig.json | 2 -- yarn.lock | 27 +++++++++++++++++-- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/packages/framework-base/src/immutable-merge/Merge.ts b/packages/framework-base/src/immutable-merge/Merge.ts index 804b93d2919..54f90e4f9e4 100644 --- a/packages/framework-base/src/immutable-merge/Merge.ts +++ b/packages/framework-base/src/immutable-merge/Merge.ts @@ -192,7 +192,7 @@ function immutableMergeWorker( * * @param objs - variable input array of typed objects to merge */ -export const immutableMerge: ObjectMerger = (...objs: unknown[]) => immutableMergeWorker(false, false, ...objs); +export const immutableMerge: ObjectMerger = (...objs: unknown[]) => immutableMergeWorker(true, false, ...objs); /** * Version of immutable merge that can be configured to behave in a variety of manners. See the documentation for details. diff --git a/packages/framework-base/tsconfig.json b/packages/framework-base/tsconfig.json index b0dd41f41f6..83975437e4d 100644 --- a/packages/framework-base/tsconfig.json +++ b/packages/framework-base/tsconfig.json @@ -2,8 +2,6 @@ "extends": "@fluentui-react-native/scripts/tsconfig", "compilerOptions": { "outDir": "lib", - "allowJs": true, - "checkJs": true, "rootDir": "src" }, "include": ["src"] diff --git a/yarn.lock b/yarn.lock index 045b2ee7eb8..8c723322e53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -339,7 +339,20 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.20.0, @babel/generator@npm:^7.25.0, @babel/generator@npm:^7.28.6, @babel/generator@npm:^7.29.0, @babel/generator@npm:^7.29.1, @babel/generator@npm:^7.7.2": +"@babel/generator@npm:^7.20.0, @babel/generator@npm:^7.25.0, @babel/generator@npm:^7.28.6, @babel/generator@npm:^7.7.2": + version: 7.28.6 + resolution: "@babel/generator@npm:7.28.6" + dependencies: + "@babel/parser": "npm:^7.28.6" + "@babel/types": "npm:^7.28.6" + "@jridgewell/gen-mapping": "npm:^0.3.12" + "@jridgewell/trace-mapping": "npm:^0.3.28" + jsesc: "npm:^3.0.2" + checksum: 10c0/162fa358484a9a18e8da1235d998f10ea77c63bab408c8d3e327d5833f120631a77ff022c5ed1d838ee00523f8bb75df1f08196d3657d0bca9f2cfeb8503cc12 + languageName: node + linkType: hard + +"@babel/generator@npm:^7.29.0, @babel/generator@npm:^7.29.1": version: 7.29.1 resolution: "@babel/generator@npm:7.29.1" dependencies: @@ -1954,7 +1967,17 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.2, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.5, @babel/types@npm:^7.28.6, @babel/types@npm:^7.29.0, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.2, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.5, @babel/types@npm:^7.28.6, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": + version: 7.28.6 + resolution: "@babel/types@npm:7.28.6" + dependencies: + "@babel/helper-string-parser": "npm:^7.27.1" + "@babel/helper-validator-identifier": "npm:^7.28.5" + checksum: 10c0/54a6a9813e48ef6f35aa73c03b3c1572cad7fa32b61b35dd07e4230bc77b559194519c8a4d8106a041a27cc7a94052579e238a30a32d5509aa4da4d6fd83d990 + languageName: node + linkType: hard + +"@babel/types@npm:^7.29.0": version: 7.29.0 resolution: "@babel/types@npm:7.29.0" dependencies: From 0f28a3050f3538d36415856a7f9f459e998b9656 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Fri, 6 Mar 2026 16:15:11 -0800 Subject: [PATCH 03/10] convert more packages to stricter types and fix tests --- .../__snapshots__/ToggleButton.test.tsx.snap | 2 +- .../__snapshots__/Chip.test.tsx.snap | 6 ++--- .../__snapshots__/Switch.test.tsx.snap | 6 +++-- .../src/component-patterns/render.types.ts | 2 +- packages/framework-base/tsconfig.json | 2 +- .../framework/use-slot/src/useSlot.test.tsx | 1 + packages/framework/use-slot/src/useSlot.ts | 2 +- packages/framework/use-slot/tsconfig.json | 2 +- packages/utils/adapters/src/filterProps.ts | 8 +++--- packages/utils/adapters/tsconfig.json | 2 +- .../src/__tests__/events.types.test.ts | 14 +++++------ .../interactive-hooks/src/useAsPressable.ts | 25 ++++++++++--------- .../src/useAsPressable.types.ts | 5 ++-- .../interactive-hooks/src/useAsToggle.ts | 2 +- .../src/useAsToggleWithEvent.ts | 2 +- .../interactive-hooks/src/usePressability.ts | 1 + .../src/usePressableState.ts | 14 ++++++----- .../utils/interactive-hooks/tsconfig.json | 2 +- 18 files changed, 52 insertions(+), 46 deletions(-) diff --git a/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap b/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap index bff788bf319..d580c17b25c 100644 --- a/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap +++ b/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap @@ -14,7 +14,7 @@ exports[`ToggleButton default 1`] = ` accessibilityState={ { "busy": undefined, - "checked": undefined, + "checked": false, "disabled": false, "expanded": undefined, "selected": undefined, diff --git a/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap b/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap index 56bd2b201fb..86e60907b09 100644 --- a/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap +++ b/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap @@ -5,7 +5,7 @@ exports[`Chip component tests Chip all props 1`] = ` accessibilityState={ { "busy": undefined, - "checked": undefined, + "checked": false, "disabled": undefined, "expanded": undefined, "selected": undefined, @@ -99,7 +99,7 @@ exports[`Chip component tests Chip tokens 1`] = ` accessibilityState={ { "busy": undefined, - "checked": undefined, + "checked": false, "disabled": undefined, "expanded": undefined, "selected": undefined, @@ -169,7 +169,7 @@ exports[`Chip component tests Empty Chip 1`] = ` accessibilityState={ { "busy": undefined, - "checked": undefined, + "checked": false, "disabled": undefined, "expanded": undefined, "selected": undefined, diff --git a/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap b/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap index 5e31d6bc58b..d2a214b0f7b 100644 --- a/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap +++ b/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap @@ -14,7 +14,7 @@ exports[`Switch Default 1`] = ` accessibilityState={ { "busy": undefined, - "checked": undefined, + "checked": false, "disabled": undefined, "expanded": undefined, "selected": undefined, @@ -29,6 +29,7 @@ exports[`Switch Default 1`] = ` } } accessible={true} + checked={false} collapsable={false} focusable={true} onAccessibilityAction={[Function]} @@ -140,7 +141,7 @@ exports[`Switch Disabled 1`] = ` accessibilityState={ { "busy": undefined, - "checked": undefined, + "checked": false, "disabled": true, "expanded": undefined, "selected": undefined, @@ -155,6 +156,7 @@ exports[`Switch Disabled 1`] = ` } } accessible={false} + checked={false} collapsable={false} focusable={false} onAccessibilityAction={[Function]} diff --git a/packages/framework-base/src/component-patterns/render.types.ts b/packages/framework-base/src/component-patterns/render.types.ts index df68822103d..8079be58e66 100644 --- a/packages/framework-base/src/component-patterns/render.types.ts +++ b/packages/framework-base/src/component-patterns/render.types.ts @@ -100,7 +100,7 @@ export type SlotFn = { * Children will be passed as part of the props for component rendering. The `children` prop will be * automatically inferred and typed correctly by the prop type. */ -export type PhasedRender = (props: TProps) => React.ComponentType>; +export type PhasedRender = (props: TProps) => React.ComponentType; /** * Component type for a component that can be rendered in two phases, with the attached phased render function. diff --git a/packages/framework-base/tsconfig.json b/packages/framework-base/tsconfig.json index 83975437e4d..7c5e7a85ebd 100644 --- a/packages/framework-base/tsconfig.json +++ b/packages/framework-base/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@fluentui-react-native/scripts/tsconfig", + "extends": "@fluentui-react-native/scripts/tsconfig-strict", "compilerOptions": { "outDir": "lib", "rootDir": "src" diff --git a/packages/framework/use-slot/src/useSlot.test.tsx b/packages/framework/use-slot/src/useSlot.test.tsx index 7a6a839260b..49615739ef2 100644 --- a/packages/framework/use-slot/src/useSlot.test.tsx +++ b/packages/framework/use-slot/src/useSlot.test.tsx @@ -121,6 +121,7 @@ describe('useSlot tests', () => { }); const tree2 = component2!.toJSON(); expect(tree2).toMatchSnapshot(); + // @ts-expect-error - we know the structure of the tree here and want to compare the text nodes directly, this is not a general pattern expect(tree1!['HeaderCaptionText1']).toEqual(tree2!['HeaderCaptionText2']); }); }); diff --git a/packages/framework/use-slot/src/useSlot.ts b/packages/framework/use-slot/src/useSlot.ts index f35c32a1019..bbd71ec1bc8 100644 --- a/packages/framework/use-slot/src/useSlot.ts +++ b/packages/framework/use-slot/src/useSlot.ts @@ -48,7 +48,7 @@ export function useSlot( const { propsToMerge, innerComponent } = slotData; if (propsToMerge) { // merge in props from phase one if they haven't been captured in the phased render - innerProps = mergeProps(propsToMerge, innerProps); + innerProps = mergeProps(propsToMerge, innerProps); } if (filter) { // filter the final props if a filter is specified diff --git a/packages/framework/use-slot/tsconfig.json b/packages/framework/use-slot/tsconfig.json index 83975437e4d..7c5e7a85ebd 100644 --- a/packages/framework/use-slot/tsconfig.json +++ b/packages/framework/use-slot/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@fluentui-react-native/scripts/tsconfig", + "extends": "@fluentui-react-native/scripts/tsconfig-strict", "compilerOptions": { "outDir": "lib", "rootDir": "src" diff --git a/packages/utils/adapters/src/filterProps.ts b/packages/utils/adapters/src/filterProps.ts index 30db1220afc..ae79d100976 100644 --- a/packages/utils/adapters/src/filterProps.ts +++ b/packages/utils/adapters/src/filterProps.ts @@ -1,6 +1,4 @@ import { getViewMask, getTextMask, getImageMask } from './filters'; -import type { ViewProps, TextProps, ImageProps } from 'react-native'; -import type { IFilterMask } from './filter.types'; /** * Filters props based on the provided mask. Each filter function is memoized to only compute the mask once, @@ -12,7 +10,7 @@ import type { IFilterMask } from './filter.types'; * @param propName - The name of the prop to check against the view mask */ export const filterViewProps = (() => { - let viewMask: IFilterMask | undefined; + let viewMask: Record | undefined; return (propName: string): boolean => { viewMask ??= getViewMask(); return Boolean(viewMask[propName]); @@ -24,7 +22,7 @@ export const filterViewProps = (() => { * @param propName - The name of the prop to check against the text mask */ export const filterTextProps = (() => { - let textMask: IFilterMask | undefined; + let textMask: Record | undefined; return (propName: string): boolean => { textMask ??= getTextMask(); return Boolean(textMask[propName]); @@ -36,7 +34,7 @@ export const filterTextProps = (() => { * @param propName - The name of the prop to check against the image mask */ export const filterImageProps = (() => { - let imageMask: IFilterMask | undefined; + let imageMask: Record | undefined; return (propName: string): boolean => { imageMask ??= getImageMask(); return Boolean(imageMask[propName]); diff --git a/packages/utils/adapters/tsconfig.json b/packages/utils/adapters/tsconfig.json index 83975437e4d..7c5e7a85ebd 100644 --- a/packages/utils/adapters/tsconfig.json +++ b/packages/utils/adapters/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@fluentui-react-native/scripts/tsconfig", + "extends": "@fluentui-react-native/scripts/tsconfig-strict", "compilerOptions": { "outDir": "lib", "rootDir": "src" diff --git a/packages/utils/interactive-hooks/src/__tests__/events.types.test.ts b/packages/utils/interactive-hooks/src/__tests__/events.types.test.ts index 6685f5b264b..8edae17b2a5 100644 --- a/packages/utils/interactive-hooks/src/__tests__/events.types.test.ts +++ b/packages/utils/interactive-hooks/src/__tests__/events.types.test.ts @@ -3,7 +3,7 @@ import type { AccessibilityActionEvent, GestureResponderEvent } from 'react-nati import { isAccessibilityActionEvent, isGestureResponderEvent, isKeyPressEvent } from '../events.types'; import type { KeyPressEvent } from '../useKeyProps.types'; -const createMockEvent = (nativeEvent) => { +const createMockEvent = (nativeEvent: Record) => { return { nativeEvent: nativeEvent, currentTarget: null, @@ -33,7 +33,7 @@ const createMockEvent = (nativeEvent) => { }; }; -const mockGestureEvent: GestureResponderEvent = createMockEvent({ +const mockGestureEvent = createMockEvent({ changedTouches: [], identifier: '', locationX: 0, @@ -43,15 +43,15 @@ const mockGestureEvent: GestureResponderEvent = createMockEvent({ target: '', timestamp: 0, touches: [], -}); +}) as unknown as GestureResponderEvent; -const mockKeyPressEvent: KeyPressEvent = createMockEvent({ +const mockKeyPressEvent = createMockEvent({ key: 'enter', -}); +}) as unknown as KeyPressEvent; -const mockAccessibilityEvent: AccessibilityActionEvent = createMockEvent({ +const mockAccessibilityEvent = createMockEvent({ actionName: 'longpress', -}); +}) as unknown as AccessibilityActionEvent; describe('InteractionEvent type guard tests', () => { it('has correct output from isGestureResponderEvent when input is type GestureResponderEvent', () => { diff --git a/packages/utils/interactive-hooks/src/useAsPressable.ts b/packages/utils/interactive-hooks/src/useAsPressable.ts index db84d13a61d..b79aa31db74 100644 --- a/packages/utils/interactive-hooks/src/useAsPressable.ts +++ b/packages/utils/interactive-hooks/src/useAsPressable.ts @@ -8,11 +8,12 @@ import type { IHoverState, IFocusState, IWithPressableEvents, + IWithPartialPressableEvents, } from './useAsPressable.types'; +import type { BlurEvent, FocusEvent, MouseEvent, GestureResponderEvent } from 'react-native'; import type { PressableFocusProps, PressableHoverProps, PressablePressProps } from './usePressableState.types'; -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -type ObjectBase = {}; +type ObjectBase = object; /** * hover specific state and callback helper @@ -22,7 +23,7 @@ function useHoverHelper(props: PressableHoverProps): [PressableHoverProps, IHove const { onHoverIn: onHoverInProp, onHoverOut: onHoverOutProp } = props; const onHoverIn = React.useCallback( - (e) => { + (e: MouseEvent) => { setHoverState({ hovered: true }); if (onHoverInProp) { onHoverInProp(e); @@ -32,7 +33,7 @@ function useHoverHelper(props: PressableHoverProps): [PressableHoverProps, IHove ); const onHoverOut = React.useCallback( - (e) => { + (e: MouseEvent) => { setHoverState({ hovered: false }); if (onHoverOutProp) { onHoverOutProp(e); @@ -50,7 +51,7 @@ function useFocusHelper(props: PressableFocusProps): [PressableFocusProps, IFocu const [focusState, setFocusState] = React.useState({ focused: false }); const { onBlur: onBlurProp, onFocus: onFocusProp } = props; const onFocus = React.useCallback( - (e) => { + (e: FocusEvent) => { setFocusState({ focused: true }); if (onFocusProp) { onFocusProp(e); @@ -60,7 +61,7 @@ function useFocusHelper(props: PressableFocusProps): [PressableFocusProps, IFocu ); const onBlur = React.useCallback( - (e) => { + (e: BlurEvent) => { setFocusState({ focused: false }); if (onBlurProp) { onBlurProp(e); @@ -79,7 +80,7 @@ function usePressHelper(props: PressablePressProps): [PressablePressProps, IPres const { onPressIn: onPressInProp, onPressOut: onPressOutProp } = props; const onPressIn = React.useCallback( - (e) => { + (e: GestureResponderEvent) => { setPressState({ pressed: true }); if (onPressInProp) { onPressInProp(e); @@ -89,7 +90,7 @@ function usePressHelper(props: PressablePressProps): [PressablePressProps, IPres ); const onPressOut = React.useCallback( - (e) => { + (e: GestureResponderEvent) => { setPressState({ pressed: false }); if (onPressOutProp) { onPressOutProp(e); @@ -106,7 +107,7 @@ function usePressHelper(props: PressablePressProps): [PressablePressProps, IPres * as each of these calls will create a new instance of the Pressability class. * @param props - input props for the component */ -export function useFocusState(props: IWithPressableOptions): [IWithPressableEvents, IFocusState] { +export function useFocusState(props: IWithPressableOptions): [IWithPartialPressableEvents, IFocusState] { const [focusProps, focusState] = useFocusHelper(props); return [{ ...props, ...usePressability({ ...props, ...focusProps }) }, focusState]; } @@ -116,7 +117,7 @@ export function useFocusState(props: IWithPressableOptions * as each of these calls will create a new instance of the Pressability class. * @param props - input props for the component */ -export function usePressState(props: IWithPressableOptions): [IWithPressableEvents, IPressState] { +export function usePressState(props: IWithPressableOptions): [IWithPartialPressableEvents, IPressState] { const [pressProps, pressState] = usePressHelper(props); return [{ ...props, ...usePressability({ ...props, ...pressProps }) }, pressState]; } @@ -126,7 +127,7 @@ export function usePressState(props: IWithPressableOptions * as each of these calls will create a new instance of the Pressability class. * @param props - input props for the component */ -export function useHoverState(props: IWithPressableOptions): [IWithPressableEvents, IHoverState] { +export function useHoverState(props: IWithPressableOptions): [IWithPartialPressableEvents, IHoverState] { const [hoverProps, hoverState] = useHoverHelper(props); return [{ ...props, ...usePressability({ ...props, ...hoverProps }) }, hoverState]; } @@ -142,7 +143,7 @@ export function useAsPressable(props: IWithPressableOption const pressabilityProps = usePressability({ ...props, ...hoverProps, ...focusProps, ...pressProps }); return { - props: { ...props, ...pressabilityProps }, + props: { ...props, ...pressabilityProps } as IWithPressableEvents, state: { ...hoverState, ...focusState, ...pressState }, }; } diff --git a/packages/utils/interactive-hooks/src/useAsPressable.types.ts b/packages/utils/interactive-hooks/src/useAsPressable.types.ts index 981b6ee9261..88b0cc7221a 100644 --- a/packages/utils/interactive-hooks/src/useAsPressable.types.ts +++ b/packages/utils/interactive-hooks/src/useAsPressable.types.ts @@ -1,7 +1,6 @@ import type { PressabilityConfig, EventHandlers } from './usePressability'; -// eslint-disable-next-line @typescript-eslint/no-empty-object-type -type ObjectBase = {}; +type ObjectBase = object; export type IPressState = { pressed?: boolean; @@ -25,6 +24,8 @@ export type IWithPressableOptions = T & IPressableOptions; export type IWithPressableEvents = T & EventHandlers; +export type IWithPartialPressableEvents = T & Partial; + export type IPressableHooks = { props: IWithPressableEvents; state: IPressableState; diff --git a/packages/utils/interactive-hooks/src/useAsToggle.ts b/packages/utils/interactive-hooks/src/useAsToggle.ts index 7a93a3fb035..2b180c1a35d 100644 --- a/packages/utils/interactive-hooks/src/useAsToggle.ts +++ b/packages/utils/interactive-hooks/src/useAsToggle.ts @@ -15,7 +15,7 @@ export type OnChangeCallback = () => void; * state.isChecked - Whether or not component is currently checked or selected */ export function useAsToggle(defaultChecked?: boolean, checked?: boolean, userCallback?: OnToggleCallback): [boolean, OnChangeCallback] { - const [isChecked, setChecked] = React.useState(defaultChecked ?? checked); + const [isChecked = false, setChecked] = React.useState(defaultChecked ?? checked); const onChange = React.useCallback(() => { userCallback && userCallback(!isChecked); diff --git a/packages/utils/interactive-hooks/src/useAsToggleWithEvent.ts b/packages/utils/interactive-hooks/src/useAsToggleWithEvent.ts index 3d6a081b4e6..80092cadd6d 100644 --- a/packages/utils/interactive-hooks/src/useAsToggleWithEvent.ts +++ b/packages/utils/interactive-hooks/src/useAsToggleWithEvent.ts @@ -22,7 +22,7 @@ export function useAsToggleWithEvent( checked?: boolean, userCallback?: OnToggleWithEventCallback, ): [boolean, OnChangeWithEventCallback] { - const [isChecked, setChecked] = useControllableValue(checked, defaultChecked); + const [isChecked = false, setChecked] = useControllableValue(checked, defaultChecked); const onChange = React.useCallback( (e: any) => { diff --git a/packages/utils/interactive-hooks/src/usePressability.ts b/packages/utils/interactive-hooks/src/usePressability.ts index 4ff8f0a5210..2099ca01f17 100644 --- a/packages/utils/interactive-hooks/src/usePressability.ts +++ b/packages/utils/interactive-hooks/src/usePressability.ts @@ -1,5 +1,6 @@ import type { PressableProps, GestureResponderEvent, BlurEvent, MouseEvent } from 'react-native'; +// @ts-expect-error - types are still in flow, we are explicitly creating a typed wrapper around this import usePressabilityBase from 'react-native/Libraries/Pressability/usePressability'; export type Rect = { diff --git a/packages/utils/interactive-hooks/src/usePressableState.ts b/packages/utils/interactive-hooks/src/usePressableState.ts index d35427b07f8..fe74ecf3ab2 100644 --- a/packages/utils/interactive-hooks/src/usePressableState.ts +++ b/packages/utils/interactive-hooks/src/usePressableState.ts @@ -11,6 +11,8 @@ import type { PressablePropsExtended, } from './usePressableState.types'; +import type { MouseEvent, FocusEvent, BlurEvent, GestureResponderEvent } from 'react-native'; + /** * hover specific state and callback helper */ @@ -19,7 +21,7 @@ export function useHoverHelper(props: PressableHoverProps): [PressableHoverProps const { onHoverIn, onHoverOut } = props; const _onHoverIn = React.useCallback( - (e) => { + (e: MouseEvent) => { setHoverState({ hovered: true }); onHoverIn?.(e); }, @@ -27,7 +29,7 @@ export function useHoverHelper(props: PressableHoverProps): [PressableHoverProps ); const _onHoverOut = React.useCallback( - (e) => { + (e: MouseEvent) => { setHoverState({ hovered: false }); onHoverOut?.(e); }, @@ -43,7 +45,7 @@ export function useFocusHelper(props: PressableFocusProps): [PressableFocusProps const [focusState, setFocusState] = React.useState({ focused: false }); const { onFocus, onBlur } = props; const _onFocus = React.useCallback( - (e) => { + (e: FocusEvent) => { setFocusState({ focused: true }); onFocus?.(e); }, @@ -51,7 +53,7 @@ export function useFocusHelper(props: PressableFocusProps): [PressableFocusProps ); const _onBlur = React.useCallback( - (e) => { + (e: BlurEvent) => { setFocusState({ focused: false }); onBlur?.(e); }, @@ -68,7 +70,7 @@ export function usePressHelper(props: PressablePressProps): [PressablePressProps const { onPressIn, onPressOut } = props; const _onPressIn = React.useCallback( - (e) => { + (e: GestureResponderEvent) => { setPressState({ pressed: true }); onPressIn?.(e); }, @@ -76,7 +78,7 @@ export function usePressHelper(props: PressablePressProps): [PressablePressProps ); const _onPressOut = React.useCallback( - (e) => { + (e: GestureResponderEvent) => { setPressState({ pressed: false }); onPressOut?.(e); }, diff --git a/packages/utils/interactive-hooks/tsconfig.json b/packages/utils/interactive-hooks/tsconfig.json index 83975437e4d..7c5e7a85ebd 100644 --- a/packages/utils/interactive-hooks/tsconfig.json +++ b/packages/utils/interactive-hooks/tsconfig.json @@ -1,5 +1,5 @@ { - "extends": "@fluentui-react-native/scripts/tsconfig", + "extends": "@fluentui-react-native/scripts/tsconfig-strict", "compilerOptions": { "outDir": "lib", "rootDir": "src" From 659c4d85298feb724a21b70d59597592e44a32c4 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Thu, 4 Jun 2026 12:59:48 -0700 Subject: [PATCH 04/10] add changeset --- .changeset/nice-stamps-win.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .changeset/nice-stamps-win.md diff --git a/.changeset/nice-stamps-win.md b/.changeset/nice-stamps-win.md new file mode 100644 index 00000000000..ca22c6dd2ab --- /dev/null +++ b/.changeset/nice-stamps-win.md @@ -0,0 +1,11 @@ +--- +"@fluentui-react-native/interactive-hooks": patch +"@fluentui-react-native/use-slot": patch +"@fluentui-react-native/button": patch +"@fluentui-react-native/switch": patch +"@fluentui-react-native/chip": patch +"@fluentui-react-native/framework-base": patch +"@fluentui-react-native/adapters": patch +--- + +Change base furn packages to stricter types From 24641e9be495fc7fef9720af1637a396d5dc7bbb Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Thu, 4 Jun 2026 13:13:47 -0700 Subject: [PATCH 05/10] fix lint error in base types --- packages/framework-base/src/utilities/baseTypes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework-base/src/utilities/baseTypes.ts b/packages/framework-base/src/utilities/baseTypes.ts index 38cefe36f53..b93dd70140f 100644 --- a/packages/framework-base/src/utilities/baseTypes.ts +++ b/packages/framework-base/src/utilities/baseTypes.ts @@ -3,7 +3,7 @@ */ type Falsy = undefined | null | false | ''; // eslint-disable-next-line @typescript-eslint/no-empty-object-type -interface RecursiveArray extends Array | RecursiveArray> {} +interface RecursiveArray extends Array> {} /** Keep a brand of 'T' so that calls to `StyleSheet.flatten` can take `RegisteredStyle` and return `T`. */ type RegisteredStyle = number & { __registeredStyleBrand: T }; export type StyleProp = T | RegisteredStyle | RecursiveArray | Falsy> | Falsy; From 98787da57c0006b6e7f9b26c6b97e64b67ee2ae5 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Mon, 22 Jun 2026 13:21:56 -0700 Subject: [PATCH 06/10] remove behavior change for checked state --- .../ToggleButton/__snapshots__/ToggleButton.test.tsx.snap | 2 +- .../Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap | 6 +++--- .../src/__tests__/__snapshots__/Switch.test.tsx.snap | 6 ++---- packages/utils/interactive-hooks/src/useAsToggle.ts | 8 ++++++-- .../utils/interactive-hooks/src/useAsToggleWithEvent.ts | 4 ++-- 5 files changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap b/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap index d580c17b25c..bff788bf319 100644 --- a/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap +++ b/packages/components/Button/src/ToggleButton/__snapshots__/ToggleButton.test.tsx.snap @@ -14,7 +14,7 @@ exports[`ToggleButton default 1`] = ` accessibilityState={ { "busy": undefined, - "checked": false, + "checked": undefined, "disabled": false, "expanded": undefined, "selected": undefined, diff --git a/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap b/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap index 86e60907b09..56bd2b201fb 100644 --- a/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap +++ b/packages/components/Chip/src/__tests__/__snapshots__/Chip.test.tsx.snap @@ -5,7 +5,7 @@ exports[`Chip component tests Chip all props 1`] = ` accessibilityState={ { "busy": undefined, - "checked": false, + "checked": undefined, "disabled": undefined, "expanded": undefined, "selected": undefined, @@ -99,7 +99,7 @@ exports[`Chip component tests Chip tokens 1`] = ` accessibilityState={ { "busy": undefined, - "checked": false, + "checked": undefined, "disabled": undefined, "expanded": undefined, "selected": undefined, @@ -169,7 +169,7 @@ exports[`Chip component tests Empty Chip 1`] = ` accessibilityState={ { "busy": undefined, - "checked": false, + "checked": undefined, "disabled": undefined, "expanded": undefined, "selected": undefined, diff --git a/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap b/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap index d2a214b0f7b..5e31d6bc58b 100644 --- a/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap +++ b/packages/components/Switch/src/__tests__/__snapshots__/Switch.test.tsx.snap @@ -14,7 +14,7 @@ exports[`Switch Default 1`] = ` accessibilityState={ { "busy": undefined, - "checked": false, + "checked": undefined, "disabled": undefined, "expanded": undefined, "selected": undefined, @@ -29,7 +29,6 @@ exports[`Switch Default 1`] = ` } } accessible={true} - checked={false} collapsable={false} focusable={true} onAccessibilityAction={[Function]} @@ -141,7 +140,7 @@ exports[`Switch Disabled 1`] = ` accessibilityState={ { "busy": undefined, - "checked": false, + "checked": undefined, "disabled": true, "expanded": undefined, "selected": undefined, @@ -156,7 +155,6 @@ exports[`Switch Disabled 1`] = ` } } accessible={false} - checked={false} collapsable={false} focusable={false} onAccessibilityAction={[Function]} diff --git a/packages/utils/interactive-hooks/src/useAsToggle.ts b/packages/utils/interactive-hooks/src/useAsToggle.ts index 2b180c1a35d..836974f56ac 100644 --- a/packages/utils/interactive-hooks/src/useAsToggle.ts +++ b/packages/utils/interactive-hooks/src/useAsToggle.ts @@ -14,8 +14,12 @@ export type OnChangeCallback = () => void; * onChange() - Callback to toggle the component * state.isChecked - Whether or not component is currently checked or selected */ -export function useAsToggle(defaultChecked?: boolean, checked?: boolean, userCallback?: OnToggleCallback): [boolean, OnChangeCallback] { - const [isChecked = false, setChecked] = React.useState(defaultChecked ?? checked); +export function useAsToggle( + defaultChecked?: boolean, + checked?: boolean, + userCallback?: OnToggleCallback, +): [boolean | undefined, OnChangeCallback] { + const [isChecked, setChecked] = React.useState(defaultChecked ?? checked); const onChange = React.useCallback(() => { userCallback && userCallback(!isChecked); diff --git a/packages/utils/interactive-hooks/src/useAsToggleWithEvent.ts b/packages/utils/interactive-hooks/src/useAsToggleWithEvent.ts index 80092cadd6d..eaca470c590 100644 --- a/packages/utils/interactive-hooks/src/useAsToggleWithEvent.ts +++ b/packages/utils/interactive-hooks/src/useAsToggleWithEvent.ts @@ -21,8 +21,8 @@ export function useAsToggleWithEvent( defaultChecked?: boolean, checked?: boolean, userCallback?: OnToggleWithEventCallback, -): [boolean, OnChangeWithEventCallback] { - const [isChecked = false, setChecked] = useControllableValue(checked, defaultChecked); +): [boolean | undefined, OnChangeWithEventCallback] { + const [isChecked, setChecked] = useControllableValue(checked, defaultChecked); const onChange = React.useCallback( (e: any) => { From 147d8c31daacf9f0b57b01290a08918c8f84e9e9 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Mon, 22 Jun 2026 14:15:56 -0700 Subject: [PATCH 07/10] revert bad lockfile merge --- yarn.lock | 395 +++++++----------------------------------------------- 1 file changed, 48 insertions(+), 347 deletions(-) diff --git a/yarn.lock b/yarn.lock index 54b3ed5b196..ce3ba0605cb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -166,13 +166,13 @@ __metadata: linkType: hard "@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.21.4, @babel/code-frame@npm:^7.24.7, @babel/code-frame@npm:^7.26.2, @babel/code-frame@npm:^7.27.1, @babel/code-frame@npm:^7.28.6, @babel/code-frame@npm:^7.29.0": - version: 7.29.0 - resolution: "@babel/code-frame@npm:7.29.0" + version: 7.29.7 + resolution: "@babel/code-frame@npm:7.29.7" dependencies: - "@babel/helper-validator-identifier": "npm:^7.28.5" + "@babel/helper-validator-identifier": "npm:^7.29.7" js-tokens: "npm:^4.0.0" picocolors: "npm:^1.1.1" - checksum: 10c0/d34cc504e7765dfb576a663d97067afb614525806b5cad1a5cc1a7183b916fec8ff57fa233585e3926fd5a9e6b31aae6df91aa81ae9775fb7a28f658d3346f0d + checksum: 10c0/169fc2080169a40c1760155eaaaf739bcb882df0bec76a83adbda5493645bc17270a3434b8848c494b1933e96fe1d147370001e3cda09a39f43ae30f08ef2069 languageName: node linkType: hard @@ -183,30 +183,7 @@ __metadata: languageName: node linkType: hard -"@babel/core@npm:^7.0.0, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.13.16, @babel/core@npm:^7.20.0, @babel/core@npm:^7.21.3, @babel/core@npm:^7.23.9, @babel/core@npm:^7.25.2": - version: 7.28.6 - resolution: "@babel/core@npm:7.28.6" - dependencies: - "@babel/code-frame": "npm:^7.28.6" - "@babel/generator": "npm:^7.28.6" - "@babel/helper-compilation-targets": "npm:^7.28.6" - "@babel/helper-module-transforms": "npm:^7.28.6" - "@babel/helpers": "npm:^7.28.6" - "@babel/parser": "npm:^7.28.6" - "@babel/template": "npm:^7.28.6" - "@babel/traverse": "npm:^7.28.6" - "@babel/types": "npm:^7.28.6" - "@jridgewell/remapping": "npm:^2.3.5" - convert-source-map: "npm:^2.0.0" - debug: "npm:^4.1.0" - gensync: "npm:^1.0.0-beta.2" - json5: "npm:^2.2.3" - semver: "npm:^6.3.1" - checksum: 10c0/716b88b1ab057aa53ffa40f2b2fb7e4ab7a35cd6a065fa60e55ca13d2a666672592329f7ea9269aec17e90cc7ce29f42eda566d07859bfd998329a9f283faadb - languageName: node - linkType: hard - -"@babel/core@npm:^7.24.7": +"@babel/core@npm:^7.0.0, @babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.13.16, @babel/core@npm:^7.20.0, @babel/core@npm:^7.21.3, @babel/core@npm:^7.23.9, @babel/core@npm:^7.24.7, @babel/core@npm:^7.25.2": version: 7.29.0 resolution: "@babel/core@npm:7.29.0" dependencies: @@ -229,7 +206,7 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.20.0, @babel/generator@npm:^7.25.0, @babel/generator@npm:^7.7.2": +"@babel/generator@npm:^7.20.0, @babel/generator@npm:^7.25.0, @babel/generator@npm:^7.29.0, @babel/generator@npm:^7.29.1, @babel/generator@npm:^7.7.2": version: 7.29.7 resolution: "@babel/generator@npm:7.29.7" dependencies: @@ -242,32 +219,6 @@ __metadata: languageName: node linkType: hard -"@babel/generator@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/generator@npm:7.28.6" - dependencies: - "@babel/parser": "npm:^7.28.6" - "@babel/types": "npm:^7.28.6" - "@jridgewell/gen-mapping": "npm:^0.3.12" - "@jridgewell/trace-mapping": "npm:^0.3.28" - jsesc: "npm:^3.0.2" - checksum: 10c0/162fa358484a9a18e8da1235d998f10ea77c63bab408c8d3e327d5833f120631a77ff022c5ed1d838ee00523f8bb75df1f08196d3657d0bca9f2cfeb8503cc12 - languageName: node - linkType: hard - -"@babel/generator@npm:^7.29.0, @babel/generator@npm:^7.29.1": - version: 7.29.1 - resolution: "@babel/generator@npm:7.29.1" - dependencies: - "@babel/parser": "npm:^7.29.0" - "@babel/types": "npm:^7.29.0" - "@jridgewell/gen-mapping": "npm:^0.3.12" - "@jridgewell/trace-mapping": "npm:^0.3.28" - jsesc: "npm:^3.0.2" - checksum: 10c0/349086e6876258ef3fb2823030fee0f6c0eb9c3ebe35fc572e16997f8c030d765f636ddc6299edae63e760ea6658f8ee9a2edfa6d6b24c9a80c917916b973551 - languageName: node - linkType: hard - "@babel/helper-annotate-as-pure@npm:^7.18.6, @babel/helper-annotate-as-pure@npm:^7.27.1, @babel/helper-annotate-as-pure@npm:^7.27.3": version: 7.27.3 resolution: "@babel/helper-annotate-as-pure@npm:7.27.3" @@ -371,7 +322,7 @@ __metadata: languageName: node linkType: hard -"@babel/helper-module-transforms@npm:^7.27.1, @babel/helper-module-transforms@npm:^7.28.3, @babel/helper-module-transforms@npm:^7.28.6": +"@babel/helper-module-transforms@npm:^7.27.1, @babel/helper-module-transforms@npm:^7.28.6": version: 7.28.6 resolution: "@babel/helper-module-transforms@npm:7.28.6" dependencies: @@ -436,13 +387,6 @@ __metadata: languageName: node linkType: hard -"@babel/helper-string-parser@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-string-parser@npm:7.27.1" - checksum: 10c0/8bda3448e07b5583727c103560bcf9c4c24b3c1051a4c516d4050ef69df37bb9a4734a585fe12725b8c2763de0a265aa1e909b485a4e3270b7cfd3e4dbe4b602 - languageName: node - linkType: hard - "@babel/helper-string-parser@npm:^7.29.7": version: 7.29.7 resolution: "@babel/helper-string-parser@npm:7.29.7" @@ -485,29 +429,7 @@ __metadata: languageName: node linkType: hard -"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.13.16, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.0, @babel/parser@npm:^7.20.15, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.3, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.25.3, @babel/parser@npm:^7.28.6, @babel/parser@npm:^7.29.0": - version: 7.29.2 - resolution: "@babel/parser@npm:7.29.2" - dependencies: - "@babel/types": "npm:^7.29.0" - bin: - parser: ./bin/babel-parser.js - checksum: 10c0/e5a4e69e3ac7acdde995f37cf299a68458cfe7009dff66bd0962fd04920bef287201169006af365af479c08ff216bfefbb595e331f87f6ae7283858aebbc3317 - languageName: node - linkType: hard - -"@babel/parser@npm:^7.24.7": - version: 7.29.3 - resolution: "@babel/parser@npm:7.29.3" - dependencies: - "@babel/types": "npm:^7.29.0" - bin: - parser: ./bin/babel-parser.js - checksum: 10c0/f06920c819550c0db689e4c5b626bf55ba3cebf80ebe9ccfa434e134036cf3de50951fe759f74abb2dae381989239860bde46d4600328578ad1f7114c3711a6d - languageName: node - linkType: hard - -"@babel/parser@npm:^7.29.7": +"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.13.16, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.0, @babel/parser@npm:^7.20.15, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.21.3, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.25.3, @babel/parser@npm:^7.28.6, @babel/parser@npm:^7.29.0, @babel/parser@npm:^7.29.7": version: 7.29.7 resolution: "@babel/parser@npm:7.29.7" dependencies: @@ -1254,16 +1176,16 @@ __metadata: linkType: hard "@babel/plugin-transform-modules-systemjs@npm:^7.28.5": - version: 7.28.5 - resolution: "@babel/plugin-transform-modules-systemjs@npm:7.28.5" + version: 7.29.4 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.29.4" dependencies: - "@babel/helper-module-transforms": "npm:^7.28.3" - "@babel/helper-plugin-utils": "npm:^7.27.1" + "@babel/helper-module-transforms": "npm:^7.28.6" + "@babel/helper-plugin-utils": "npm:^7.28.6" "@babel/helper-validator-identifier": "npm:^7.28.5" - "@babel/traverse": "npm:^7.28.5" + "@babel/traverse": "npm:^7.29.0" peerDependencies: "@babel/core": ^7.0.0-0 - checksum: 10c0/7e8c0bcff79689702b974f6a0fedb5d0c6eeb5a5e3384deb7028e7cfe92a5242cc80e981e9c1817aad29f2ecc01841753365dd38d877aa0b91737ceec2acfd07 + checksum: 10c0/1da94f89ef8ba1aa1501136a80eb4c010c6a19f5550e10db84677b3ccb7a4934c8098f2b5134def87cf513bf05747ffa523d33722a1ea5a5c8ef956e9136c4c2 languageName: node linkType: hard @@ -1845,27 +1767,7 @@ __metadata: languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.2, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.5, @babel/types@npm:^7.28.6, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": - version: 7.28.6 - resolution: "@babel/types@npm:7.28.6" - dependencies: - "@babel/helper-string-parser": "npm:^7.27.1" - "@babel/helper-validator-identifier": "npm:^7.28.5" - checksum: 10c0/54a6a9813e48ef6f35aa73c03b3c1572cad7fa32b61b35dd07e4230bc77b559194519c8a4d8106a041a27cc7a94052579e238a30a32d5509aa4da4d6fd83d990 - languageName: node - linkType: hard - -"@babel/types@npm:^7.29.0": - version: 7.29.0 - resolution: "@babel/types@npm:7.29.0" - dependencies: - "@babel/helper-string-parser": "npm:^7.27.1" - "@babel/helper-validator-identifier": "npm:^7.28.5" - checksum: 10c0/23cc3466e83bcbfab8b9bd0edaafdb5d4efdb88b82b3be6728bbade5ba2f0996f84f63b1c5f7a8c0d67efded28300898a5f930b171bb40b311bca2029c4e9b4f - languageName: node - linkType: hard - -"@babel/types@npm:^7.29.7": +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.21.3, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.2, @babel/types@npm:^7.27.1, @babel/types@npm:^7.27.3, @babel/types@npm:^7.28.5, @babel/types@npm:^7.28.6, @babel/types@npm:^7.29.0, @babel/types@npm:^7.29.7, @babel/types@npm:^7.3.0, @babel/types@npm:^7.3.3, @babel/types@npm:^7.4.4": version: 7.29.7 resolution: "@babel/types@npm:7.29.7" dependencies: @@ -2173,7 +2075,7 @@ __metadata: languageName: node linkType: hard -"@emnapi/runtime@npm:1.10.0": +"@emnapi/runtime@npm:1.10.0, @emnapi/runtime@npm:^1.7.0": version: 1.10.0 resolution: "@emnapi/runtime@npm:1.10.0" dependencies: @@ -2182,15 +2084,6 @@ __metadata: languageName: node linkType: hard -"@emnapi/runtime@npm:^1.7.0": - version: 1.8.1 - resolution: "@emnapi/runtime@npm:1.8.1" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/f4929d75e37aafb24da77d2f58816761fe3f826aad2e37fa6d4421dac9060cbd5098eea1ac3c9ecc4526b89deb58153852fa432f87021dc57863f2ff726d713f - languageName: node - linkType: hard - "@emnapi/wasi-threads@npm:1.2.1": version: 1.2.1 resolution: "@emnapi/wasi-threads@npm:1.2.1" @@ -6949,16 +6842,16 @@ __metadata: linkType: hard "@nevware21/ts-utils@npm:>= 0.10.4 < 2.x, @nevware21/ts-utils@npm:>= 0.11.8 < 2.x, @nevware21/ts-utils@npm:>= 0.12.2 < 2.x, @nevware21/ts-utils@npm:>= 0.9.4 < 2.x": - version: 0.14.0 - resolution: "@nevware21/ts-utils@npm:0.14.0" - checksum: 10c0/744b1e7b8cad9f2cc0e56fe4913ed6313976841b6814fad164f5d9a3b2e0f95565e92ddbbec491d0b03c4b7ee65fdcfb599c0a5c46d60ee66b282451341d3008 + version: 0.12.5 + resolution: "@nevware21/ts-utils@npm:0.12.5" + checksum: 10c0/788e691b78725d35ea65b3411ebcedca882c21ceefe632abbffff0954c4a3611cf8e6f704c41d1fbcfa4b4512969fae1be143282fd5e6f1aaa1893659bbb4be9 languageName: node linkType: hard "@nodable/entities@npm:^2.1.0": - version: 2.1.0 - resolution: "@nodable/entities@npm:2.1.0" - checksum: 10c0/5a4cba2b61a5b6c726328b18b1de6d033cae4a658a118644bf31e0bcbda126ea7b69385043dc556cf1ed859b9ca220e82b81b5e5c48ef1b519fb8ec104575dee + version: 2.1.1 + resolution: "@nodable/entities@npm:2.1.1" + checksum: 10c0/d295c148a3a4a30dbcbb453d464ff93b28301d72c8f6f3a2f138f8a2bc1ad9f8c5210a70d857e7133f44468c3d8e90d3026e1aecee5a632d6c3f74898c14e5b9 languageName: node linkType: hard @@ -8151,38 +8044,7 @@ __metadata: languageName: node linkType: hard -"@react-native-windows/cli@npm:0.81.1": - version: 0.81.1 - resolution: "@react-native-windows/cli@npm:0.81.1" - dependencies: - "@react-native-windows/codegen": "npm:0.81.1" - "@react-native-windows/fs": "npm:0.81.0" - "@react-native-windows/package-utils": "npm:0.81.0" - "@react-native-windows/telemetry": "npm:0.81.0" - "@xmldom/xmldom": "npm:^0.7.7" - chalk: "npm:^4.1.0" - cli-spinners: "npm:^2.2.0" - envinfo: "npm:^7.5.0" - execa: "npm:^5.0.0" - find-up: "npm:^4.1.0" - glob: "npm:^7.1.1" - lodash: "npm:^4.17.15" - mustache: "npm:^4.0.1" - ora: "npm:^3.4.0" - prompts: "npm:^2.4.1" - semver: "npm:^7.3.2" - shelljs: "npm:^0.8.4" - username: "npm:^5.1.0" - xml-formatter: "npm:^2.4.0" - xml-parser: "npm:^1.2.1" - xpath: "npm:^0.0.27" - peerDependencies: - react-native: ^0.81.0-0 - checksum: 10c0/ec1becd47f85ef81aff178b2e4edd89378ea9b991b1285ef53f3af7b4a7f114eb9b3ed779ce5ff691b2783bb60c2421aa47c4c6063007e3f070dfcbdaa84f0bb - languageName: node - linkType: hard - -"@react-native-windows/cli@npm:^0.81.0": +"@react-native-windows/cli@npm:0.81.5, @react-native-windows/cli@npm:^0.81.0": version: 0.81.5 resolution: "@react-native-windows/cli@npm:0.81.5" dependencies: @@ -8213,24 +8075,6 @@ __metadata: languageName: node linkType: hard -"@react-native-windows/codegen@npm:0.81.1": - version: 0.81.1 - resolution: "@react-native-windows/codegen@npm:0.81.1" - dependencies: - "@react-native-windows/fs": "npm:0.81.0" - chalk: "npm:^4.1.0" - globby: "npm:^11.1.0" - mustache: "npm:^4.0.1" - source-map-support: "npm:^0.5.19" - yargs: "npm:^16.2.0" - peerDependencies: - react-native: ^0.81.0-0 - bin: - react-native-windows-codegen: bin.js - checksum: 10c0/71d25ada8e2eb2e7e1ac26a041f0ad0e0179fe8e8d649113c68c6f809f122657759f19afd88fe2f51adafbb163a90e19fa45481e996ce407f294b5fce1316773 - languageName: node - linkType: hard - "@react-native-windows/codegen@npm:0.81.5": version: 0.81.5 resolution: "@react-native-windows/codegen@npm:0.81.5" @@ -8249,16 +8093,6 @@ __metadata: languageName: node linkType: hard -"@react-native-windows/find-repo-root@npm:0.81.0": - version: 0.81.0 - resolution: "@react-native-windows/find-repo-root@npm:0.81.0" - dependencies: - "@react-native-windows/fs": "npm:0.81.0" - find-up: "npm:^4.1.0" - checksum: 10c0/6521cb8d200cca63f7166296e8f18313c8e9d7a8ea34929c0bb5d0ca79f1dc4f96db61d115ca732e1d766702c21d13234f66d2ee94c080a4705af3c5dad6e764 - languageName: node - linkType: hard - "@react-native-windows/find-repo-root@npm:0.81.1": version: 0.81.1 resolution: "@react-native-windows/find-repo-root@npm:0.81.1" @@ -8269,15 +8103,6 @@ __metadata: languageName: node linkType: hard -"@react-native-windows/fs@npm:0.81.0": - version: 0.81.0 - resolution: "@react-native-windows/fs@npm:0.81.0" - dependencies: - graceful-fs: "npm:^4.2.8" - checksum: 10c0/3bb8d17bc494906f8fd06ed595d4a4ac79a798807d19c69f0c253a90ea6b3f4a6982eb8e1bff41be324700ae20f118be52f4f420c47025c42a1eb919aa9016d6 - languageName: node - linkType: hard - "@react-native-windows/fs@npm:0.81.1": version: 0.81.1 resolution: "@react-native-windows/fs@npm:0.81.1" @@ -8287,18 +8112,6 @@ __metadata: languageName: node linkType: hard -"@react-native-windows/package-utils@npm:0.81.0": - version: 0.81.0 - resolution: "@react-native-windows/package-utils@npm:0.81.0" - dependencies: - "@react-native-windows/find-repo-root": "npm:0.81.0" - "@react-native-windows/fs": "npm:0.81.0" - get-monorepo-packages: "npm:^1.2.0" - lodash: "npm:^4.17.15" - checksum: 10c0/7527f54d275db1591d0d85bea9b1a75ae97c606591981917e0e8329cbef6fc8eda9bff3f2f1f61c99c0e1172013fafb708fb7483888ecade274b29147dd458d5 - languageName: node - linkType: hard - "@react-native-windows/package-utils@npm:0.81.1": version: 0.81.1 resolution: "@react-native-windows/package-utils@npm:0.81.1" @@ -8311,23 +8124,6 @@ __metadata: languageName: node linkType: hard -"@react-native-windows/telemetry@npm:0.81.0": - version: 0.81.0 - resolution: "@react-native-windows/telemetry@npm:0.81.0" - dependencies: - "@microsoft/1ds-core-js": "npm:^4.3.0" - "@microsoft/1ds-post-js": "npm:^4.3.0" - "@react-native-windows/fs": "npm:0.81.0" - "@xmldom/xmldom": "npm:^0.7.7" - ci-info: "npm:^3.2.0" - envinfo: "npm:^7.8.1" - lodash: "npm:^4.17.21" - os-locale: "npm:^5.0.0" - xpath: "npm:^0.0.27" - checksum: 10c0/1b33a1e5ac3617a6dfe0a8ea25aae0835cc632a0bd14c7e7a75c98e105172d1ca0cb972861de36dfffd86791c1e56c3022f5e7c59c3c51421c2387cf274d4c16 - languageName: node - linkType: hard - "@react-native-windows/telemetry@npm:0.81.2": version: 0.81.2 resolution: "@react-native-windows/telemetry@npm:0.81.2" @@ -8746,23 +8542,6 @@ __metadata: languageName: node linkType: hard -"@react-native/virtualized-lists@npm:0.81.5": - version: 0.81.5 - resolution: "@react-native/virtualized-lists@npm:0.81.5" - dependencies: - invariant: "npm:^2.2.4" - nullthrows: "npm:^1.1.1" - peerDependencies: - "@types/react": ^19.1.0 - react: "*" - react-native: "*" - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/2f38e73d850e4c7f8bf9e6598ebdf97c524d6ddfa720044798e827aaa613ff6dc47dbdb8e440ce370f92f7ff932f0ac3204328287e79d7e3b8ac8db5651d0b4d - languageName: node - linkType: hard - "@react-native/virtualized-lists@npm:0.81.6": version: 0.81.6 resolution: "@react-native/virtualized-lists@npm:0.81.6" @@ -11803,15 +11582,6 @@ __metadata: languageName: node linkType: hard -"babel-plugin-syntax-hermes-parser@npm:0.28.1": - version: 0.28.1 - resolution: "babel-plugin-syntax-hermes-parser@npm:0.28.1" - dependencies: - hermes-parser: "npm:0.28.1" - checksum: 10c0/7a522b5f3f31701e4e70ddd7976946abe4b1bf8a041fd091f672411eb0f67a79253a671b934aa27bab305e0845933a4cdb9016fcea80b64c95e18cec8d08a154 - languageName: node - linkType: hard - "babel-plugin-syntax-hermes-parser@npm:0.29.1": version: 0.29.1 resolution: "babel-plugin-syntax-hermes-parser@npm:0.29.1" @@ -12080,11 +11850,11 @@ __metadata: linkType: hard "brace-expansion@npm:^5.0.2": - version: 5.0.6 - resolution: "brace-expansion@npm:5.0.6" + version: 5.0.4 + resolution: "brace-expansion@npm:5.0.4" dependencies: balanced-match: "npm:^4.0.2" - checksum: 10c0/8c919869b90f61d533b341d3340be5ee4413232ea89b8246cbc2f38eb014f1d8182785c98a006eaf6111d02dc9eeffefdc240d5ac158625b2ed084dccd4bbf9b + checksum: 10c0/359cbcfa80b2eb914ca1f3440e92313fbfe7919ee6b274c35db55bec555aded69dac5ee78f102cec90c35f98c20fa43d10936d0cd9978158823c249257e1643a languageName: node linkType: hard @@ -15166,7 +14936,7 @@ __metadata: languageName: node linkType: hard -"get-tsconfig@npm:4.14.0": +"get-tsconfig@npm:4.14.0, get-tsconfig@npm:^4.7.0, get-tsconfig@npm:^4.7.5": version: 4.14.0 resolution: "get-tsconfig@npm:4.14.0" dependencies: @@ -15175,15 +14945,6 @@ __metadata: languageName: node linkType: hard -"get-tsconfig@npm:^4.7.0, get-tsconfig@npm:^4.7.5": - version: 4.10.1 - resolution: "get-tsconfig@npm:4.10.1" - dependencies: - resolve-pkg-maps: "npm:^1.0.0" - checksum: 10c0/7f8e3dabc6a49b747920a800fb88e1952fef871cdf51b79e98db48275a5de6cdaf499c55ee67df5fa6fe7ce65f0063e26de0f2e53049b408c585aa74d39ffa21 - languageName: node - linkType: hard - "get-uri@npm:^6.0.1": version: 6.0.3 resolution: "get-uri@npm:6.0.3" @@ -15499,13 +15260,6 @@ __metadata: languageName: node linkType: hard -"hermes-estree@npm:0.28.1": - version: 0.28.1 - resolution: "hermes-estree@npm:0.28.1" - checksum: 10c0/aa00f437c82099b9043e384b529c75de21d0111b792ab7480fe992975b5f9535a8581664789db197824a7825ea66d2fd70eb20cb568c5315804421deaf009500 - languageName: node - linkType: hard - "hermes-estree@npm:0.29.1": version: 0.29.1 resolution: "hermes-estree@npm:0.29.1" @@ -15538,15 +15292,6 @@ __metadata: languageName: node linkType: hard -"hermes-parser@npm:0.28.1": - version: 0.28.1 - resolution: "hermes-parser@npm:0.28.1" - dependencies: - hermes-estree: "npm:0.28.1" - checksum: 10c0/c6d3c01fb1ea5232f4587b6b038f5c2c6414932e7c48efbe156ab160e2bcaac818c9eb2f828f30967a24b40f543cad503baed0eedf5a7e877852ed271915981f - languageName: node - linkType: hard - "hermes-parser@npm:0.29.1": version: 0.29.1 resolution: "hermes-parser@npm:0.29.1" @@ -18373,24 +18118,6 @@ __metadata: languageName: node linkType: hard -"metro-source-map@npm:0.82.5, metro-source-map@npm:^0.82.2": - version: 0.82.5 - resolution: "metro-source-map@npm:0.82.5" - dependencies: - "@babel/traverse": "npm:^7.25.3" - "@babel/traverse--for-generate-function-map": "npm:@babel/traverse@^7.25.3" - "@babel/types": "npm:^7.25.2" - flow-enums-runtime: "npm:^0.0.6" - invariant: "npm:^2.2.4" - metro-symbolicate: "npm:0.82.5" - nullthrows: "npm:^1.1.1" - ob1: "npm:0.82.5" - source-map: "npm:^0.5.6" - vlq: "npm:^1.0.0" - checksum: 10c0/cf04c8f5430eaf2aa8aa97034382d2cb1b0906a4c7cf3c4faaf0203eb00dd683b8d108e74694700a10085796beb292383cfcea50b388cc03062640bd95d3f84a - languageName: node - linkType: hard - "metro-source-map@npm:0.83.1": version: 0.83.1 resolution: "metro-source-map@npm:0.83.1" @@ -18443,22 +18170,6 @@ __metadata: languageName: node linkType: hard -"metro-symbolicate@npm:0.82.5": - version: 0.82.5 - resolution: "metro-symbolicate@npm:0.82.5" - dependencies: - flow-enums-runtime: "npm:^0.0.6" - invariant: "npm:^2.2.4" - metro-source-map: "npm:0.82.5" - nullthrows: "npm:^1.1.1" - source-map: "npm:^0.5.6" - vlq: "npm:^1.0.0" - bin: - metro-symbolicate: src/index.js - checksum: 10c0/39c53b878ae9392586e23ff3a8071eceb1feed2d226e3ac9a170eb6bcd46fe6b69b8204851ee8eb231fdc3eac9012af3c6940ad48f6d1c04810ea9c4a75e1c7c - languageName: node - linkType: hard - "metro-symbolicate@npm:0.83.1": version: 0.83.1 resolution: "metro-symbolicate@npm:0.83.1" @@ -19423,15 +19134,6 @@ __metadata: languageName: node linkType: hard -"ob1@npm:0.82.5": - version: 0.82.5 - resolution: "ob1@npm:0.82.5" - dependencies: - flow-enums-runtime: "npm:^0.0.6" - checksum: 10c0/4d65e82fde0612a5c411f3c926de6bc722bdb4751c4fb08f5a5ef91bdaf860e7f9c4f08dcb7acfdfc05340fc4929efb00ea9e973570c1d61adfc4353657abf55 - languageName: node - linkType: hard - "ob1@npm:0.83.1": version: 0.83.1 resolution: "ob1@npm:0.83.1" @@ -20831,7 +20533,7 @@ __metadata: languageName: node linkType: hard -"react-devtools-core@npm:^6.1.1, react-devtools-core@npm:^6.1.5": +"react-devtools-core@npm:^6.1.5": version: 6.1.5 resolution: "react-devtools-core@npm:6.1.5" dependencies: @@ -21003,16 +20705,15 @@ __metadata: linkType: hard "react-native-svg@npm:^15.12.1": - version: 15.15.1 - resolution: "react-native-svg@npm:15.15.1" + version: 15.15.5 + resolution: "react-native-svg@npm:15.15.5" dependencies: css-select: "npm:^5.1.0" css-tree: "npm:^1.1.3" - warn-once: "npm:0.1.1" peerDependencies: react: "*" react-native: "*" - checksum: 10c0/9e047e8afdd5121296a3402c5c37363b9b37fbddc41f7b0b49b923ac4d2898954c8b57a6784a625321236987e494ee54f594e22f9de815f807e03a3433d7fefd + checksum: 10c0/34b71b6c83d7235efbc4263abaffcbad780375f9e0fca95786e4f1a543a2b6d07e90c7df426f708e85be68331c412066cdc639f4a6ce82bed42bc728050d9402 languageName: node linkType: hard @@ -21054,29 +20755,29 @@ __metadata: linkType: hard "react-native-windows@npm:^0.81.0": - version: 0.81.3 - resolution: "react-native-windows@npm:0.81.3" + version: 0.81.25 + resolution: "react-native-windows@npm:0.81.25" dependencies: "@babel/runtime": "npm:^7.0.0" "@jest/create-cache-key-function": "npm:^29.7.0" "@react-native-community/cli": "npm:17.0.0" "@react-native-community/cli-platform-android": "npm:17.0.0" "@react-native-community/cli-platform-ios": "npm:17.0.0" - "@react-native-windows/cli": "npm:0.81.1" + "@react-native-windows/cli": "npm:0.81.5" "@react-native/assets": "npm:1.0.0" - "@react-native/assets-registry": "npm:0.81.5" - "@react-native/codegen": "npm:0.81.5" - "@react-native/community-cli-plugin": "npm:0.81.5" - "@react-native/gradle-plugin": "npm:0.81.5" - "@react-native/js-polyfills": "npm:0.81.5" + "@react-native/assets-registry": "npm:0.81.6" + "@react-native/codegen": "npm:0.81.6" + "@react-native/community-cli-plugin": "npm:0.81.6" + "@react-native/gradle-plugin": "npm:0.81.6" + "@react-native/js-polyfills": "npm:0.81.6" "@react-native/new-app-screen": "npm:0.81.5" - "@react-native/normalize-colors": "npm:0.81.5" - "@react-native/virtualized-lists": "npm:0.81.5" + "@react-native/normalize-colors": "npm:0.81.6" + "@react-native/virtualized-lists": "npm:0.81.6" abort-controller: "npm:^3.0.0" anser: "npm:^1.4.9" ansi-regex: "npm:^5.0.0" babel-jest: "npm:^29.7.0" - babel-plugin-syntax-hermes-parser: "npm:0.28.1" + babel-plugin-syntax-hermes-parser: "npm:0.29.1" base64-js: "npm:^1.5.1" chalk: "npm:^4.0.0" commander: "npm:^12.0.0" @@ -21087,12 +20788,12 @@ __metadata: jest-environment-node: "npm:^29.7.0" memoize-one: "npm:^5.0.0" metro-runtime: "npm:^0.83.1" - metro-source-map: "npm:^0.82.2" + metro-source-map: "npm:^0.83.1" mkdirp: "npm:^0.5.1" nullthrows: "npm:^1.1.1" pretty-format: "npm:^29.7.0" promise: "npm:^8.3.0" - react-devtools-core: "npm:^6.1.1" + react-devtools-core: "npm:^6.1.5" react-refresh: "npm:^0.14.0" regenerator-runtime: "npm:^0.13.2" scheduler: "npm:0.26.0" @@ -21103,10 +20804,10 @@ __metadata: ws: "npm:^6.2.3" yargs: "npm:^17.6.2" peerDependencies: - "@types/react": ^19.1.0 - react: ^19.1.0 - react-native: 0.81.5 - checksum: 10c0/5408bb6ac8708c32e2d80a5d29ea78c874532d83e7c18908b396393782cfb7269f542e3d6dcd69c369eca720200362ce8b6218788e1cc470aca7fc7fcfe07b65 + "@types/react": ^19.1.4 + react: ^19.1.4 + react-native: ^0.81.0 + checksum: 10c0/cf83749927a6c6bd1b25902fe19fec931e1cc5bc13ab1ee0356485e0aaece487436838a5de6e342af2b937919902d889ff5db6964fbda52e943056acfbea78e4 languageName: node linkType: hard From a1887a0aeab7e518c2db02b6fa27b2f7c11cb2cb Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Mon, 22 Jun 2026 16:04:47 -0700 Subject: [PATCH 08/10] pull in new versino of rnta to (hopefully) fix windows/macos build issues --- .yarnrc.yml | 3 +- apps/fluent-tester/ios/Podfile.lock | 34 +++++++++++------------ apps/fluent-tester/macos/Podfile.lock | 40 +++++++++++++-------------- apps/fluent-tester/package.json | 2 +- apps/tester-core/package.json | 2 +- apps/win32/package.json | 2 +- yarn.lock | 16 +++++------ 7 files changed, 50 insertions(+), 49 deletions(-) diff --git a/.yarnrc.yml b/.yarnrc.yml index 24e7f3c2113..43a93b4fc98 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml @@ -24,7 +24,7 @@ catalog: "@rnx-kit/oxlint-config": ^1.0.3 "@rnx-kit/reporter": ^0.2.0 "@rnx-kit/tools-packages": ^0.1.3 - "@rnx-kit/tools-react-native": ^2.3.7 + "@rnx-kit/tools-react-native": ^2.3.8 "@rnx-kit/tools-typescript": ^0.2.0 "@rnx-kit/tools-workspaces": ^0.2.3 "@rnx-kit/tsconfig": ^3.0.3 @@ -51,6 +51,7 @@ catalog: knip: ^6.12.1 lage: ^2.14.19 oxc-resolver: ^11.17.0 + react-native-test-app: ^5.3.3 rimraf: ^6.1.2 webdriverio: ^9.24.0 diff --git a/apps/fluent-tester/ios/Podfile.lock b/apps/fluent-tester/ios/Podfile.lock index 2e677092e2e..d667ad465d1 100644 --- a/apps/fluent-tester/ios/Podfile.lock +++ b/apps/fluent-tester/ios/Podfile.lock @@ -4,15 +4,15 @@ PODS: - fast_float (8.0.0) - FBLazyVector (0.81.6) - fmt (11.0.2) - - FRNAppearanceAdditions (0.8.3): + - FRNAppearanceAdditions (0.8.4): - React - - FRNAvatar (0.22.3): + - FRNAvatar (0.22.4): - MicrosoftFluentUI (= 0.13.1) - React - - FRNDatePicker (0.12.3): + - FRNDatePicker (0.12.4): - MicrosoftFluentUI (= 0.13.1) - React - - FRNFontMetrics (0.7.3): + - FRNFontMetrics (0.7.4): - React - glog (0.3.5) - hermes-engine (0.81.6): @@ -2424,7 +2424,7 @@ PODS: - React-perflogger (= 0.81.6) - React-utils (= 0.81.6) - SocketRocket - - ReactNativeHost (0.5.17): + - ReactNativeHost (0.5.19): - boost - DoubleConversion - fast_float @@ -2453,7 +2453,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - ReactTestApp-DevSupport (5.1.10): + - ReactTestApp-DevSupport (5.3.3): - React-Core - React-jsi - ReactTestApp-Resources (1.0.0-dev) @@ -2538,7 +2538,7 @@ DEPENDENCIES: - ReactAppDependencyProvider (from `build/generated/ios`) - ReactCodegen (from `build/generated/ios`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) - - "ReactNativeHost (from `../../../node_modules/.store/react-native-test-app-virtual-d4246a9700/node_modules/@rnx-kit/react-native-host`)" + - "ReactNativeHost (from `../../../node_modules/.store/react-native-test-app-virtual-6d85e861d1/node_modules/@rnx-kit/react-native-host`)" - ReactTestApp-DevSupport (from `../node_modules/react-native-test-app`) - ReactTestApp-Resources (from `..`) - RNSVG (from `../node_modules/react-native-svg`) @@ -2701,7 +2701,7 @@ EXTERNAL SOURCES: ReactCommon: :path: "../node_modules/react-native/ReactCommon" ReactNativeHost: - :path: "../../../node_modules/.store/react-native-test-app-virtual-d4246a9700/node_modules/@rnx-kit/react-native-host" + :path: "../../../node_modules/.store/react-native-test-app-virtual-6d85e861d1/node_modules/@rnx-kit/react-native-host" ReactTestApp-DevSupport: :path: "../node_modules/react-native-test-app" ReactTestApp-Resources: @@ -2713,15 +2713,15 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost: 7e761d76ca2ce687f7cc98e698152abd03a18f90 - DoubleConversion: cb417026b2400c8f53ae97020b2be961b59470cb + DoubleConversion: 76ab83afb40bddeeee456813d9c04f67f78771b5 fast_float: b32c788ed9c6a8c584d114d0047beda9664e7cc6 FBLazyVector: 812782f0506ba4c4a1b9f4b793e6de1bfdfc4c25 fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd - FRNAppearanceAdditions: 60f9fb4552fb3d92a63df00aa8f76fd6e8efb942 - FRNAvatar: ffa0facb219806b0e5083d2388bc61e590f5df19 - FRNDatePicker: 312243694338f941080b15f6fac4d0dac8f54137 - FRNFontMetrics: 363f87c2aee015325a399388dda266ed8f1f65a0 - glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 + FRNAppearanceAdditions: 58fe872ed668bac5b1f6b3f81b61c7f9fccd6788 + FRNAvatar: 586585a440e2b23c9ac872fd1fa2ddb7819cd7bd + FRNDatePicker: 6cf33c0f00f68606e2e301689670a7f90a9e5f37 + FRNFontMetrics: dba3c15a2feef87ee987d7c502cc3e2ba15adb5b + glog: fdfdfe5479092de0c4bdbebedd9056951f092c4f hermes-engine: 7219f6e751ad6ec7f3d7ec121830ee34dae40749 MicrosoftFluentUI: dde98d8ed3fc306d9ddd0a6f0bc0c1f24fe5275e RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 @@ -2787,13 +2787,13 @@ SPEC CHECKSUMS: ReactAppDependencyProvider: 50d5506ddd091d4ed24b88b661ce9a0e17347357 ReactCodegen: dae737e6acce32f4e6dda1c5c7ad0e7fd7235b71 ReactCommon: 8fafefb37d562f9e4bbbc9081ca4501f178a97ec - ReactNativeHost: 66a23d7106b451f1a1087f565a45c839abef1e73 - ReactTestApp-DevSupport: 2852f266ad4b393124413d4290c16aff35892cf4 + ReactNativeHost: 8680b5bbc3afdbfeccc206ed0f3230d7c3df691b + ReactTestApp-DevSupport: 0527915bd439c17242bab26d2136cc837b5eebd2 ReactTestApp-Resources: de7bab7391b329e4e22614a22a7d350b5f08939c RNSVG: 7ee150379dc2a5ed4c9fdac92a5d6efab98e9cf7 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 Yoga: 3196a843cc5f4bc433f1a41cf17cdf804a01a529 -PODFILE CHECKSUM: b3aedc74b779b6e577dfef780f9684a0bb0daaae +PODFILE CHECKSUM: fec1d0c29d19b06181402b781cf7db0e3b52a2c8 COCOAPODS: 1.16.2 diff --git a/apps/fluent-tester/macos/Podfile.lock b/apps/fluent-tester/macos/Podfile.lock index 670b26132fe..def1409b608 100644 --- a/apps/fluent-tester/macos/Podfile.lock +++ b/apps/fluent-tester/macos/Podfile.lock @@ -4,10 +4,10 @@ PODS: - fast_float (8.0.0) - FBLazyVector (0.81.2) - fmt (11.0.2) - - FRNAvatar (0.22.3): + - FRNAvatar (0.22.4): - MicrosoftFluentUI (= 0.13.1) - React - - FRNCallout (0.28.3): + - FRNCallout (0.28.4): - boost - DoubleConversion - fast_float @@ -36,13 +36,13 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - FRNCheckbox (0.18.3): + - FRNCheckbox (0.18.4): - React - - FRNMenuButton (0.14.3): + - FRNMenuButton (0.14.4): - React - - FRNRadioButton (0.22.3): + - FRNRadioButton (0.22.4): - React - - FRNVibrancyView (0.4.3): + - FRNVibrancyView (0.4.4): - React - glog (0.3.5) - hermes-engine (0.81.5): @@ -137,7 +137,7 @@ PODS: - fmt (= 11.0.2) - glog - RCTDeprecation (0.81.2) - - RCTFocusZone (0.22.3): + - RCTFocusZone (0.22.4): - React - RCTRequired (0.81.2) - RCTTypeSafety (0.81.2): @@ -2394,7 +2394,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - ReactTestApp-DevSupport (5.2.3): + - ReactTestApp-DevSupport (5.3.3): - React-Core - React-jsi - ReactTestApp-Resources (1.0.0-dev) @@ -2482,7 +2482,7 @@ DEPENDENCIES: - ReactAppDependencyProvider (from `build/generated/ios`) - ReactCodegen (from `build/generated/ios`) - ReactCommon/turbomodule/core (from `../node_modules/react-native-macos/ReactCommon`) - - "ReactNativeHost (from `../../../node_modules/.store/react-native-test-app-virtual-779a5f15d5/node_modules/@rnx-kit/react-native-host`)" + - "ReactNativeHost (from `../../../node_modules/.store/react-native-test-app-virtual-6d85e861d1/node_modules/@rnx-kit/react-native-host`)" - ReactTestApp-DevSupport (from `../node_modules/react-native-test-app`) - ReactTestApp-Resources (from `..`) - RNSVG (from `../node_modules/react-native-svg`) @@ -2651,7 +2651,7 @@ EXTERNAL SOURCES: ReactCommon: :path: "../node_modules/react-native-macos/ReactCommon" ReactNativeHost: - :path: "../../../node_modules/.store/react-native-test-app-virtual-779a5f15d5/node_modules/@rnx-kit/react-native-host" + :path: "../../../node_modules/.store/react-native-test-app-virtual-6d85e861d1/node_modules/@rnx-kit/react-native-host" ReactTestApp-DevSupport: :path: "../node_modules/react-native-test-app" ReactTestApp-Resources: @@ -2663,22 +2663,22 @@ EXTERNAL SOURCES: SPEC CHECKSUMS: boost: cea1d4f90a3a59537f3deb03ff5656489d7133dd - DoubleConversion: d31b1eb37f6d6f456530c4fd9124b857d6889cab + DoubleConversion: 5b92c4507c560bb62e7aa1acdf2785ea3ff08b3b fast_float: 20817c22759af6ac8d4d67e6e059b8b499953656 FBLazyVector: 0e3076dbb16169b0afc2d701a24a526423b5e76b fmt: 24e7591456deb60b4a77518f83d9a916ac84223f - FRNAvatar: ffa0facb219806b0e5083d2388bc61e590f5df19 - FRNCallout: bc2178e4478504e21c01a3c1c8617c91783eae8c - FRNCheckbox: 1cba85c9c8c75257970f8ffcc4a5e2602c22be7c - FRNMenuButton: 709f3218ce9a421c154ea0570acbeb3f535629d3 - FRNRadioButton: a0e58ac8a7be290778a30add5bdf41dc245e3483 - FRNVibrancyView: 96debdb9a1d2d9315c25748450a33fe2cb8b6321 - glog: 0b31c25149b9d350b2666c7d459229861a00ec07 + FRNAvatar: 586585a440e2b23c9ac872fd1fa2ddb7819cd7bd + FRNCallout: f3234f07e6f49334c0f1de7cb7185494f2915db5 + FRNCheckbox: a5afb9bb4e6405d39a30f997f7e69d6e5672533d + FRNMenuButton: e9e49a3afa5eb5ecbe4a36c41047bce763f661c7 + FRNRadioButton: 6f7db3424604a413b4cca73c5a22033c79f92d43 + FRNVibrancyView: a9cf18fcaee2a7d9f9ea292924ebf1b3acb0a5b2 + glog: ba31c1afa7dcf1915a109861bccdb4421be6175b hermes-engine: 9f4dfe93326146a1c99eb535b1cb0b857a3cd172 MicrosoftFluentUI: dde98d8ed3fc306d9ddd0a6f0bc0c1f24fe5275e RCT-Folly: c803cf33238782d5fd21a5e02d44f64068e0e130 RCTDeprecation: b60b889eafa75f46c3d6be5332681efbb16ad0c7 - RCTFocusZone: 1b8ab01688bbb8ef6357bd8789e5c6f38ddac4d9 + RCTFocusZone: a6d62c46c530e790479915bc9faa578137e9e2a6 RCTRequired: 070d7f0ef937e7a93aab20761cef55419f16b5de RCTTypeSafety: dd2ad1eb0c0c01ba41222d115be141f9a348c636 React: 304df3d34c8c0281fd1fd3a506e69f234095425d @@ -2741,7 +2741,7 @@ SPEC CHECKSUMS: ReactCodegen: 9cb74b74196a04d189f74995f8f11d1228316fb4 ReactCommon: 9f8189efbc1aa52926df2791a2e47b3340353849 ReactNativeHost: 8680b5bbc3afdbfeccc206ed0f3230d7c3df691b - ReactTestApp-DevSupport: a966d21f704e95b197479b4f47cad1cf25808385 + ReactTestApp-DevSupport: 0527915bd439c17242bab26d2136cc837b5eebd2 ReactTestApp-Resources: 7625eab22d0a702577b048d60b5fb3f2e2f5b2a7 RNSVG: 7ee150379dc2a5ed4c9fdac92a5d6efab98e9cf7 SocketRocket: d4aabe649be1e368d1318fdf28a022d714d65748 diff --git a/apps/fluent-tester/package.json b/apps/fluent-tester/package.json index ec7bd00a53b..b61acd93e19 100644 --- a/apps/fluent-tester/package.json +++ b/apps/fluent-tester/package.json @@ -95,7 +95,7 @@ "oxc-resolver": "catalog:", "path-dirname": "^1.0.2", "react-native-svg-transformer": "^1.0.0", - "react-native-test-app": "^5.2.3", + "react-native-test-app": "catalog:", "react-test-renderer": "19.1.4", "webdriverio": "catalog:" }, diff --git a/apps/tester-core/package.json b/apps/tester-core/package.json index 3566f473956..a8432fe9043 100644 --- a/apps/tester-core/package.json +++ b/apps/tester-core/package.json @@ -119,7 +119,7 @@ "react-native-macos": "^0.81.0", "react-native-svg": "^15.12.1", "react-native-svg-transformer": "^1.0.0", - "react-native-test-app": "^5.2.3", + "react-native-test-app": "catalog:", "react-native-windows": "^0.81.0", "react-test-renderer": "19.1.4", "webdriverio": "catalog:" diff --git a/apps/win32/package.json b/apps/win32/package.json index aec0df35558..4473e8445a6 100644 --- a/apps/win32/package.json +++ b/apps/win32/package.json @@ -59,7 +59,7 @@ "metro-config": "^0.83.3", "oxc-resolver": "catalog:", "react-native-svg-transformer": "^1.0.0", - "react-native-test-app": "^5.2.3", + "react-native-test-app": "catalog:", "react-test-renderer": "19.1.4", "rimraf": "catalog:" }, diff --git a/yarn.lock b/yarn.lock index ce3ba0605cb..b4719b5bd1f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5074,7 +5074,7 @@ __metadata: react-native-macos: "npm:^0.81.0" react-native-svg: "npm:^15.12.1" react-native-svg-transformer: "npm:^1.0.0" - react-native-test-app: "npm:^5.2.3" + react-native-test-app: "catalog:" react-native-windows: "npm:^0.81.0" react-test-renderer: "npm:19.1.4" webdriverio: "catalog:" @@ -5165,7 +5165,7 @@ __metadata: react-native: "npm:^0.81.6" react-native-svg: "npm:^15.12.1" react-native-svg-transformer: "npm:^1.0.0" - react-native-test-app: "npm:^5.2.3" + react-native-test-app: "catalog:" react-test-renderer: "npm:19.1.4" rimraf: "catalog:" languageName: unknown @@ -5228,7 +5228,7 @@ __metadata: react-native-macos: "npm:^0.81.0" react-native-svg: "npm:^15.12.1" react-native-svg-transformer: "npm:^1.0.0" - react-native-test-app: "npm:^5.2.3" + react-native-test-app: "catalog:" react-native-windows: "npm:^0.81.0" react-test-renderer: "npm:19.1.4" webdriverio: "catalog:" @@ -20717,9 +20717,9 @@ __metadata: languageName: node linkType: hard -"react-native-test-app@npm:^5.2.3": - version: 5.2.3 - resolution: "react-native-test-app@npm:5.2.3" +"react-native-test-app@npm:^5.3.3": + version: 5.3.3 + resolution: "react-native-test-app@npm:5.3.3" dependencies: "@isaacs/cliui": "npm:^9.0.0" "@rnx-kit/react-native-host": "npm:^0.5.19" @@ -20733,7 +20733,7 @@ __metadata: "@callstack/react-native-visionos": 0.76 - 0.79 "@expo/config-plugins": ">=5.0" react: 18.2 - 19.2 - react-native: 0.76 - 0.85 || >=0.85.0-0 <0.86.0 + react-native: 0.76 - 0.86 || >=0.86.0-0 <0.87.0 react-native-macos: ^0.0.0-0 || 0.76 - 0.81 react-native-windows: ^0.0.0-0 || 0.76 - 0.83 peerDependenciesMeta: @@ -20750,7 +20750,7 @@ __metadata: init: scripts/init.mjs init-test-app: scripts/init.mjs install-windows-test-app: windows/app.mjs - checksum: 10c0/a87c47f93eba76bf2ea7a2f7bfdb2d1925b6bbeb00d67b9f365c5016e1a4ba063f5f1c1d7a86aab3f782b85921b1cbe802290010cca320ae66d762c24ee5683e + checksum: 10c0/fb1a8aef116e92f599976b27987ebf303a29ce42a1482e1bc352cfd4f82200cf42b091010e0c4a21d6c85076e8269468d2c1044cbc9a56af77acd3a4d1a4fcb5 languageName: node linkType: hard From c57ea464ed52d6364bdb72e702d51abd832176d3 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Mon, 22 Jun 2026 16:38:35 -0700 Subject: [PATCH 09/10] downgrade the windows target --- .github/workflows/pr.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index 8976dc9d51c..ad899c13764 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -4,6 +4,10 @@ on: pull_request permissions: contents: read +env: + VisualStudioVersion: '17.0' + WindowsTargetPlatformVersion: '10.0.26100.0' + concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true @@ -162,7 +166,7 @@ jobs: windows: name: Windows PR - runs-on: windows-latest + runs-on: windows-2022 timeout-minutes: 60 steps: - name: Checkout From 3aa919f99197bd85b193cd8b919b3279a0263939 Mon Sep 17 00:00:00 2001 From: Jason Morse Date: Tue, 23 Jun 2026 17:29:39 -0700 Subject: [PATCH 10/10] specify powershell for e2e script --- .github/workflows/pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index ad899c13764..37568cce150 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -216,7 +216,7 @@ jobs: working-directory: apps/fluent-tester - name: Run E2E RNW tests - shell: pwsh + shell: powershell run: | .\launchE2EWindows.ps1 -enableDumpFiles working-directory: apps/E2E