Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
flet / components / use_context.py
Size: Mime:
from collections.abc import Callable
from typing import TypeVar, cast

from typing_extensions import Protocol

from flet.components.component import _get_renderer, current_component
from flet.components.hooks import ContextHook
from flet.components.observable import Observable

ContextValueT = TypeVar("ContextValueT")

T = TypeVar("T")  # context value type
ProviderResultT = TypeVar(
    "ProviderResultT", covariant=True
)  # return type of the callback/provider


class ContextProvider(Protocol[T]):
    default_value: T
    _key: object

    # Generic call: whatever the callback returns (ProviderResultT),
    # the provider returns too.
    def __call__(
        self, value: T, callback: Callable[[], ProviderResultT]
    ) -> ProviderResultT: ...


def create_context(default_value: T) -> ContextProvider[T]:
    key = object()

    def provider(value: T, callback: Callable[[], ProviderResultT]) -> ProviderResultT:  # type: ignore[type-var]
        r = _get_renderer()
        r._push_context(key, value)
        try:
            return callback()  # type: ignore[return-value]
        finally:
            r._pop_context(key)

    p = cast(ContextProvider[T], provider)
    p.default_value = default_value
    p._key = key
    return p


def use_context(context: ContextProvider[T]) -> T:
    component = current_component()
    component.use_hook(lambda: ContextHook(component))

    value = cast(T, context.default_value)
    # look up the component tree for the nearest context provider
    comp = component
    while comp:
        if context._key in comp._state.contexts:
            value = cast(T, comp._state.contexts[context._key])
            break
        comp = comp._parent_component() if comp._parent_component else None

    if isinstance(value, Observable):
        component._attach_observable_subscription(value)

    return value