// see JSPanel.de sclass JSPanel { LS moreHeadStuff; sclass HeaderControls { Map add; S smallify; // e.g. "remove" Map asMap() { ret mapValues_withoutNulls nullIfEmpty_gen(litorderedmap( +add, +smallify )); } } sclass Options { S headerTitle = null; new LS contents; // HTML content S theme; // e.g. "info" S overflow; // e.g. "hidden" S border; // e.g. "thick dashed orange" HeaderControls headerControls; Map asMap() { ret mapValues_withoutNulls nullIfEmpty_gen(litorderedmap( +headerTitle, content := lines_rtrim(contents), +theme, +overflow, +border, headerControls := headerControls?.asMap() )); } HeaderControls headerControls() { ret headerControls == null ? (headerControls = new HeaderControls) : headerControls; } } Options newOptions() { ret new Options; } // expression to create this panel JS createPanel(Options options default null) { ret JS("jsPanel.create($options)", options := or(options, newOptions()).asMap()); } S headStuff() { ret nemptyLines_flattenLists( hlink("https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel.css"), hlink("https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel.js"), moreHeadStuff); } ifdef guggida /* */ endifdef }