{"version":3,"sources":["../src/canary.tsx","../src/types.ts","../src/util.ts","../src/index.tsx"],"sourcesContent":["/// <reference types=\"react/canary\" />\r\nimport type { Context, Usable } from \"react\";\r\nimport { use as originalUse } from \"react\";\r\nimport type { NamedContext } from \"./types\";\r\nimport { UNSET_VALUE } from \"./types\";\r\nimport { assert, type OneOf } from \"./util\";\r\nimport { notSet } from \".\";\r\n\r\nfunction getProviderName(\r\n  context: OneOf<NamedContext<any> | Context<any>>,\r\n): string {\r\n  return context.providerName ?? `${context.displayName ?? \"Unknown\"}.Provider`;\r\n}\r\n\r\nexport function use<T>(\r\n  usable: NamedContext<T | typeof UNSET_VALUE> | Usable<T | typeof UNSET_VALUE>,\r\n): T {\r\n  const value = originalUse(usable);\r\n  assert(\r\n    value !== UNSET_VALUE,\r\n    \"then\" in usable\r\n      ? \"thenable returned UNSET_VALUE\"\r\n      : notSet(\"use\", getProviderName(usable)),\r\n  );\r\n  return value;\r\n}\r\n","import type { PropsWithChildren, Context, FC, ConsumerProps } from \"react\";\nimport type { Compute } from \"./util\";\n\nexport const UNSET_VALUE = Symbol.for(\"required-react-context/unset-value\");\n\nexport interface Names {\n  name: string;\n  contextName?: string;\n  providerName?: string;\n  providerProp?: string;\n  consumerName?: string;\n  hookName?: `use${string}`;\n}\n\ntype GetName<\n  N extends Names,\n  K extends keyof Names,\n  Fallback extends string,\n> = N[K] extends string ? N[K] : Fallback;\n\ntype GetContextName<N extends Names> = GetName<\n  N,\n  \"contextName\",\n  `${Capitalize<N[\"name\"]>}Context`\n>;\n\ntype GetProviderName<N extends Names> = GetName<\n  N,\n  \"providerName\",\n  `${Capitalize<N[\"name\"]>}Provider`\n>;\n\ntype GetProviderProp<N extends Names> = GetName<N, \"providerProp\", N[\"name\"]>;\n\ntype GetConsumerName<N extends Names> = GetName<\n  N,\n  \"consumerName\",\n  `${Capitalize<N[\"name\"]>}Consumer`\n>;\n\ntype GetHookName<N extends Names> = GetName<\n  N,\n  \"hookName\",\n  `use${Capitalize<N[\"name\"]>}`\n>;\n\nexport interface NamedContext<T> extends Context<T> {\n  displayName: string;\n  providerName: string;\n}\n\nexport type NamedContextUtils<\n  T,\n  N extends Names,\n  IsRequired extends boolean = true,\n> = Compute<\n  Record<\n    GetContextName<N>,\n    Context<IsRequired extends true ? T | typeof UNSET_VALUE : T>\n  > &\n    Record<\n      GetProviderName<N>,\n      FC<PropsWithChildren<Record<GetProviderProp<N>, T>>>\n    > &\n    Record<GetConsumerName<N>, FC<ConsumerProps<T>>> &\n    Record<GetHookName<N>, () => T>\n>;\n","// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents\r\nexport type Compute<T> = { [K in keyof T]: T[K] } & unknown;\r\n\r\ntype KeyofUnion<T> = T extends any ? keyof T : never;\r\n\r\nexport type OneOf<\r\n  U,\r\n  K extends KeyofUnion<U> = KeyofUnion<U>,\r\n> = U extends infer T\r\n  ? Compute<T & { [P in Exclude<K, keyof T>]?: undefined }>\r\n  : never;\r\n\r\nexport function capitalise(str: string) {\r\n  if (typeof str !== \"string\") return \"\";\r\n  return str.charAt(0).toUpperCase() + str.slice(1);\r\n}\r\n\r\nexport function assert(condition: boolean, message: string): asserts condition {\r\n  if (!condition) {\r\n    throw new Error(message);\r\n  }\r\n}\r\n\r\nexport function wait(ms: number) {\r\n  return new Promise((resolve) => {\r\n    setTimeout(resolve, ms);\r\n  });\r\n}\r\n","import type { PropsWithChildren, ConsumerProps } from \"react\";\r\nimport React, { createContext, useContext, useDebugValue } from \"react\";\r\nimport type { Names, NamedContext, NamedContextUtils } from \"./types\";\r\nimport { UNSET_VALUE } from \"./types\";\r\nimport { assert, capitalise } from \"./util\";\r\n\r\nexport { UNSET_VALUE };\r\n\r\nexport const notSet = (caller: string, providerName: string) =>\r\n  `${caller}: context value is not set. Use ${providerName} to set the value.`;\r\n\r\nconst makeNamedContext = <T,>(\r\n  defaultValue: T,\r\n  {\r\n    providerName,\r\n    contextName,\r\n  }: Required<Pick<Names, \"contextName\" | \"providerName\">>,\r\n): NamedContext<T> =>\r\n  Object.assign(createContext<T>(defaultValue), {\r\n    providerName,\r\n    displayName: contextName,\r\n  });\r\n\r\nconst validateNames = (names: Names, caller: string) => {\r\n  for (const [name, value] of Object.entries(names)) {\r\n    assert(\r\n      typeof value === \"string\",\r\n      `${caller}: Expected ${name} to be a string. Got: ${typeof value}`,\r\n    );\r\n  }\r\n  if (names.hookName) {\r\n    assert(\r\n      names.hookName.startsWith(\"use\"),\r\n      `${caller}: hookName must start with \"use\". Got: ${names.hookName}`,\r\n    );\r\n  }\r\n};\r\n\r\nconst applyDefaultNames = ({\r\n  name,\r\n  contextName = `${capitalise(name)}Context`,\r\n  providerName = `${capitalise(name)}Provider`,\r\n  providerProp = name,\r\n  consumerName = `${capitalise(name)}Consumer`,\r\n  hookName = `use${capitalise(name)}`,\r\n}: Names): Required<Names> => ({\r\n  name,\r\n  contextName,\r\n  providerName,\r\n  providerProp,\r\n  consumerName,\r\n  hookName,\r\n});\r\n\r\nexport function createRequiredContext<T>(): {\r\n  with: <const N extends Names>(names: N) => NamedContextUtils<T, N>;\r\n} {\r\n  return {\r\n    with(names) {\r\n      validateNames(names, \"createRequiredContext\");\r\n\r\n      const {\r\n        contextName,\r\n        providerName,\r\n        providerProp,\r\n        consumerName,\r\n        hookName,\r\n      } = applyDefaultNames(names);\r\n\r\n      const Context = makeNamedContext<T | typeof UNSET_VALUE>(UNSET_VALUE, {\r\n        providerName,\r\n        contextName,\r\n      });\r\n      return {\r\n        [contextName]: Context,\r\n        [providerName](props: PropsWithChildren<Record<string, T>>) {\r\n          return (\r\n            <Context.Provider value={props[providerProp] as never}>\r\n              {props.children}\r\n            </Context.Provider>\r\n          );\r\n        },\r\n        [consumerName](props: ConsumerProps<T>) {\r\n          return (\r\n            <Context.Consumer>\r\n              {(value) => {\r\n                assert(\r\n                  value !== UNSET_VALUE,\r\n                  notSet(consumerName, providerName),\r\n                );\r\n                return props.children(value);\r\n              }}\r\n            </Context.Consumer>\r\n          );\r\n        },\r\n        [hookName]() {\r\n          const value = useContext(Context);\r\n          assert(value !== UNSET_VALUE, notSet(hookName, providerName));\r\n          useDebugValue(value);\r\n          return value;\r\n        },\r\n      } as never;\r\n    },\r\n  };\r\n}\r\n\r\nexport function createOptionalContext<T>(defaultValue: T): {\r\n  with: <const N extends Names>(names: N) => NamedContextUtils<T, N, false>;\r\n} {\r\n  return {\r\n    with(names) {\r\n      validateNames(names, \"createOptionalContext\");\r\n\r\n      const {\r\n        contextName,\r\n        providerName,\r\n        providerProp,\r\n        consumerName,\r\n        hookName,\r\n      } = applyDefaultNames(names);\r\n\r\n      const Context = makeNamedContext(defaultValue, {\r\n        providerName,\r\n        contextName,\r\n      });\r\n      return {\r\n        [contextName]: Context,\r\n        [providerName](props: PropsWithChildren<Record<string, T>>) {\r\n          return (\r\n            <Context.Provider value={props[providerProp] as never}>\r\n              {props.children}\r\n            </Context.Provider>\r\n          );\r\n        },\r\n        [consumerName](props: ConsumerProps<T>) {\r\n          return <Context.Consumer {...props} />;\r\n        },\r\n        [hookName]() {\r\n          const value = useContext(Context);\r\n          useDebugValue(value);\r\n          return value;\r\n        },\r\n      } as never;\r\n    },\r\n  };\r\n}\r\n"],"mappings":"0jBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,SAAAE,IAAA,eAAAC,EAAAH,GAEA,IAAAI,EAAmC,iBCC5B,IAAMC,EAAc,OAAO,IAAI,oCAAoC,ECcnE,SAASC,EAAOC,EAAoBC,EAAoC,CAC7E,GAAI,CAACD,EACH,MAAM,IAAI,MAAMC,CAAO,CAE3B,CCpBA,IAAAC,EAAgE,sBAOzD,IAAMC,EAAS,CAACC,EAAgBC,IACrC,GAAGD,CAAM,mCAAmCC,CAAY,qBHD1D,SAASC,EACPC,EACQ,CACR,OAAOA,EAAQ,cAAgB,GAAGA,EAAQ,aAAe,SAAS,WACpE,CAEO,SAASC,EACdC,EACG,CACH,IAAMC,KAAQ,EAAAC,KAAYF,CAAM,EAChC,OAAAG,EACEF,IAAUG,EACV,SAAUJ,EACN,gCACAK,EAAO,MAAOR,EAAgBG,CAAM,CAAC,CAC3C,EACOC,CACT","names":["canary_exports","__export","use","__toCommonJS","import_react","UNSET_VALUE","assert","condition","message","import_react","notSet","caller","providerName","getProviderName","context","use","usable","value","originalUse","assert","UNSET_VALUE","notSet"]}