pyglove 0.4.5.dev202412080808__tar.gz → 0.4.5.dev202412100720__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/PKG-INFO +1 -1
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/base.py +1 -1
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/controls/base.py +41 -4
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/controls/label.py +12 -1
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/controls/label_test.py +21 -2
- pyglove-0.4.5.dev202412100720/pyglove/core/views/html/controls/tab.py +242 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/controls/tab_test.py +13 -15
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove.egg-info/PKG-INFO +1 -1
- pyglove-0.4.5.dev202412080808/pyglove/core/views/html/controls/tab.py +0 -169
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/LICENSE +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/README.md +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/detouring/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/detouring/class_detour.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/detouring/class_detour_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/base.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/base_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/categorical.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/categorical_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/custom.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/custom_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/deduping.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/deduping_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/dna_generator.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/dna_generator_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/numerical.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/numerical_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/random.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/random_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/space.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/space_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/sweeping.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/sweeping_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/base.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/categorical.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/categorical_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/custom.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/custom_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/derived.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/derived_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/dynamic_evaluation.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/dynamic_evaluation_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/evolvable.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/evolvable_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/iter.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/iter_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/numerical.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/numerical_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/object_template.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/hyper/object_template_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/io/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/io/file_system.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/io/file_system_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/io/sequence.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/io/sequence_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/logging.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/logging_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/codegen.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/codegen_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/common_traits.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/common_traits_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/docstr_utils.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/docstr_utils_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/error_utils.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/error_utils_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/formatting.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/formatting_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/hierarchical.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/hierarchical_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/json_conversion.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/json_conversion_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/missing.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/missing_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/thread_local.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/thread_local_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/timing.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/timing_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/value_location.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/object_utils/value_location_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/patching/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/patching/object_factory.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/patching/object_factory_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/patching/pattern_based.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/patching/pattern_based_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/patching/rule_based.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/patching/rule_based_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/base.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/base_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/boilerplate.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/boilerplate_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/class_wrapper.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/class_wrapper_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/compounding.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/compounding_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/dict.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/dict_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/diff.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/diff_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/flags.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/flags_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/functor.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/functor_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/inferred.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/inferred_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/list.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/list_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/object.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/object_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/origin.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/origin_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/pure_symbolic.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/ref.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/ref_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/symbolize.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/symbolic/symbolize_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/tuning/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/tuning/backend.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/tuning/backend_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/tuning/early_stopping.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/tuning/local_backend.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/tuning/protocols.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/tuning/protocols_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/tuning/sample.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/tuning/sample_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/annotated.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/annotated_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/annotation_conversion.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/annotation_conversion_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/callable_ext.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/callable_ext_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/callable_signature.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/callable_signature_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/class_schema.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/class_schema_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/custom_typing.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/inspect.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/inspect_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/key_specs.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/key_specs_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/pytype_support.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/type_conversion.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/type_conversion_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/typed_missing.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/typed_missing_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/value_specs.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/typing/value_specs_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/base.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/base_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/base_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/controls/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/controls/progress_bar.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/controls/progress_bar_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/controls/tooltip.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/controls/tooltip_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/tree_view.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/views/html/tree_view_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/early_stopping/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/early_stopping/base.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/early_stopping/base_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/early_stopping/step_wise.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/early_stopping/step_wise_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/base.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/base_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/hill_climb.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/hill_climb_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/mutators.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/mutators_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/neat.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/neat_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/nsga2.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/nsga2_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/recombinators.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/recombinators_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/regularized_evolution.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/regularized_evolution_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/selectors.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/selectors_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/where.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/evolution/where_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/mutfun/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/mutfun/base.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/mutfun/base_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/mutfun/basic_ops.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/mutfun/basic_ops_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/scalars/__init__.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/scalars/base.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/scalars/base_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/scalars/maths.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/scalars/maths_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/scalars/randoms.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/scalars/randoms_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/scalars/step_wise.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/ext/scalars/step_wise_test.py +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove.egg-info/SOURCES.txt +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove.egg-info/dependency_links.txt +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove.egg-info/requires.txt +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove.egg-info/top_level.txt +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/setup.cfg +0 -0
- {pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/setup.py +0 -0
@@ -62,6 +62,7 @@ class HtmlControl(pg_object.Object):
|
|
62
62
|
super()._on_bound()
|
63
63
|
self._rendered = False
|
64
64
|
self._css_styles = []
|
65
|
+
self._dynamic_injected_css = set()
|
65
66
|
self._scripts = []
|
66
67
|
|
67
68
|
def add_style(self, *css: str) -> 'HtmlControl':
|
@@ -76,6 +77,7 @@ class HtmlControl(pg_object.Object):
|
|
76
77
|
def to_html(self, **kwargs) -> Html:
|
77
78
|
"""Returns the HTML representation of the control."""
|
78
79
|
self._rendered = True
|
80
|
+
self._dynamic_injected_css = set()
|
79
81
|
html = self._to_html(**kwargs)
|
80
82
|
return html.add_style(*self._css_styles).add_script(*self._scripts)
|
81
83
|
|
@@ -102,7 +104,7 @@ class HtmlControl(pg_object.Object):
|
|
102
104
|
"""Synchronizes displayed values to members."""
|
103
105
|
self.rebind(fields, skip_notification=True, raise_on_no_change=False)
|
104
106
|
|
105
|
-
def _run_javascript(self, code: str) -> None:
|
107
|
+
def _run_javascript(self, code: str, debug: bool = False) -> None:
|
106
108
|
"""Runs the given JavaScript code."""
|
107
109
|
if not self.interactive:
|
108
110
|
raise ValueError(
|
@@ -113,6 +115,8 @@ class HtmlControl(pg_object.Object):
|
|
113
115
|
return
|
114
116
|
|
115
117
|
code = inspect.cleandoc(code)
|
118
|
+
if debug:
|
119
|
+
print('RUN JAVSCRIPT:\n', code)
|
116
120
|
if _notebook is not None:
|
117
121
|
_notebook.display(_notebook.Javascript(code))
|
118
122
|
|
@@ -121,6 +125,40 @@ class HtmlControl(pg_object.Object):
|
|
121
125
|
for tracked in all_tracked:
|
122
126
|
tracked.append(code)
|
123
127
|
|
128
|
+
def _add_css_rules(self, css: str) -> None:
|
129
|
+
if not self._rendered or not css or css in self._dynamic_injected_css:
|
130
|
+
return
|
131
|
+
self._run_javascript(
|
132
|
+
f"""
|
133
|
+
const style = document.createElement('style');
|
134
|
+
style.type = 'text/css';
|
135
|
+
style.textContent = "{Html.escape(css, javascript_str=True)}";
|
136
|
+
document.head.appendChild(style);
|
137
|
+
"""
|
138
|
+
)
|
139
|
+
self._dynamic_injected_css.add(css)
|
140
|
+
|
141
|
+
def _apply_css_rules(self, html: Html) -> None:
|
142
|
+
self._add_css_rules(html.styles.content)
|
143
|
+
|
144
|
+
def _insert_adjacent_html(
|
145
|
+
self,
|
146
|
+
element_selector_js: str,
|
147
|
+
html: Html,
|
148
|
+
var_name: str = 'elem',
|
149
|
+
position: str = 'beforeend'
|
150
|
+
):
|
151
|
+
self._run_javascript(
|
152
|
+
f"""
|
153
|
+
{element_selector_js}
|
154
|
+
{var_name}.insertAdjacentHTML(
|
155
|
+
"{position}",
|
156
|
+
"{Html.escape(html, javascript_str=True).to_str(content_only=True)}"
|
157
|
+
);
|
158
|
+
""",
|
159
|
+
)
|
160
|
+
self._apply_css_rules(html)
|
161
|
+
|
124
162
|
def element_id(self, child: Optional[str] = None) -> Optional[str]:
|
125
163
|
"""Returns the element id of this control or a child."""
|
126
164
|
if self.id is not None:
|
@@ -163,14 +201,13 @@ class HtmlControl(pg_object.Object):
|
|
163
201
|
child: Optional[str] = None,
|
164
202
|
) -> base.Html:
|
165
203
|
"""Updates the inner HTML of the control."""
|
166
|
-
js_html = Html.escape(html, javascript_str=True)
|
167
|
-
assert isinstance(js_html, Html), js_html
|
168
204
|
self._run_javascript(
|
169
205
|
f"""
|
170
206
|
elem = document.getElementById("{self.element_id(child)}");
|
171
|
-
elem.innerHTML = "{
|
207
|
+
elem.innerHTML = "{Html.escape(html, javascript_str=True).to_str(content_only=True)}";
|
172
208
|
"""
|
173
209
|
)
|
210
|
+
self._add_css_rules(html.styles.content)
|
174
211
|
return html
|
175
212
|
|
176
213
|
def _update_style(
|
@@ -96,6 +96,8 @@ class Label(HtmlControl):
|
|
96
96
|
tooltip: Union[str, Html, None] = None,
|
97
97
|
link: Optional[str] = None,
|
98
98
|
styles: Optional[Dict[str, Any]] = None,
|
99
|
+
add_class: Optional[List[str]] = None,
|
100
|
+
remove_class: Optional[List[str]] = None,
|
99
101
|
) -> None:
|
100
102
|
if text is not None:
|
101
103
|
self._sync_members(text=self._update_content(text))
|
@@ -105,7 +107,16 @@ class Label(HtmlControl):
|
|
105
107
|
self._sync_members(link=self._update_property('href', link))
|
106
108
|
if tooltip is not None:
|
107
109
|
self.tooltip.update(content=tooltip)
|
108
|
-
|
110
|
+
if add_class or remove_class:
|
111
|
+
css_classes = list(self.css_classes)
|
112
|
+
for x in add_class or []:
|
113
|
+
self._add_css_class(x)
|
114
|
+
css_classes.append(x)
|
115
|
+
for x in remove_class or []:
|
116
|
+
self._remove_css_class(x)
|
117
|
+
if x in css_classes:
|
118
|
+
css_classes.remove(x)
|
119
|
+
self._sync_members(css_classes=css_classes)
|
109
120
|
|
110
121
|
# Register converter for automatic conversion.
|
111
122
|
pg_typing.register_converter(str, Label, Label)
|
@@ -60,19 +60,26 @@ class LabelTest(TestCase):
|
|
60
60
|
)
|
61
61
|
|
62
62
|
def test_update(self):
|
63
|
-
label = label_lib.Label(
|
63
|
+
label = label_lib.Label(
|
64
|
+
'foo', 'bar', 'http://google.com',
|
65
|
+
interactive=True,
|
66
|
+
css_classes=['foo', 'bar'],
|
67
|
+
)
|
64
68
|
self.assertIn('id="control-', label.to_html_str(content_only=True))
|
65
69
|
with label.track_scripts() as scripts:
|
66
70
|
label.update(
|
67
71
|
'bar',
|
68
72
|
tooltip='baz',
|
69
73
|
link='http://www.yahoo.com',
|
70
|
-
styles=dict(color='red')
|
74
|
+
styles=dict(color='red'),
|
75
|
+
add_class=['baz'],
|
76
|
+
remove_class=['bar'],
|
71
77
|
)
|
72
78
|
self.assertEqual(label.text, 'bar')
|
73
79
|
self.assertEqual(label.tooltip.content, 'baz')
|
74
80
|
self.assertEqual(label.link, 'http://www.yahoo.com')
|
75
81
|
self.assertEqual(label.styles, dict(color='red'))
|
82
|
+
self.assertEqual(label.css_classes, ['foo', 'baz'])
|
76
83
|
self.assertEqual(
|
77
84
|
scripts,
|
78
85
|
[
|
@@ -106,6 +113,18 @@ class LabelTest(TestCase):
|
|
106
113
|
elem.classList.remove("html-content");
|
107
114
|
"""
|
108
115
|
),
|
116
|
+
inspect.cleandoc(
|
117
|
+
f"""
|
118
|
+
elem = document.getElementById("{label.element_id()}");
|
119
|
+
elem.classList.add("baz");
|
120
|
+
"""
|
121
|
+
),
|
122
|
+
inspect.cleandoc(
|
123
|
+
f"""
|
124
|
+
elem = document.getElementById("{label.element_id()}");
|
125
|
+
elem.classList.remove("bar");
|
126
|
+
"""
|
127
|
+
),
|
109
128
|
]
|
110
129
|
)
|
111
130
|
|
@@ -0,0 +1,242 @@
|
|
1
|
+
# Copyright 2024 The PyGlove Authors
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
"""Tab control."""
|
15
|
+
|
16
|
+
from typing import Annotated, List, Literal, Union
|
17
|
+
|
18
|
+
from pyglove.core.symbolic import flags as pg_flags
|
19
|
+
from pyglove.core.symbolic import object as pg_object
|
20
|
+
|
21
|
+
# pylint: disable=g-importing-member
|
22
|
+
from pyglove.core.views.html.base import Html
|
23
|
+
from pyglove.core.views.html.base import HtmlConvertible
|
24
|
+
from pyglove.core.views.html.controls.base import HtmlControl
|
25
|
+
from pyglove.core.views.html.controls.label import Label
|
26
|
+
# pylint: enable=g-importing-member
|
27
|
+
|
28
|
+
|
29
|
+
class Tab(pg_object.Object):
|
30
|
+
"""A tab."""
|
31
|
+
|
32
|
+
label: Annotated[
|
33
|
+
Label,
|
34
|
+
'The label of the tab.'
|
35
|
+
]
|
36
|
+
|
37
|
+
content: Annotated[
|
38
|
+
Union[Html, HtmlConvertible],
|
39
|
+
'The content of the tab.'
|
40
|
+
]
|
41
|
+
|
42
|
+
css_classes: Annotated[
|
43
|
+
List[str],
|
44
|
+
'The CSS classes of the tab.'
|
45
|
+
] = []
|
46
|
+
|
47
|
+
|
48
|
+
@pg_object.use_init_args(
|
49
|
+
['tabs', 'selected', 'tab_position', 'id', 'css_classes', 'styles']
|
50
|
+
)
|
51
|
+
class TabControl(HtmlControl):
|
52
|
+
"""A tab control."""
|
53
|
+
|
54
|
+
tabs: Annotated[
|
55
|
+
List[Tab],
|
56
|
+
'The tabs of the tab control.'
|
57
|
+
]
|
58
|
+
|
59
|
+
selected: Annotated[
|
60
|
+
int,
|
61
|
+
'The index of the selected tab.'
|
62
|
+
] = 0
|
63
|
+
|
64
|
+
tab_position: Annotated[
|
65
|
+
Literal['top', 'left'],
|
66
|
+
'The direction of the tab control.'
|
67
|
+
] = 'top'
|
68
|
+
|
69
|
+
interactive = True
|
70
|
+
|
71
|
+
def append(self, tab: Tab) -> None:
|
72
|
+
with pg_flags.notify_on_change(False):
|
73
|
+
self.tabs.append(tab)
|
74
|
+
|
75
|
+
self._insert_adjacent_html(
|
76
|
+
f"""
|
77
|
+
const elem = document.getElementById('{self.element_id()}-button-group');
|
78
|
+
""",
|
79
|
+
self._tab_button(tab, len(self.tabs) - 1),
|
80
|
+
position='beforeend',
|
81
|
+
)
|
82
|
+
self._insert_adjacent_html(
|
83
|
+
f"""
|
84
|
+
const elem = document.getElementById('{self.element_id()}-content-group');
|
85
|
+
""",
|
86
|
+
self._tab_content(tab, len(self.tabs) - 1),
|
87
|
+
position='beforeend',
|
88
|
+
)
|
89
|
+
|
90
|
+
def extend(self, tabs: List[Tab]) -> None:
|
91
|
+
for tab in tabs:
|
92
|
+
self.append(tab)
|
93
|
+
|
94
|
+
def _to_html(self, **kwargs):
|
95
|
+
return Html.element(
|
96
|
+
'table',
|
97
|
+
[
|
98
|
+
'<tr><td>',
|
99
|
+
Html.element(
|
100
|
+
'div',
|
101
|
+
[self._tab_button(tab, i) for i, tab in enumerate(self.tabs)],
|
102
|
+
css_classes=[
|
103
|
+
'tab-button-group',
|
104
|
+
self.tab_position
|
105
|
+
] + self.css_classes,
|
106
|
+
id=self.element_id('button-group'),
|
107
|
+
),
|
108
|
+
('</td><td>' if self.tab_position == 'left'
|
109
|
+
else '</td></tr><tr><td>'),
|
110
|
+
Html.element(
|
111
|
+
'div',
|
112
|
+
[self._tab_content(tab, i) for i, tab in enumerate(self.tabs)],
|
113
|
+
css_classes=[
|
114
|
+
'tab-content-group',
|
115
|
+
self.tab_position
|
116
|
+
] + self.css_classes,
|
117
|
+
id=self.element_id('content-group'),
|
118
|
+
),
|
119
|
+
'</td></tr>'
|
120
|
+
],
|
121
|
+
css_classes=['tab-control'],
|
122
|
+
styles=self.styles,
|
123
|
+
).add_script(
|
124
|
+
"""
|
125
|
+
function openTab(event, controlId, tabId) {
|
126
|
+
const tabButtons = document.querySelectorAll('#' + controlId + '-button-group > .tab-button');
|
127
|
+
for (let i = 0; i < tabButtons.length; i++) {
|
128
|
+
tabButtons[i].classList.remove('selected');
|
129
|
+
}
|
130
|
+
const tabContents = document.querySelectorAll('#' + controlId + '-content-group > .tab-content');
|
131
|
+
for (let i = 0; i < tabContents.length; i++) {
|
132
|
+
tabContents[i].classList.remove('selected')
|
133
|
+
}
|
134
|
+
const tabButton = event.currentTarget;
|
135
|
+
tabButton.classList.add('selected');
|
136
|
+
document.getElementById(tabId).classList.add('selected');
|
137
|
+
}
|
138
|
+
"""
|
139
|
+
).add_style(
|
140
|
+
"""
|
141
|
+
.tab-control {
|
142
|
+
border-spacing: 0px;
|
143
|
+
border-collapse: collapse;
|
144
|
+
height: 100%;
|
145
|
+
margin-top: 10px;
|
146
|
+
}
|
147
|
+
.tab-control td {
|
148
|
+
padding: 0px;
|
149
|
+
margin: 0px;
|
150
|
+
vertical-align: top;
|
151
|
+
}
|
152
|
+
.top.tab-button-group {
|
153
|
+
border-left: 1px solid #DDD;
|
154
|
+
border-top: 1px solid #DDD;
|
155
|
+
border-right: 1px solid #DDD;
|
156
|
+
border-radius: 5px 5px 0px 0px;
|
157
|
+
padding: 0px 5px 0px 0px;
|
158
|
+
margin-bottom: -2px;
|
159
|
+
}
|
160
|
+
.tab-button {
|
161
|
+
background-color: transparent;
|
162
|
+
border-radius: 5px;
|
163
|
+
border: 0px;
|
164
|
+
font-weight: bold;
|
165
|
+
color: gray;
|
166
|
+
outline: none;
|
167
|
+
cursor: pointer;
|
168
|
+
transition: 0.3s;
|
169
|
+
}
|
170
|
+
.tab-button:hover {
|
171
|
+
background-color: #fff1dd;
|
172
|
+
}
|
173
|
+
.tab-button.selected {
|
174
|
+
background-color: #f0ecf9;
|
175
|
+
color: black;
|
176
|
+
}
|
177
|
+
.top.tab-content-group {
|
178
|
+
border-left: 1px solid #DDD;
|
179
|
+
border-right: 1px solid #DDD;
|
180
|
+
border-bottom: 1px solid #DDD;
|
181
|
+
border-radius: 0px 0px 5px 5px;
|
182
|
+
margin: 0px;
|
183
|
+
padding: 5px;
|
184
|
+
height: 100%;
|
185
|
+
}
|
186
|
+
.top > .tab-button {
|
187
|
+
margin: 5px 0px 5px 5px;
|
188
|
+
}
|
189
|
+
.tab-content {
|
190
|
+
display: none;
|
191
|
+
}
|
192
|
+
.tab-content.selected {
|
193
|
+
display: block;
|
194
|
+
}
|
195
|
+
.left.tab-button-group {
|
196
|
+
display: inline-flex;
|
197
|
+
flex-direction: column;
|
198
|
+
border: 1px solid #DDD;
|
199
|
+
border-radius: 5px;
|
200
|
+
margin-right: 5px;
|
201
|
+
padding: 0px 0px 5px 0px;
|
202
|
+
}
|
203
|
+
.left.tab-content-group {
|
204
|
+
border: 0px
|
205
|
+
margin: 0px;
|
206
|
+
padding: 0px;
|
207
|
+
height: 100%;
|
208
|
+
}
|
209
|
+
.left > .tab-button {
|
210
|
+
text-align: left;
|
211
|
+
margin: 5px 5px 0px 5px;
|
212
|
+
}
|
213
|
+
"""
|
214
|
+
)
|
215
|
+
|
216
|
+
def _tab_button(self, tab: Tab, i: int) -> Html:
|
217
|
+
return Html.element(
|
218
|
+
'button',
|
219
|
+
[
|
220
|
+
tab.label
|
221
|
+
],
|
222
|
+
css_classes=[
|
223
|
+
'tab-button',
|
224
|
+
'selected' if i == self.selected else None
|
225
|
+
] + tab.css_classes,
|
226
|
+
onclick=(
|
227
|
+
f"""openTab(event, '{self.element_id()}', '{self.element_id(str(i))}')"""
|
228
|
+
)
|
229
|
+
)
|
230
|
+
|
231
|
+
def _tab_content(self, tab: Tab, i: int) -> Html:
|
232
|
+
return Html.element(
|
233
|
+
'div',
|
234
|
+
[
|
235
|
+
tab.content
|
236
|
+
],
|
237
|
+
css_classes=[
|
238
|
+
'tab-content',
|
239
|
+
'selected' if i == self.selected else None
|
240
|
+
] + tab.css_classes,
|
241
|
+
id=self.element_id(str(i))
|
242
|
+
)
|
@@ -30,26 +30,24 @@ class TabControlTest(unittest.TestCase):
|
|
30
30
|
|
31
31
|
def test_basic(self):
|
32
32
|
tab = tab_lib.TabControl([
|
33
|
-
tab_lib.Tab('foo', base.Html('<h1>foo</h1>')),
|
33
|
+
tab_lib.Tab('foo', base.Html('<h1>foo</h1>'), css_classes=['foo']),
|
34
34
|
tab_lib.Tab('bar', base.Html('<h1>bar</h1>')),
|
35
35
|
])
|
36
|
+
elem_id = tab.element_id()
|
36
37
|
self.assert_html_content(
|
37
38
|
tab,
|
38
|
-
(
|
39
|
-
f'<div class="tab-control top" id="{tab.element_id()}">'
|
40
|
-
'<div class="tab-button-group"><button class="tab-button selected" '
|
41
|
-
f'''onclick="openTab(event, '{tab.element_id()}', '''
|
42
|
-
f''''{tab.element_id(str(0))}')">'''
|
43
|
-
'<a class="label">foo</a></button><button class="tab-button" '
|
44
|
-
f'''onclick="openTab(event, '{tab.element_id()}', '''
|
45
|
-
f''''{tab.element_id(str(1))}')">'''
|
46
|
-
'<a class="label">bar</a></button></div>'
|
47
|
-
'<div class="tab-content" style="display:block;" '
|
48
|
-
f'id="{tab.element_id(str(0))}"><h1>foo</h1></div>'
|
49
|
-
'<div class="tab-content" style="display:none;" '
|
50
|
-
f'id="{tab.element_id(str(1))}"><h1>bar</h1></div></div>'
|
51
|
-
)
|
39
|
+
f"""<table class="tab-control"><tr><td><div class="tab-button-group top" id="{elem_id}-button-group"><button class="tab-button selected foo" onclick="openTab(event, '{elem_id}', '{elem_id}-0')"><a class="label">foo</a></button><button class="tab-button" onclick="openTab(event, '{elem_id}', '{elem_id}-1')"><a class="label">bar</a></button></div></td></tr><tr><td><div class="tab-content-group top" id="{elem_id}-content-group"><div class="tab-content selected foo" id="{elem_id}-0"><h1>foo</h1></div><div class="tab-content" id="{elem_id}-1"><h1>bar</h1></div></div></td></tr></table>"""
|
52
40
|
)
|
41
|
+
with tab.track_scripts() as scripts:
|
42
|
+
tab.extend([
|
43
|
+
tab_lib.Tab(
|
44
|
+
'baz',
|
45
|
+
base.Html(
|
46
|
+
'<h1 class="a">baz</h1>').add_style('.a { color: red; }')
|
47
|
+
),
|
48
|
+
tab_lib.Tab('qux', base.Html('<h1>qux</h1>')),
|
49
|
+
])
|
50
|
+
self.assertEqual(len(scripts), 6)
|
53
51
|
|
54
52
|
|
55
53
|
if __name__ == '__main__':
|
@@ -1,169 +0,0 @@
|
|
1
|
-
# Copyright 2024 The PyGlove Authors
|
2
|
-
#
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
-
# you may not use this file except in compliance with the License.
|
5
|
-
# You may obtain a copy of the License at
|
6
|
-
#
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
-
#
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
-
# See the License for the specific language governing permissions and
|
13
|
-
# limitations under the License.
|
14
|
-
"""Tab control."""
|
15
|
-
|
16
|
-
from typing import Annotated, List, Literal, Union
|
17
|
-
|
18
|
-
from pyglove.core.symbolic import object as pg_object
|
19
|
-
# pylint: disable=g-importing-member
|
20
|
-
from pyglove.core.views.html.base import Html
|
21
|
-
from pyglove.core.views.html.base import HtmlConvertible
|
22
|
-
from pyglove.core.views.html.controls.base import HtmlControl
|
23
|
-
from pyglove.core.views.html.controls.label import Label
|
24
|
-
# pylint: enable=g-importing-member
|
25
|
-
|
26
|
-
|
27
|
-
class Tab(pg_object.Object):
|
28
|
-
"""A tab."""
|
29
|
-
|
30
|
-
label: Annotated[
|
31
|
-
Label,
|
32
|
-
'The label of the tab.'
|
33
|
-
]
|
34
|
-
|
35
|
-
content: Annotated[
|
36
|
-
Union[Html, HtmlConvertible],
|
37
|
-
'The content of the tab.'
|
38
|
-
]
|
39
|
-
|
40
|
-
|
41
|
-
@pg_object.use_init_args(
|
42
|
-
['tabs', 'selected', 'tab_position', 'id', 'css_classes', 'styles']
|
43
|
-
)
|
44
|
-
class TabControl(HtmlControl):
|
45
|
-
"""A tab control."""
|
46
|
-
|
47
|
-
tabs: Annotated[
|
48
|
-
List[Tab],
|
49
|
-
'The tabs of the tab control.'
|
50
|
-
]
|
51
|
-
|
52
|
-
selected: Annotated[
|
53
|
-
int,
|
54
|
-
'The index of the selected tab.'
|
55
|
-
] = 0
|
56
|
-
|
57
|
-
tab_position: Annotated[
|
58
|
-
Literal['top', 'left'],
|
59
|
-
'The direction of the tab control.'
|
60
|
-
] = 'top'
|
61
|
-
|
62
|
-
interactive = True
|
63
|
-
|
64
|
-
def _to_html(self, **kwargs):
|
65
|
-
return Html.element(
|
66
|
-
'div',
|
67
|
-
[
|
68
|
-
Html.element(
|
69
|
-
'div',
|
70
|
-
[
|
71
|
-
Html.element(
|
72
|
-
'button',
|
73
|
-
[
|
74
|
-
tab.label
|
75
|
-
],
|
76
|
-
css_classes=[
|
77
|
-
'tab-button',
|
78
|
-
'selected' if i == self.selected else None
|
79
|
-
],
|
80
|
-
onclick=(
|
81
|
-
f"""openTab(event, '{self.element_id()}', '{self.element_id(str(i))}')"""
|
82
|
-
)
|
83
|
-
) for i, tab in enumerate(self.tabs)
|
84
|
-
],
|
85
|
-
css_classes=['tab-button-group'],
|
86
|
-
),
|
87
|
-
] + [
|
88
|
-
Html.element(
|
89
|
-
'div',
|
90
|
-
[
|
91
|
-
tab.content
|
92
|
-
],
|
93
|
-
css_classes=['tab-content'],
|
94
|
-
styles=dict(
|
95
|
-
display='block' if i == self.selected else 'none'
|
96
|
-
),
|
97
|
-
id=self.element_id(str(i))
|
98
|
-
) for i, tab in enumerate(self.tabs)
|
99
|
-
],
|
100
|
-
css_classes=['tab-control', self.tab_position] + self.css_classes,
|
101
|
-
id=self.element_id(),
|
102
|
-
styles=self.styles,
|
103
|
-
).add_script(
|
104
|
-
"""
|
105
|
-
function openTab(event, controlId, tabId) {
|
106
|
-
const tabButtons = document.querySelectorAll('#' + controlId + '> .tab-button-group > .tab-button');
|
107
|
-
for (let i = 0; i < tabButtons.length; i++) {
|
108
|
-
tabButtons[i].classList.remove('selected');
|
109
|
-
}
|
110
|
-
const tabContents = document.querySelectorAll('#' + controlId + '> .tab-content');
|
111
|
-
for (let i = 0; i < tabContents.length; i++) {
|
112
|
-
tabContents[i].style.display = 'none';
|
113
|
-
}
|
114
|
-
const tabButton = event.currentTarget;
|
115
|
-
tabButton.classList.add('selected');
|
116
|
-
document.getElementById(tabId).style.display = "block";
|
117
|
-
}
|
118
|
-
"""
|
119
|
-
).add_style(
|
120
|
-
"""
|
121
|
-
.top .tab-button-group {
|
122
|
-
overflow-x: hidden;
|
123
|
-
border-bottom: 1px solid #EEE;
|
124
|
-
}
|
125
|
-
.left .tab-button-group {
|
126
|
-
float: left;
|
127
|
-
top: 0;
|
128
|
-
}
|
129
|
-
.tab-button {
|
130
|
-
background-color: #EEE;
|
131
|
-
border: 1px solid #EEE;
|
132
|
-
outline: none;
|
133
|
-
cursor: pointer;
|
134
|
-
transition: 0.3s;
|
135
|
-
padding: 10px 15px 10px 15px;
|
136
|
-
}
|
137
|
-
.top .tab-button {
|
138
|
-
border-top-width: 2px;
|
139
|
-
}
|
140
|
-
.left .tab-button {
|
141
|
-
display: block;
|
142
|
-
width: 100%;
|
143
|
-
border-left-width: 2px;
|
144
|
-
}
|
145
|
-
.top .tab-button.selected {
|
146
|
-
border-bottom-color: #fff;
|
147
|
-
border-top-color: #B721FF;
|
148
|
-
background: #fff;
|
149
|
-
}
|
150
|
-
.left .tab-button.selected {
|
151
|
-
border-right-color: #fff;
|
152
|
-
border-left-color: #B721FF;
|
153
|
-
background: #fff;
|
154
|
-
}
|
155
|
-
.top .tab-button:hover {
|
156
|
-
border-top-color: orange;
|
157
|
-
}
|
158
|
-
.left .tab-button:hover {
|
159
|
-
border-left-color: orange;
|
160
|
-
}
|
161
|
-
.tab-content {
|
162
|
-
display: none;
|
163
|
-
padding: 10px;
|
164
|
-
}
|
165
|
-
.left .tab-content {
|
166
|
-
float: left;
|
167
|
-
}
|
168
|
-
"""
|
169
|
-
)
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
{pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/detouring/__init__.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/__init__.py
RENAMED
File without changes
|
File without changes
|
{pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/base_test.py
RENAMED
File without changes
|
{pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/categorical.py
RENAMED
File without changes
|
File without changes
|
File without changes
|
{pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/custom_test.py
RENAMED
File without changes
|
{pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/deduping.py
RENAMED
File without changes
|
{pyglove-0.4.5.dev202412080808 → pyglove-0.4.5.dev202412100720}/pyglove/core/geno/deduping_test.py
RENAMED
File without changes
|