react-ko
Version:
React + Knockout integration library
1 lines • 8.28 kB
Source Map (JSON)
{"version":3,"sources":["../src/index.ts","../src/context/AppViewModelContext.ts","../src/components/scope/RootKnockoutProvider.tsx","../src/components/scope/KnockoutScope.tsx","../src/components/structural/KoForeach.tsx","../src/components/structural/KoIf.tsx","../src/components/structural/KoIfNot.tsx","../src/components/structural/compat/KoForeachComment.tsx","../src/components/structural/compat/KoIfComment.tsx","../src/components/structural/compat/KoIfNotComment.tsx"],"sourcesContent":["export * from './context'\r\nexport * from './components/scope'\r\nexport * from './components/structural'\r\nexport * from './components/structural/compat'\r\n","import { createContext, useContext } from 'react'\r\n\r\n/**\r\n * Context to store the global AppViewModel.\r\n * Intended to be overridden by consumer's ViewModel type.\r\n */\r\nexport const AppViewModelContext = createContext<unknown | null>(null)\r\n\r\n/**\r\n * Hook to access the current AppViewModel.\r\n * Must be used within a RootKnockoutProvider.\r\n */\r\nexport function useAppViewModel<T>(): T {\r\n const context = useContext(AppViewModelContext)\r\n if (context === null) {\r\n throw new Error('useAppViewModel must be used within a RootKnockoutProvider.')\r\n }\r\n return context as T\r\n}","import React, { useRef, useLayoutEffect, useMemo } from 'react'\r\nimport ko from 'knockout'\r\nimport { AppViewModelContext } from '@/index'\r\n\r\ntype Props<T> = {\r\n viewModel: T\r\n children: React.ReactNode\r\n}\r\n\r\n/**\r\n * Applies Knockout bindings once on initial render,\r\n * and provides the ViewModel via context.\r\n */\r\nexport const RootKnockoutProvider = React.memo(function RootKnockoutProvider<T>({ viewModel, children }: Props<T>) {\r\n const koContainer = useRef<HTMLDivElement | null>(null)\r\n const isBoundRef = useRef(false)\r\n\r\n const appViewModel = useMemo(() => viewModel, [viewModel])\r\n\r\n useLayoutEffect(() => {\r\n if (koContainer.current === null) {\r\n return\r\n }\r\n if (isBoundRef.current === true) {\r\n return\r\n }\r\n ko.applyBindings(appViewModel, koContainer.current)\r\n isBoundRef.current = true\r\n }, [appViewModel])\r\n\r\n return (\r\n <AppViewModelContext.Provider value={appViewModel}>\r\n <div ref={koContainer} style={{ display: 'contents' }}>\r\n {children}\r\n </div>\r\n </AppViewModelContext.Provider>\r\n )\r\n})","import React, { useMemo, useLayoutEffect } from 'react'\r\nimport { useAppViewModel } from '@/index'\r\n\r\ntype Props<T> = {\r\n viewModel: T\r\n children: React.ReactNode\r\n}\r\n\r\n/**\r\n * Wraps a child component with a Knockout `with:` binding scope\r\n * to isolate a sub-ViewModel within the global ViewModel.\r\n */\r\nexport const KnockoutScope = React.memo(function KnockoutScope<T>({ viewModel, children }: Props<T>) {\r\n const appViewModel = useAppViewModel<Record<string, unknown>>()\r\n\r\n const uniqueKey = useMemo(() => crypto.randomUUID(), [])\r\n\r\n useLayoutEffect(() => {\r\n appViewModel[uniqueKey] = viewModel\r\n\r\n return () => {\r\n delete appViewModel[uniqueKey]\r\n }\r\n }, [appViewModel, viewModel, uniqueKey])\r\n\r\n return (\r\n <div data-bind={`with: $root['${uniqueKey}']`} style={{ display: 'contents' }}>\r\n {children}\r\n </div>\r\n )\r\n})","import React from 'react'\r\nimport ko from 'knockout'\r\nimport { KnockoutScope } from '@/index'\r\n\r\ntype Props = {\r\n items: ko.Observable<unknown[]> | ko.Computed<unknown[]> | unknown[]\r\n children: React.ReactNode\r\n}\r\n\r\n/**\r\n * Renders children for each item in the given array.\r\n * Uses Knockout's `foreach:` binding internally.\r\n */\r\nexport const KoForeach = React.memo(function KoForeach({ items, children }: Props) {\r\n const vm = { items }\r\n\r\n return (\r\n <KnockoutScope viewModel={vm}>\r\n <div data-bind=\"foreach: items\" style={{ display: 'contents' }}>\r\n {children}\r\n </div>\r\n </KnockoutScope>\r\n )\r\n})","import React from 'react'\r\nimport ko from 'knockout'\r\nimport { KnockoutScope } from '@/index'\r\n\r\ntype Props = {\r\n condition: ko.Observable<boolean> | ko.Computed<boolean> | boolean\r\n children: React.ReactNode\r\n}\r\n\r\n/**\r\n * Wraps children with a Knockout `if:` binding using a `div` container.\r\n * Safer and more efficient than comment-based bindings in React.\r\n * Recommended for standard usage when template compatibility is not required.\r\n */\r\nexport const KoIf = React.memo(function KoIf({ condition, children }: Props) {\r\n const vm = { condition }\r\n\r\n return (\r\n <KnockoutScope viewModel={vm}>\r\n <div data-bind=\"if: condition\" style={{ display: 'contents' }}>\r\n {children}\r\n </div>\r\n </KnockoutScope>\r\n )\r\n})\r\n","import React from 'react'\r\nimport { KnockoutScope } from '@/index'\r\n\r\ntype Props = {\r\n condition: ko.Observable<boolean> | ko.Computed<boolean> | boolean\r\n children: React.ReactNode\r\n}\r\n\r\n/**\r\n * Renders children only when the given condition is false.\r\n * Uses Knockout's `ifnot:` binding internally.\r\n */\r\nexport const KoIfNot = React.memo(function KoIfNot({ condition, children }: Props) {\r\n const vm = { condition }\r\n\r\n return (\r\n <KnockoutScope viewModel={vm}>\r\n <div data-bind=\"ifnot: condition\" style={{ display: 'contents' }}>\r\n {children}\r\n </div>\r\n </KnockoutScope>\r\n )\r\n})","import { KoForeach } from \"@/index\"\r\n\r\n/**\r\n * @deprecated Use `KoForeach` instead. This component will be removed in a future version.\r\n */\r\nexport const KoForeachComment = KoForeach\r\n","import { KoIf } from \"@/index\"\r\n\r\n/**\r\n * @deprecated Use `KoIf` instead. This component will be removed in a future version.\r\n */\r\nexport const KoIfComment = KoIf\r\n","import { KoIfNot } from \"@/index\"\r\n\r\n/**\r\n * @deprecated Use `KoIfNot` instead. This component will be removed in a future version.\r\n */\r\nexport const KoIfNotComment = KoIfNot\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,mBAA0C;AAMnC,IAAM,0BAAsB,4BAA8B,IAAI;AAM9D,SAAS,kBAAwB;AACtC,QAAM,cAAU,yBAAW,mBAAmB;AAC9C,MAAI,YAAY,MAAM;AACpB,UAAM,IAAI,MAAM,6DAA6D;AAAA,EAC/E;AACA,SAAO;AACT;;;AClBA,IAAAA,gBAAwD;AACxD,sBAAe;AA+BT;AAnBC,IAAM,uBAAuB,cAAAC,QAAM,KAAK,SAASC,sBAAwB,EAAE,WAAW,SAAS,GAAa;AACjH,QAAM,kBAAc,sBAA8B,IAAI;AACtD,QAAM,iBAAa,sBAAO,KAAK;AAE/B,QAAM,mBAAe,uBAAQ,MAAM,WAAW,CAAC,SAAS,CAAC;AAEzD,qCAAgB,MAAM;AACpB,QAAI,YAAY,YAAY,MAAM;AAChC;AAAA,IACF;AACA,QAAI,WAAW,YAAY,MAAM;AAC/B;AAAA,IACF;AACA,oBAAAC,QAAG,cAAc,cAAc,YAAY,OAAO;AAClD,eAAW,UAAU;AAAA,EACvB,GAAG,CAAC,YAAY,CAAC;AAEjB,SACE,4CAAC,oBAAoB,UAApB,EAA6B,OAAO,cACnC,sDAAC,SAAI,KAAK,aAAa,OAAO,EAAE,SAAS,WAAW,GACjD,UACH,GACF;AAEJ,CAAC;;;ACrCD,IAAAC,gBAAgD;AA0B5C,IAAAC,sBAAA;AAdG,IAAM,gBAAgB,cAAAC,QAAM,KAAK,SAASC,eAAiB,EAAE,WAAW,SAAS,GAAa;AACnG,QAAM,eAAe,gBAAyC;AAE9D,QAAM,gBAAY,uBAAQ,MAAM,OAAO,WAAW,GAAG,CAAC,CAAC;AAEvD,qCAAgB,MAAM;AACpB,iBAAa,SAAS,IAAI;AAE1B,WAAO,MAAM;AACX,aAAO,aAAa,SAAS;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,cAAc,WAAW,SAAS,CAAC;AAEvC,SACE,6CAAC,SAAI,aAAW,gBAAgB,SAAS,MAAM,OAAO,EAAE,SAAS,WAAW,GACzE,UACH;AAEJ,CAAC;;;AC9BD,IAAAC,gBAAkB;AAkBZ,IAAAC,sBAAA;AALC,IAAM,YAAY,cAAAC,QAAM,KAAK,SAASC,WAAU,EAAE,OAAO,SAAS,GAAU;AACjF,QAAM,KAAK,EAAE,MAAM;AAEnB,SACE,6CAAC,iBAAc,WAAW,IACxB,uDAAC,SAAI,aAAU,kBAAiB,OAAO,EAAE,SAAS,WAAW,GAC1D,UACH,GACF;AAEJ,CAAC;;;ACvBD,IAAAC,gBAAkB;AAmBZ,IAAAC,sBAAA;AALC,IAAM,OAAO,cAAAC,QAAM,KAAK,SAASC,MAAK,EAAE,WAAW,SAAS,GAAU;AAC3E,QAAM,KAAK,EAAE,UAAU;AAEvB,SACE,6CAAC,iBAAc,WAAW,IACxB,uDAAC,SAAI,aAAU,iBAAgB,OAAO,EAAE,SAAS,WAAW,GACzD,UACH,GACF;AAEJ,CAAC;;;ACxBD,IAAAC,gBAAkB;AAiBZ,IAAAC,sBAAA;AALC,IAAM,UAAU,cAAAC,QAAM,KAAK,SAASC,SAAQ,EAAE,WAAW,SAAS,GAAU;AACjF,QAAM,KAAK,EAAE,UAAU;AAEvB,SACE,6CAAC,iBAAc,WAAW,IACxB,uDAAC,SAAI,aAAU,oBAAmB,OAAO,EAAE,SAAS,WAAW,GAC5D,UACH,GACF;AAEJ,CAAC;;;ACjBM,IAAM,mBAAmB;;;ACAzB,IAAM,cAAc;;;ACApB,IAAM,iBAAiB;","names":["import_react","React","RootKnockoutProvider","ko","import_react","import_jsx_runtime","React","KnockoutScope","import_react","import_jsx_runtime","React","KoForeach","import_react","import_jsx_runtime","React","KoIf","import_react","import_jsx_runtime","React","KoIfNot"]}