diff --git a/prop/prop.view.tree b/prop/prop.view.tree index 3d89e5d..3e338a9 100644 --- a/prop/prop.view.tree +++ b/prop/prop.view.tree @@ -29,6 +29,14 @@ $hyoo_studio_prop $mol_view hint @ \Changeable Icon <= Next_icon $mol_icon_atom_variant checked? <=> changeable? false + <= Styles $mol_check_icon + hint @ \Styles + Icon <= Styles_icon $mol_icon_language_css3 + checked? <=> styles_opened? false + <= Behavior $mol_check_icon + hint @ \Behavior + Icon <= Behavior_icon $mol_icon_language_javascript + checked? <=> behavior_opened? false content <= prop_content / <= Value $hyoo_studio_value hide_tools true diff --git a/prop/prop.view.ts b/prop/prop.view.ts index 2218114..2feac96 100644 --- a/prop/prop.view.ts +++ b/prop/prop.view.ts @@ -37,6 +37,39 @@ namespace $.$$ { return Boolean( sign_obj.next ) } + + @ $mol_mem + styles_opened( next?: boolean ) { + if (next !== undefined) { + this.$.$mol_state_arg.value('raw', next ? '' : null) + this.$.$mol_state_arg.value('raw_type', next ? 'Styles' : null) + this.$.$mol_state_arg.value('raw_prop', next ? this.name() : null) + } + + return this.$.$mol_state_arg.value('raw_prop') === this.name() && this.$.$mol_state_arg.value('raw') === '' && this.$.$mol_state_arg.value('raw_type') === 'styles' + } + + @ $mol_mem + behavior_opened( next?: boolean ) { + if (next !== undefined) { + this.$.$mol_state_arg.value('raw', next ? '' : null) + this.$.$mol_state_arg.value('raw_type', next ? 'Behavior' : null) + this.$.$mol_state_arg.value('raw_prop', next ? this.name() : null) + } + + return this.$.$mol_state_arg.value('raw_prop') === this.name() && this.$.$mol_state_arg.value('raw') === '' && this.$.$mol_state_arg.value('raw_type') === 'behavior' + } + + @ $mol_mem + prop_tools() { + return [ + this.Value_tools(), + ... this.Value().type() === 'object' ? [this.Styles()] : [], + this.Behavior(), + this.Key(), + this.Next(), + ] + } prop_content() { switch (this.Value().type()) { @@ -71,6 +104,7 @@ namespace $.$$ { } } + @ $mol_mem expanded(next?: boolean): boolean { diff --git a/studio.view.css.ts b/studio.view.css.ts index 5d1d999..e7493fb 100644 --- a/studio.view.css.ts +++ b/studio.view.css.ts @@ -52,6 +52,17 @@ namespace $.$$ { }, }, + Source_type: { + flex: { + grow: 1, + }, + Switch: { + flex: { + grow: 0, + }, + }, + }, + Source_page: { flex: { basis: rem( 40 ), @@ -61,6 +72,14 @@ namespace $.$$ { }, }, + Source_page_list: { + width: '100%', + }, + + Source_prop_name: { + padding: $mol_gap.block, + }, + Preview: { flex: { basis: rem( 40 ), diff --git a/studio.view.tree b/studio.view.tree index 155f3dd..7c9a8ac 100644 --- a/studio.view.tree +++ b/studio.view.tree @@ -81,10 +81,35 @@ $hyoo_studio $mol_book2 <= Source_page $mol_page title @ \Raw Code body / - <= Source $mol_textarea - hint \$hyoo_studio_example $mol_view - sidebar_showed true - value?val <=> source?val \$hyoo_studio_example $mol_view + <= Source_page_list $mol_list rows <= source_page_body / + <= Source_prop_switch $mol_view + sub / + <= Source_prop_name $mol_paragraph title <= source_prop_name \The property is editing: {prop_name} + <= Source_prop_exit $mol_button_minor + title @ \Show all + click? <=> source_prop_exit? null + <= Source_type $mol_deck + current? <=> soure_type_current? \0 + items / + <= Source $mol_textarea + title \Composition + hint \$hyoo_studio_example $mol_view + sidebar_showed true + value? <=> source_tree? \$hyoo_studio_example $mol_view + <= Source_css $mol_textarea + title \Styles + hint \ + sidebar_showed true + value? <=> source_css_switch? <=> source_css? \ + <= Source_js $mol_textarea + title \Behavior + hint \ + sidebar_showed true + value? <=> source_js_switch? <=> source_js? \ + \class {self} extends $.{self} { + \// Don't delete the first and last lines + \// Don't delete auto-generated comments + \} <= Preview $mol_frame title @ \Preview uri <= pack diff --git a/studio.view.ts b/studio.view.ts index 2bdbcdd..99a3300 100644 --- a/studio.view.ts +++ b/studio.view.ts @@ -36,8 +36,18 @@ namespace $.$$ { } @ $mol_mem - source( next?: string ): string { - return this.$.$mol_state_arg.value( 'source', next ) ?? super.source() + source_tree( next?: string ): string { + return this.$.$mol_state_arg.value( 'source', next ) ?? super.source_tree() + } + + @ $mol_mem + source_css( next?: string ): string { + return this.$.$mol_state_arg.value( 'source_css', next ) ?? '/* Don\'t delete auto-generated comments */\n' + } + + @ $mol_mem + source_js( next?: string ): string { + return this.$.$mol_state_arg.value( 'source_js', next ) ?? super.source_js() } @ $mol_mem @@ -56,7 +66,6 @@ namespace $.$$ { </body> </html> ` - } @ $mol_mem @@ -108,7 +117,7 @@ namespace $.$$ { @ $mol_mem tree( next?: $mol_tree2 ) { - const source = this.source( next && next.toString() ).replace( /\n?$/, '\n' ) + const source = this.source_tree( next && next.toString() ).replace( /\n?$/, '\n' ) const tree = this.$.$mol_view_tree2_normalize( this.$.$mol_tree2_from_string( source ) @@ -155,7 +164,7 @@ namespace $.$$ { return this.readme_selected( next ) } - + @ $mol_mem self_code() { @@ -172,6 +181,9 @@ namespace $.$$ { return ` $.$mol_wire_auto = parent.$mol_wire_auto $.${ this.self() } = ${ code } + $.${ this.self() } = ${this.source_js().replaceAll('{self}', this.self())} + ;${ this.source_js_decorators() }; + $.$mol_style_attach(${ this.self() }, \`${ this.source_css().replaceAll('{self}', this.self().slice(1)) }\`) ` } @@ -320,5 +332,107 @@ namespace $.$$ { return this.props_all().select( sign ).kids[0] ?? null } + + @ $mol_mem + soure_type_current( next?: string ) { + const options = Object.entries(this.Source_type().switch_options()) + if (next === undefined) { + const title = this.$.$mol_state_arg.value('raw_type') + const [value] = options.find(([value, label]) => label === title) ?? ['0'] + return value + } + + const next_title = options[Number(next)]?.[1] + this.$.$mol_state_arg.value('raw_type', next_title ?? options[0][1]) + return next + } + + @ $mol_mem_key + source_css_prop( prop_name: string, next?: string ) { + const tag = `/*${prop_name}*/` + const [before = '', prop_styles = '', after = ''] = this.source_css().split(tag) + + if (next === undefined) { + return prop_styles.trim() || `[{self}_${prop_name.toLowerCase()}] {\n\t\n}` + } + + const all = [before, tag, next.trim(), tag, after].join('\n').trim().replaceAll(/\n{2,}/g, '\n\n') + this.source_css(all) + return next.trim() + } + + @ $mol_mem + source_css_switch( next?: string ) { + const prop_name = this.$.$mol_state_arg.value('raw_prop') + + if (!prop_name) return this.source_css(next) + + return this.source_css_prop(prop_name, next) + } + + @ $mol_mem + source_js_decorators() { + const list = new Array<string>() + + const add = (prop_name: string, key: boolean, next: boolean) => { + if (!key && !next) return + if (this.source_js().includes(`/*${prop_name}*/`)) + list.push(`($mol_mem${key ? '_key' : ''}(($.${ this.self() }.prototype), "${ prop_name }"));`) + } + + this.props().forEach(prop => add(prop.name(), prop.multiple(), prop.changeable())) + + return list.join('\n') + } + + @ $mol_mem_key + source_js_prop( prop_name: string, next?: string ) { + console.log(11111111) + console.log(this.source_js_decorators()) + const lines = this.source_js().split('\n') + const class_begin = lines.shift() + const class_end = lines.pop() + + const tag = `/*${prop_name}*/` + const [before = '', prop_js = '', after = ''] = lines.join('\n').split(tag) + + const multiple = this.Prop(prop_name).multiple() + const changeable = this.Prop(prop_name).changeable() + const params = [...multiple ? ['key'] : [], ...changeable ? ['next'] : []].join(', ') + if (next === undefined) { + return prop_js.trim().replace(new RegExp(`${prop_name}\\s*\\(.*\\)`), `${prop_name} (${params})`) || `${prop_name} (${params}) {\n\t\n}` + } + + const all = [class_begin, before, tag, next.trim(), tag, after, class_end].join('\n').trim().replaceAll(/\n{2,}/g, '\n\n') + this.source_js(all) + return next.trim() + } + + @ $mol_mem + source_js_switch( next?: string ) { + const prop_name = this.$.$mol_state_arg.value('raw_prop') + + if (!prop_name) return this.source_js(next) + + return this.source_js_prop(prop_name, next) + } + + source_prop_name() { + return super.source_prop_name().replaceAll('{prop_name}', this.$.$mol_state_arg.value('raw_prop')!) + } + + @ $mol_action + source_prop_exit() { + this.$.$mol_state_arg.value('raw_prop', null) + } + + @ $mol_mem + source_page_body() { + const show = this.$.$mol_state_arg.value('raw_prop') !== null && this.$.$mol_state_arg.value('raw_type') !== 'view.tree' + return [ + ... show ? [this.Source_prop_switch()] : [], + this.Source_type(), + ] + } } }