import { WCSuiteInfo, WCInfo, PropertyInfo, CustomEventInfo, SlotInfo, AttribInfo } from "wc-info/types.js";
import { more } from 'trans-render/transform.js';
import { templStampSym} from 'trans-render/standardPlugins.js';
import { createTemplate} from "trans-render/createTemplate.js";
import {
XtalFetchViewElement, define, mergeProps, AttributeProps, p, symbolize, RenderContext, PESettings, TransformValueOptions,
SelectiveUpdate
} from "xtal-element/XtalFetchViewElement.js";
import {PD} from "p-et-alia/p-d.js";
import { SwagTagPrimitiveBase } from './swag-tag-primitive-base.js';
//import { SwagTagObjectBase } from './lib/swag-tag-object-base.js';
import { JsonEventViewer } from './json-event-viewer.js';
import { SwagTagJsonEditor } from "./swag-tag-json-editor.js";
import { conditionalImport } from 'xtal-sip/conditionalImport.js';
//#region Templates
//Very little top level styling used, so consumers can take the first crack at styling.
//So make what little styling there is guaranteed to not affect anything else via guid.
const mainTemplate = createTemplate(/* html */ `
View Schema
`);
const eventListenerForJsonViewer = createTemplate(/* html */`
`);
//#endregion
//#region Transforms
export const uiRefs = {
componentName: p, header: p, componentHolder: p, componentListeners: p, jsonViewer: p,
fieldset: p, scrollableArea: p, legend: p
};
symbolize(uiRefs);
const initTransform = ({self, tag}: SwagTag) => ({
':host': [templStampSym, uiRefs],
[uiRefs.legend]: [{},{click: self.toggleForm}] as PESettings,
main:{
'[-care-of]': tag,
}
} as TransformValueOptions);
export const bindName = ({name, innerTemplate}: SwagTag) => ({
[uiRefs.header]: `<${name}>`,
[uiRefs.componentName]: name,
[uiRefs.componentHolder]: [name, 'afterBegin'],
[more]:{
[uiRefs.componentHolder]: {
[name!]: ({target}: RenderContext) => {
if(innerTemplate !== undefined){
target!.appendChild(innerTemplate!.content.cloneNode(true));
}
}
}
}
});
export const addEventListeners = ({events, name}: SwagTag) => ({
[uiRefs.componentListeners]: [events || [], eventListenerForJsonViewer,,{
[PD.is]:({item}: RenderContext) => [{observe: name, on: item.name}]
}]
});
export const copyPropInfoIntoEditor = ({item, target}: RenderContext) => {
Object.assign(target, item);
target!.setAttribute('role', 'textbox');
};
const copyPropInfoIntoEditors = {
[`${SwagTagPrimitiveBase.is},${SwagTagJsonEditor.is}`]: copyPropInfoIntoEditor,
}
export const addEditors = ({massagedProps, name}: SwagTag) => ({
// Loop over massagedProps, and insert dynamic editor via tag name (item.editor is the tag name)
[uiRefs.scrollableArea]: [
//Array to loop over
massagedProps || [],
//A **toTagOrTemplate** function that returns a string -- used to generate a (custom element) with the name of the string.
({item}: RenderContext) => (item).editor,
//range could go here
,
//now that document.createElement(tag) done, apply transform
copyPropInfoIntoEditors]
});
export const bindSelf = ({attribs, self}: SwagTag) => ({
[uiRefs.jsonViewer]: [{object: self}]
});
const updateTransforms = [
bindName,
addEventListeners,
addEditors,
bindSelf
] as SelectiveUpdate[];
//#endregion
//#region propActions
export const linkWcInfo = ({viewModel, tag, self} : SwagTag) => {
if(tag === undefined || viewModel === undefined) return;
conditionalImport(self, {
'json-viewer':[
[
'@power-elements/json-viewer/json-viewer.js',
() => import('@power-elements/json-viewer/json-viewer.js'),
({path}) => `//unpkg.com/${path}?module`,,
]
],
});
const wcInfo = viewModel.tags.find(t => t.name === tag)!;
wcInfo.attribs = (wcInfo).attributes;
delete (wcInfo).attributes;
Object.assign(self, wcInfo);
}
export function adjustValueAndType(prop: PropertyInfo){
let defaultVal = (prop).default;
let parsedType = undefined;
if(defaultVal !== undefined){
try{
defaultVal = JSON.parse(defaultVal);
parsedType = JSON.parse('[' + prop.type!.replace(/\|/g, ',') + ']');
}catch(e){}
if(Array.isArray(parsedType)){
prop.value = defaultVal;
prop.type = 'stringArray';
prop.options = parsedType;
return;
}
switch(typeof defaultVal){
case 'object':
prop.value = (prop).default;
prop.type = 'object'
break;
case 'string':
prop.value = defaultVal;
prop.type = 'string';
break;
case 'number':
prop.value = defaultVal;
prop.type = 'number';
break;
case 'boolean':
prop.value = defaultVal;
prop.type = 'boolean';
break;
default:
prop.value = (prop).default;
prop.type = 'object';
}
}else{
switch(prop.type){
case 'string':
case 'boolean':
case 'number':
break;
default:
prop.type = 'object';
}
}
}
const massaged = Symbol();
export const linkMassagedProps = ({properties, self, block}: SwagTag) => {
if(properties === undefined || (properties)[massaged as any as string]) return;
properties.forEach(prop =>{
adjustValueAndType(prop);
const anyProp = prop;
switch(prop.type){
case 'string':
case 'number':
case 'boolean':
anyProp.editor = SwagTagPrimitiveBase.is;
break;
case 'object':
anyProp.editor = SwagTagJsonEditor.is;
break;
default:
throw 'not implemented';
}
});
(properties)[massaged as any as string] = true;
self.massagedProps = block !== undefined ? properties.filter(prop => !block.includes(prop.name!)) : properties;
}
export const linkInnerTemplate = ({useInnerTemplate, self}: SwagTag) =>{
if(!useInnerTemplate) return;
const innerTemplate = self.querySelector('template');
if(innerTemplate === null){
setTimeout(() =>{
linkInnerTemplate(self);
}, 50);
return;
}
self.innerTemplate = innerTemplate;
}
export const triggerImportReferencedModule = ({path, self, skipImports}: SwagTag) => {
if(path !== undefined && !skipImports){
if(self.href!.indexOf('//') > -1 && self.href!.indexOf('//') < 7){
const selfResolvingModuleSplitPath = self.href!.split('/');
selfResolvingModuleSplitPath.pop();
const selfResolvingModulePath = selfResolvingModuleSplitPath.join('/') + self.path!.substring(1) + '?module';
import(selfResolvingModulePath);
}else{
const splitPath = (location.origin + location.pathname).split('/');
splitPath.pop();
let path = self.path!;
while(path.startsWith('../')){
splitPath.pop();
path = path.substr(3);
}
const importPath = splitPath.join('/') + '/' + path;
import(importPath);
}
}
}
export const showHideEditor = ({editOpen, self}: SwagTag) => {
(self)[uiRefs.fieldset].dataset.open = (editOpen || false).toString();
}
const propActions = [
linkWcInfo, linkMassagedProps, triggerImportReferencedModule, showHideEditor, linkInnerTemplate
];
//#endregion
/**
* @csspart header
* @csspart section
* @csspart componentHolder
* @csspart componentListeners
* @csspart jsonEventViewer
* @csspart propsEditor
* @csspart fieldset
* @csspart action
* @csspart componentName
* @csspart scrollableArea
* @csspart viewSchema
* @csspart jsonViewer
*/
export class SwagTag extends XtalFetchViewElement implements WCInfo {
static is = "swag-tag";
/**
* @private
*/
noShadow = true;
mainTemplate = mainTemplate;
readyToRender = true;
static attributeProps: any = ({tag, name, properties, path, events, slots, testCaseNames, attribs, editOpen, block, useInnerTemplate, innerTemplate, skipImports} : SwagTag) =>{
const ap = {
str: [tag, name, path],
bool: [editOpen, useInnerTemplate, skipImports],
obj: [properties, events, slots, testCaseNames, attribs, block, innerTemplate],
jsonProp: [block],
reflect: [tag, editOpen]
} as AttributeProps;
return mergeProps(ap, (XtalFetchViewElement).props);
}
propActions = [
linkWcInfo, linkMassagedProps, triggerImportReferencedModule, showHideEditor, linkInnerTemplate
];
initTransform = initTransform;
updateTransforms = updateTransforms;
tag: string | undefined;
name: string | undefined;
block: string[] | undefined;
description: string | undefined;
properties: PropertyInfo[] | undefined;
massagedProps: PropertyInfo[] | undefined;
path: string | undefined;
events: CustomEventInfo[] | undefined;
slots: SlotInfo[] | undefined;
attribs: AttribInfo[] | undefined;
testCaseNames: string[] | undefined;
editOpen: boolean | undefined;
useInnerTemplate: boolean | undefined;
innerTemplate: HTMLTemplateElement | undefined;
/**
* If test page contains needed imports, skip any imports contained in test script.
* @attr skip-imports
*/
skipImports = false;
toggleForm(e: Event){
this.editOpen = !this.editOpen;
}
}
define(SwagTag);