1*6dbdd20aSAndroid Build Coastguard Worker// Copyright (C) 2023 The Android Open Source Project 2*6dbdd20aSAndroid Build Coastguard Worker// 3*6dbdd20aSAndroid Build Coastguard Worker// Licensed under the Apache License, Version 2.0 (the "License"); 4*6dbdd20aSAndroid Build Coastguard Worker// you may not use this file except in compliance with the License. 5*6dbdd20aSAndroid Build Coastguard Worker// You may obtain a copy of the License at 6*6dbdd20aSAndroid Build Coastguard Worker// 7*6dbdd20aSAndroid Build Coastguard Worker// http://www.apache.org/licenses/LICENSE-2.0 8*6dbdd20aSAndroid Build Coastguard Worker// 9*6dbdd20aSAndroid Build Coastguard Worker// Unless required by applicable law or agreed to in writing, software 10*6dbdd20aSAndroid Build Coastguard Worker// distributed under the License is distributed on an "AS IS" BASIS, 11*6dbdd20aSAndroid Build Coastguard Worker// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*6dbdd20aSAndroid Build Coastguard Worker// See the License for the specific language governing permissions and 13*6dbdd20aSAndroid Build Coastguard Worker// limitations under the License. 14*6dbdd20aSAndroid Build Coastguard Worker 15*6dbdd20aSAndroid Build Coastguard Workerimport m from 'mithril'; 16*6dbdd20aSAndroid Build Coastguard Worker 17*6dbdd20aSAndroid Build Coastguard Worker// Check if a mithril component vnode has children 18*6dbdd20aSAndroid Build Coastguard Workerexport function hasChildren<T>({children}: m.Vnode<T>): boolean { 19*6dbdd20aSAndroid Build Coastguard Worker return ( 20*6dbdd20aSAndroid Build Coastguard Worker Array.isArray(children) && 21*6dbdd20aSAndroid Build Coastguard Worker children.length > 0 && 22*6dbdd20aSAndroid Build Coastguard Worker children.some((value) => value) 23*6dbdd20aSAndroid Build Coastguard Worker ); 24*6dbdd20aSAndroid Build Coastguard Worker} 25*6dbdd20aSAndroid Build Coastguard Worker 26*6dbdd20aSAndroid Build Coastguard Worker// A component which simply passes through it's children. 27*6dbdd20aSAndroid Build Coastguard Worker// Can be used for having something to attach lifecycle hooks to without having 28*6dbdd20aSAndroid Build Coastguard Worker// to add an extra HTML element to the DOM. 29*6dbdd20aSAndroid Build Coastguard Workerexport const Passthrough = { 30*6dbdd20aSAndroid Build Coastguard Worker view({children}: m.VnodeDOM) { 31*6dbdd20aSAndroid Build Coastguard Worker return children; 32*6dbdd20aSAndroid Build Coastguard Worker }, 33*6dbdd20aSAndroid Build Coastguard Worker}; 34*6dbdd20aSAndroid Build Coastguard Worker 35*6dbdd20aSAndroid Build Coastguard Workerexport interface GateAttrs { 36*6dbdd20aSAndroid Build Coastguard Worker open: boolean; 37*6dbdd20aSAndroid Build Coastguard Worker} 38*6dbdd20aSAndroid Build Coastguard Worker 39*6dbdd20aSAndroid Build Coastguard Worker// The gate component is a wrapper which can either be open or closed. 40*6dbdd20aSAndroid Build Coastguard Worker// - When open, children are rendered inside a div where display = contents. 41*6dbdd20aSAndroid Build Coastguard Worker// - When closed, children are rendered inside a div where display = none 42*6dbdd20aSAndroid Build Coastguard Worker// Use this component when we want to conditionally render certain children, 43*6dbdd20aSAndroid Build Coastguard Worker// but we want to maintain their state. 44*6dbdd20aSAndroid Build Coastguard Workerexport const Gate = { 45*6dbdd20aSAndroid Build Coastguard Worker view({attrs, children}: m.VnodeDOM<GateAttrs>) { 46*6dbdd20aSAndroid Build Coastguard Worker return m( 47*6dbdd20aSAndroid Build Coastguard Worker '', 48*6dbdd20aSAndroid Build Coastguard Worker { 49*6dbdd20aSAndroid Build Coastguard Worker style: {display: attrs.open ? 'contents' : 'none'}, 50*6dbdd20aSAndroid Build Coastguard Worker }, 51*6dbdd20aSAndroid Build Coastguard Worker children, 52*6dbdd20aSAndroid Build Coastguard Worker ); 53*6dbdd20aSAndroid Build Coastguard Worker }, 54*6dbdd20aSAndroid Build Coastguard Worker}; 55*6dbdd20aSAndroid Build Coastguard Worker 56*6dbdd20aSAndroid Build Coastguard Worker/** 57*6dbdd20aSAndroid Build Coastguard Worker * Utility function to pre-bind some mithril attrs of a component, and leave 58*6dbdd20aSAndroid Build Coastguard Worker * the others unbound and passed at run-time. 59*6dbdd20aSAndroid Build Coastguard Worker * Example use case: the Page API Passes to the registered page a PageAttrs, 60*6dbdd20aSAndroid Build Coastguard Worker * which is {subpage:string}. Imagine you write a MyPage component that takes 61*6dbdd20aSAndroid Build Coastguard Worker * some extra input attrs (e.g. the App object) and you want to bind them 62*6dbdd20aSAndroid Build Coastguard Worker * onActivate(). The results looks like this: 63*6dbdd20aSAndroid Build Coastguard Worker * 64*6dbdd20aSAndroid Build Coastguard Worker * interface MyPageAttrs extends PageAttrs { app: App; } 65*6dbdd20aSAndroid Build Coastguard Worker * 66*6dbdd20aSAndroid Build Coastguard Worker * class MyPage extends m.classComponent<MyPageAttrs> {... view() {...} } 67*6dbdd20aSAndroid Build Coastguard Worker * 68*6dbdd20aSAndroid Build Coastguard Worker * onActivate(app: App) { 69*6dbdd20aSAndroid Build Coastguard Worker * pages.register(... bindMithrilApps(MyPage, {app: app}); 70*6dbdd20aSAndroid Build Coastguard Worker * } 71*6dbdd20aSAndroid Build Coastguard Worker * 72*6dbdd20aSAndroid Build Coastguard Worker * The return value of bindMithrilApps is a mithril component that takes in 73*6dbdd20aSAndroid Build Coastguard Worker * input only a {subpage: string} and passes down to MyPage the combination 74*6dbdd20aSAndroid Build Coastguard Worker * of pre-bound and runtime attrs, that is {subpage, app}. 75*6dbdd20aSAndroid Build Coastguard Worker */ 76*6dbdd20aSAndroid Build Coastguard Workerexport function bindMithrilAttrs<BaseAttrs, Attrs>( 77*6dbdd20aSAndroid Build Coastguard Worker component: m.ComponentTypes<Attrs>, 78*6dbdd20aSAndroid Build Coastguard Worker boundArgs: Omit<Attrs, keyof BaseAttrs>, 79*6dbdd20aSAndroid Build Coastguard Worker): m.Component<BaseAttrs> { 80*6dbdd20aSAndroid Build Coastguard Worker return { 81*6dbdd20aSAndroid Build Coastguard Worker view(vnode: m.Vnode<BaseAttrs>) { 82*6dbdd20aSAndroid Build Coastguard Worker const attrs = {...vnode.attrs, ...boundArgs} as Attrs; 83*6dbdd20aSAndroid Build Coastguard Worker const emptyAttrs: m.CommonAttributes<Attrs, {}> = {}; // Keep tsc happy. 84*6dbdd20aSAndroid Build Coastguard Worker return m<Attrs, {}>(component, {...attrs, ...emptyAttrs}); 85*6dbdd20aSAndroid Build Coastguard Worker }, 86*6dbdd20aSAndroid Build Coastguard Worker }; 87*6dbdd20aSAndroid Build Coastguard Worker} 88