UNPKG

@ea-lab/reactive-json-docs

Version:

Complete documentation for Reactive-JSON - Components, examples and LLM-parsable guides

472 lines (412 loc) 18.8 kB
renderView: - type: Markdown content: | # ReactiveJsonSubroot The `ReactiveJsonSubroot` component allows you to render a new Reactive-JSON root inside an existing application. It is useful for embedding a sub-application, isolating a part of the data tree, or rendering a separate rjbuild with its own options. With the `sharedUpdates` feature, the component can also propagate data changes back to the parent, enabling seamless communication between parent and subroot when working with shared data references. ## Properties - type: TabbedSerializer yamlSerializedContent: | # Complete rjOptions structure. - type: ReactiveJsonSubroot # Component-specific properties. sharedUpdates: true dataOverrideEvaluationDepth: 10 # Subroot configuration. rjOptions: # Loading from URL. rjBuildUrl: "/path/to/rjbuild.yaml" rjBuildFetchMethod: "GET" # or "POST". headersForRjBuild: Authorization: "Bearer token" Content-Type: "application/json" # OR inline definition. maybeRawAppRjBuild: renderView: - type: div content: "Subroot content." templates: myTemplate: type: span content: ~.value data: initialValue: "Hello World" # Data replacement. dataOverride: ~~.userData # Debug mode. debugMode: true # Standard actions. actions: - what: hide when: ~.condition - type: DefinitionList content: - term: code: rjOptions after: " (object, required)" details: - type: Markdown content: "Options to pass to the subroot - accepts **all** `ReactiveJsonRoot` properties including:" - type: DefinitionList content: - term: code: rjOptions.rjBuildUrl details: "URL to load the RjBuild from." - term: code: rjOptions.rjBuildFetchMethod details: "HTTP method (\"GET\" or \"POST\")." - term: code: rjOptions.headersForRjBuild details: "Headers for the request." - term: code: rjOptions.dataOverride details: "Override data for the loaded/defined RjBuild." - term: code: rjOptions.maybeRawAppRjBuild details: - type: Markdown content: "Inline RjBuild content (string or object) containing:" - type: DefinitionList content: - term: code: rjOptions.maybeRawAppRjBuild.renderView details: "View definition." - term: code: rjOptions.maybeRawAppRjBuild.templates details: "Template definitions." - term: code: rjOptions.maybeRawAppRjBuild.data details: "Initial data." - term: code: rjOptions.debugMode details: "Enable debug mode and related wrapper components." - term: code: sharedUpdates after: " (boolean, optional)" details: "Enable upstream data propagation to parent (default: false)." - term: code: dataOverrideEvaluationDepth after: " (number, optional)" details: "Special evaluation depth for dataOverride property (default: 10)." - type: Markdown content: | ### Standard properties - type: DefinitionList content: - term: code: actions after: " (array, optional)" details: "Actions to attach to the subroot." - type: Markdown content: | ## Behavior - Renders a new `ReactiveJsonRoot` with the provided options. - The subroot is typically isolated from the parent for data, templates, and rendering¹. - Plugins from the parent are automatically reused in the subroot. - All properties in `rjOptions` are evaluated with template values. - If `rjOptions` is not a valid object, nothing is rendered. ¹Note: Data isolation is bypassed when `sharedUpdates: true` is enabled, allowing the subroot to propagate data changes back to the parent. Templates and rendering contexts remain isolated. ## Shared Updates Feature When `sharedUpdates: true` is enabled, the component automatically detects template references in `dataOverride` and creates update callbacks to propagate changes back to the parent. ### How it works 1. **Automatic analysis**: The system analyzes `dataOverride` to detect references (`~~.`, `~.`, `~>`) to parent data 2. **Callback creation**: For each detected reference, an update callback is created 3. **Update interception**: When the subroot modifies data, the system checks if it corresponds to a parent reference 4. **Propagation**: If so, the update is propagated to the parent instead of being applied locally ### Advantages 1. **Automatic synchronization**: Data remains consistent between parent and subroot 2. **Simplicity**: No need to manually manage update callbacks 3. **Performance**: Avoids unnecessary re-renders by propagating directly to the right level 4. **Flexibility**: Supports different referencing patterns (~~., ~., ~>) and arrays containing references ### Supported vs Unsupported Cases #### Supported cases ##### Direct reference ```yaml dataOverride: ~~.user # Modifications in the subroot propagate to "user" in the parent ``` ##### Object mapping with references ```yaml dataOverride: userInfo: ~~.user settings: ~~.config # Modifications to "userInfo" propagate to "user" in the parent # Modifications to "settings" propagate to "config" in the parent ``` ##### Local references ```yaml dataOverride: ~.localData # Modifications propagate to the local template context ``` ##### Hierarchical references ```yaml dataOverride: ~>key.someData # Modifications propagate up the template hierarchy ``` ##### Arrays in dataOverride ```yaml dataOverride: - ~~.firstItem - ~~.secondItem # Array items with template references are properly handled ``` #### Unsupported cases ##### Nested references in data ```yaml dataOverride: someProperty: ~~.user data: someProperty: ~~.anotherProperty # Not supported ``` - type: RjBuildDescriber title: Example description: This example demonstrates how to embed a separate Reactive-JSON application using ReactiveJsonSubroot. The component loads and renders an independent rjbuild file, creating an isolated sub-application within the current view. toDescribe: renderView: - type: ReactiveJsonSubroot rjOptions: rjBuildUrl: "/rjbuild/component/message.yaml" - type: RjBuildDescriber title: Example with inline JSON data description: This example demonstrates two approaches for using ReactiveJsonSubroot with inline data. The first shows passing JSON data directly as a string via maybeRawAppRjBuild. The second shows loading subroot options dynamically from the main RjBuild's data using template interpolation. Both approaches are useful for embedding sub-applications without external files. toDescribe: renderView: - type: ReactiveJsonSubroot rjOptions: maybeRawAppRjBuild: '{"data":{"userName":"Alice","messageCount":3},"renderView":[{"type":"div","attributes":{"style":{"padding":"1rem","border":"1px solid #ddd","borderRadius":"8px","backgroundColor":"#f9f9f9"}},"content":[{"type":"h3","content":"~~.userName"},{"type":"p","content":["You have ","~~.messageCount"," new messages."]},{"type":"button","content":"Mark as read","attributes":{"style":{"backgroundColor":"#007bff","color":"white","border":"none","padding":"0.5rem 1rem","borderRadius":"4px"}}}]}]}' - type: hr - type: ReactiveJsonSubroot rjOptions: ~~.subrootToLoad data: subrootToLoad: maybeRawAppRjBuild: renderView: - type: div content: This second subroot is loaded from the "data" key of the main root. - type: RjBuildDescriber title: Example with Shared Updates description: This example demonstrates the `sharedUpdates` feature where changes in the subroot automatically propagate back to the parent data. Notice how modifying the text field in the subroot will update the display in the parent above it. toDescribe: data: user: name: "John Doe" email: "john@example.com" renderView: - type: div attributes: style: padding: "1rem" border: "2px solid #007bff" borderRadius: "8px" marginBottom: "1rem" content: - type: h4 content: "Parent Data Display" - type: p content: ["Name: ", ~~.user.name] - type: p content: ["Email: ", ~~.user.email] - type: ReactiveJsonSubroot sharedUpdates: true rjOptions: dataOverride: ~~.user maybeRawAppRjBuild: renderView: - type: div attributes: style: padding: "1rem" border: "2px solid #28a745" borderRadius: "8px" content: - type: h4 content: "Subroot Editor (with sharedUpdates)" - type: TextField label: "Name" dataLocation: ~.name - type: TextField label: "Email" dataLocation: ~.email - type: p attributes: style: fontSize: "0.9em" color: "#666" marginTop: "0.5rem" content: "Changes here automatically update the parent data above ↑" - type: RjBuildDescriber title: Example with Multi-Section Configuration description: This example shows how `sharedUpdates` works with complex data mappings where different parts of the parent data are mapped to different sections in the subroot. toDescribe: data: profile: name: "Alice Smith" age: 28 settings: theme: "dark" language: "en" renderView: - type: div attributes: style: display: "grid" gridTemplateColumns: "1fr 1fr" gap: "1rem" marginBottom: "1rem" content: - type: div attributes: style: padding: "1rem" border: "1px solid #ddd" borderRadius: "4px" content: - type: h5 content: "Profile Data" - type: p content: ["Name: ", ~~.profile.name] - type: p content: ["Age: ", ~~.profile.age] - type: div attributes: style: padding: "1rem" border: "1px solid #ddd" borderRadius: "4px" content: - type: h5 content: "Settings Data" - type: p content: ["Theme: ", ~~.settings.theme] - type: p content: ["Language: ", ~~.settings.language] - type: ReactiveJsonSubroot sharedUpdates: true rjOptions: dataOverride: userProfile: ~~.profile userSettings: ~~.settings maybeRawAppRjBuild: renderView: - type: div attributes: style: display: "grid" gridTemplateColumns: "1fr 1fr" gap: "1rem" padding: "1rem" border: "2px solid #17a2b8" borderRadius: "8px" content: - type: div content: - type: h5 content: "Edit Profile" - type: TextField label: "Name" dataLocation: ~.userProfile.name - type: NumberField label: "Age" dataLocation: ~.userProfile.age - type: div content: - type: h5 content: "Edit Settings" - type: TextField label: "Theme" dataLocation: ~.userSettings.theme - type: TextField label: "Language" dataLocation: ~.userSettings.language - type: RjBuildDescriber title: Example with Array References description: This example demonstrates how to work with arrays in `dataOverride` where each array item is mapped to different parts of the parent data. The subroot can edit individual array items and changes will be propagated back to their respective locations in the parent array. toDescribe: data: items: - title: "Task 1" completed: false - title: "Task 2" completed: true renderView: - type: div attributes: style: padding: "1rem" border: "1px solid #ddd" borderRadius: "4px" marginBottom: "1rem" content: - type: h4 content: "Parent Items Display" - type: p content: ["Item 1: ", ~~.items.0.title, " (", ~~.items.0.completed, ")"] - type: p content: ["Item 2: ", ~~.items.1.title, " (", ~~.items.1.completed, ")"] - type: ReactiveJsonSubroot sharedUpdates: true rjOptions: dataOverride: - ~~.items.0 - ~~.items.1 maybeRawAppRjBuild: renderView: - type: div attributes: style: padding: "1rem" border: "2px solid #ffc107" borderRadius: "8px" content: - type: h4 content: "Array Items Editor" - type: div content: - type: h5 content: "First Item" - type: TextField label: "Title" dataLocation: ~.0.title - type: CheckBoxField label: "Completed" dataLocation: ~.0.completed - type: div content: - type: h5 content: "Second Item" - type: TextField label: "Title" dataLocation: ~.1.title - type: CheckBoxField label: "Completed" dataLocation: ~.1.completed - type: Markdown content: | ## Caveat: Data Loss Risk with sharedUpdates **⚠️ Important Warning**: When using `sharedUpdates`, there is a risk of data loss in specific scenarios. ### The Problem If the subroot modifies data that is **not** covered by a template reference from the parent's `dataOverride`, and subsequently the parent re-renders the subroot, the local modifications will be **lost**. ### When This Happens 1. **Subroot modifies local data**: The subroot changes a value that doesn't correspond to any template reference in the parent's `dataOverride`. 2. **Parent re-renders**: This can occur when: - The parent updates itself for any reason. - A subroot action triggers an upstream update that causes the parent to re-render. 3. **Data loss**: The parent's `dataOverride` completely overwrites the subroot's data, erasing local modifications. ### Best Practices to Avoid Data Loss 1. **Map all needed data**: Ensure all data fields the subroot might modify are included in the parent's data structure. 2. **Use complete dataOverride**: Include all necessary data paths in your `dataOverride` mapping. 3. **Avoid local-only modifications**: Design your data flow so that all user inputs correspond to parent data. 4. **Consider alternatives**: For truly local data, consider using component state or separate data management instead of `sharedUpdates`. ## Limitations - **Data loss risk**: Local modifications in subroot may be lost when parent re-renders (see Caveat section above). - **Nested references in data**: References within references are not supported. - **Circular references**: May cause infinite loops if data structures reference each other. - **Isolation by default**: Without `sharedUpdates`, the subroot is completely isolated from the parent. - **Backward compatibility**: `sharedUpdates` is disabled by default to maintain existing behavior. - type: Markdown content: | ## Changelog ### reactive-json@0.1.0 - **New**: `sharedUpdates` feature - enables automatic data synchronization between subroot and parent - **New**: `dataOverride` property - allows complete data replacement in subroot with support for template references - **New**: Automatic analysis of template references in `dataOverride` for shared updates propagation