diff --git a/packages/devtools-backend/src/index.ts b/packages/devtools-backend/src/index.ts index 18d0247..768e5a5 100644 --- a/packages/devtools-backend/src/index.ts +++ b/packages/devtools-backend/src/index.ts @@ -9,3 +9,4 @@ export * from './serialize'; export * from './search'; export * from './ui'; +export * from './interface'; diff --git a/packages/devtools-backend/src/interface/component.ts b/packages/devtools-backend/src/interface/component.ts new file mode 100644 index 0000000..ae33a19 --- /dev/null +++ b/packages/devtools-backend/src/interface/component.ts @@ -0,0 +1,23 @@ +/*! + * V4Fire DevTools + * https://github.com/V4Fire/DevTools + * + * Released under the MIT license + * https://github.com/V4Fire/DevTools/blob/main/LICENSE + */ + +/** + * Parameters to search for a component + */ +export interface ComponentQuery { + /** + * The unique component identifier. + * The value is formed based on the passed prop or dynamically. + */ + readonly componentId: string; + + /** + * The component name in dash-style without special postfixes like `-functional` + */ + readonly componentName?: string; +} diff --git a/packages/devtools-backend/src/interface/index.ts b/packages/devtools-backend/src/interface/index.ts new file mode 100644 index 0000000..2b172cf --- /dev/null +++ b/packages/devtools-backend/src/interface/index.ts @@ -0,0 +1,9 @@ +/*! + * V4Fire DevTools + * https://github.com/V4Fire/DevTools + * + * Released under the MIT license + * https://github.com/V4Fire/DevTools/blob/main/LICENSE + */ + +export * from './component'; diff --git a/packages/devtools-backend/src/search/find-component-node.ts b/packages/devtools-backend/src/search/find-component-node.ts index a9b2fc4..6cbb44f 100644 --- a/packages/devtools-backend/src/search/find-component-node.ts +++ b/packages/devtools-backend/src/search/find-component-node.ts @@ -6,13 +6,15 @@ * https://github.com/V4Fire/DevTools/blob/main/LICENSE */ +import type { ComponentQuery } from '../interface'; + /** * Find component DOM node * - * @param id - component id - * @param name - component name + * @param query - component query */ -export default function findComponentNode(id: string, name?: string): T | null { +export default function findComponentNode(query: ComponentQuery): T | null { + const {componentId: id, componentName: name} = query; let node = Array.prototype.find.call( document.querySelectorAll(`.i-block-helper.${id}`), (node) => node.component?.componentId === id diff --git a/packages/devtools-backend/src/ui/component-highlight.ts b/packages/devtools-backend/src/ui/component-highlight.ts index 039ac7e..6f3b935 100644 --- a/packages/devtools-backend/src/ui/component-highlight.ts +++ b/packages/devtools-backend/src/ui/component-highlight.ts @@ -6,6 +6,7 @@ * https://github.com/V4Fire/DevTools/blob/main/LICENSE */ +import type { ComponentQuery } from '../interface'; import findComponentNode from '../search/find-component-node'; interface HideOptions { @@ -26,11 +27,10 @@ class ComponentHighlight { /** * Show highlight for the component * - * @param componentId - * @param componentName + * @param query */ - show(componentId: string, componentName: string): void { - const node = findComponentNode(componentId, componentName); + show(query: ComponentQuery): void { + const node = findComponentNode(query); if (node == null) { return; diff --git a/packages/devtools-backend/src/ui/component-locate.ts b/packages/devtools-backend/src/ui/component-locate.ts index 21d4ed2..4e0f6e4 100644 --- a/packages/devtools-backend/src/ui/component-locate.ts +++ b/packages/devtools-backend/src/ui/component-locate.ts @@ -27,8 +27,7 @@ class ComponentLocate { component = e.target instanceof Element ? findComponent(e.target) : null; if (component != null) { - const {componentId, componentName} = component; - componentHighlight.show(componentId, componentName); + componentHighlight.show(component); } else { componentHighlight.hide(); diff --git a/packages/devtools-core/components-lock.json b/packages/devtools-core/components-lock.json index 4024f68..45ff562 100644 --- a/packages/devtools-core/components-lock.json +++ b/packages/devtools-core/components-lock.json @@ -1,5 +1,5 @@ { - "hash": "3a340c935c646da7e210253371ed8f9eaceabbefb4db0a3a4ac1f84a6b251ac2", + "hash": "b1f092ba867cc6f75520d31a06c0b387336890ccc7bbe045022f86c3856f3fa9", "data": { "%data": "%data:Map", "%data:Map": [ @@ -198,25 +198,41 @@ "declaration": { "name": "b-components-panel-item", "parent": "i-block", - "dependencies": [], - "libs": [] + "dependencies": [ + "b-dropdown", + "b-button" + ], + "libs": [ + "components/directives/icon" + ] }, "name": "b-components-panel-item", "parent": "i-block", - "dependencies": [], - "libs": [], + "dependencies": [ + "b-dropdown", + "b-button" + ], + "libs": [ + "components/directives/icon" + ], "resolvedLibs": { "%data": "%data:Set", - "%data:Set": [] + "%data:Set": [ + "components/directives/icon" + ] }, "resolvedOwnLibs": { "%data": "%data:Set", - "%data:Set": [] + "%data:Set": [ + "components/directives/icon" + ] }, "type": "block", "mixin": false, "logic": "src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ts", - "styles": [], + "styles": [ + "src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.styl" + ], "tpl": "src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ss", "etpl": null } @@ -333,6 +349,40 @@ "etpl": null } ], + [ + "b-dropdown", + { + "index": "src/components/form/b-dropdown/index.js", + "declaration": { + "name": "b-dropdown", + "parent": "b-select", + "dependencies": [], + "libs": [] + }, + "name": "b-dropdown", + "parent": "b-select", + "dependencies": [], + "libs": [], + "resolvedLibs": { + "%data": "%data:Set", + "%data:Set": [ + "components/directives/icon" + ] + }, + "resolvedOwnLibs": { + "%data": "%data:Set", + "%data:Set": [] + }, + "type": "block", + "mixin": false, + "logic": "src/components/form/b-dropdown/b-dropdown.ts", + "styles": [ + "src/components/form/b-dropdown/b-dropdown.styl" + ], + "tpl": "src/components/form/b-dropdown/b-dropdown.ss", + "etpl": null + } + ], [ "b-dummy", { diff --git a/packages/devtools-core/src/assets/svg/caret-down.svg b/packages/devtools-core/src/assets/svg/caret-down.svg new file mode 100644 index 0000000..edd826d --- /dev/null +++ b/packages/devtools-core/src/assets/svg/caret-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/devtools-core/src/assets/svg/warning.svg b/packages/devtools-core/src/assets/svg/warning.svg new file mode 100644 index 0000000..d11bd1b --- /dev/null +++ b/packages/devtools-core/src/assets/svg/warning.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/devtools-core/src/components/form/b-dropdown/b-dropdown.ss b/packages/devtools-core/src/components/form/b-dropdown/b-dropdown.ss new file mode 100644 index 0000000..ba6aa8a --- /dev/null +++ b/packages/devtools-core/src/components/form/b-dropdown/b-dropdown.ss @@ -0,0 +1,16 @@ +- namespace [%fileName%] + +- include 'components/form/b-select'|b as placeholder + +- template index() extends ['b-select'].index + - block nativeInput() + < .&__value + {{ value }} + + - block body + < button.&__trigger & + @click = toggle | + @focus = onFocus | + @blur = onBlur + . + - super diff --git a/packages/devtools-core/src/components/form/b-dropdown/b-dropdown.styl b/packages/devtools-core/src/components/form/b-dropdown/b-dropdown.styl new file mode 100644 index 0000000..88e1d02 --- /dev/null +++ b/packages/devtools-core/src/components/form/b-dropdown/b-dropdown.styl @@ -0,0 +1,29 @@ +@import "@super/components/form/b-select/b-select.styl" + +b-dropdown extends b-select + &__dropdown + absolute left 0 top 100% + overflow-x hidden + border 1px solid black + background-color white + + &__value + margin-right 4px + + &__trigger + border none + + &__wrapper + cursor inherit + + &__icon + height 1em + font-size 0.875rem + transition transform 0.15s + + &_opened_true ^[0]__icon + transform rotate(-180deg) + + &__item_selected_true + &__item_marked_true + background-color rgba(100, 100, 100, 0.1) diff --git a/packages/devtools-core/src/components/form/b-dropdown/b-dropdown.ts b/packages/devtools-core/src/components/form/b-dropdown/b-dropdown.ts new file mode 100644 index 0000000..b171654 --- /dev/null +++ b/packages/devtools-core/src/components/form/b-dropdown/b-dropdown.ts @@ -0,0 +1,34 @@ +/*! + * V4Fire DevTools + * https://github.com/V4Fire/DevTools + * + * Released under the MIT license + * https://github.com/V4Fire/DevTools/blob/main/LICENSE + */ + +import bSelect, { component, field } from 'components/form/b-select/b-select'; +import iActiveItems from 'components/traits/i-active-items/i-active-items'; + +export * from 'components/form/b-select/b-select'; + +@component({functional: false}) +export default class bDropdown extends bSelect { + override readonly icon: string = 'caret-down'; + + @field({ + unique: true, + init: (o) => { + o.watch('valueProp', (val) => o.setActive(val, true)); + o.watch('modelValue', (val) => o.setActive(val, true)); + return iActiveItems.linkActiveStore(o, (val) => o.resolveValue(o.valueProp ?? o.modelValue ?? val)); + } + }) + override activeStore!: iActiveItems['activeStore']; + + /** + * Overriding the `onFocus` because dropdown shouldn't be opened on focus + */ + protected override onFocus(): void { + this.setMod('focused', 'true'); + } +} diff --git a/packages/devtools-core/src/components/form/b-dropdown/index.js b/packages/devtools-core/src/components/form/b-dropdown/index.js new file mode 100644 index 0000000..fb74b3e --- /dev/null +++ b/packages/devtools-core/src/components/form/b-dropdown/index.js @@ -0,0 +1,12 @@ +/*! + * V4Fire DevTools + * https://github.com/V4Fire/DevTools + * + * Released under the MIT license + * https://github.com/V4Fire/DevTools/blob/main/LICENSE + */ + +'use strict'; + +package('b-dropdown') + .extends('b-select'); diff --git a/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.ss b/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.ss index 988f431..b0d7778 100644 --- a/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.ss +++ b/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.ss @@ -29,5 +29,6 @@ :items = items | :item = 'b-components-panel-item' | :theme = 'pretty' | - :cancelable = true + :cancelable = true | + :itemProps = getPanelItemProps . diff --git a/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.styl b/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.styl index 5ccd219..e050fe5 100644 --- a/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.styl +++ b/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.styl @@ -14,6 +14,7 @@ b-components-panel extends i-block line-height 1 &__body + flex-grow 1 overflow auto padding 4px 0 word-break break-word diff --git a/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.ts b/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.ts index 063da52..98f4dae 100644 --- a/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.ts +++ b/packages/devtools-core/src/features/components/b-components-panel/b-components-panel.ts @@ -12,6 +12,7 @@ import type bTree from 'components/base/b-tree/b-tree'; import type { Item, ComponentData } from 'features/components/b-components-panel/interface'; import { createItems } from 'features/components/b-components-panel/modules/helpers'; +import type bDropdown from 'components/form/b-dropdown/b-dropdown'; export * from 'features/components/b-components-panel/interface'; @@ -65,6 +66,42 @@ export default class bComponentsPanel extends iBlock { } } + /** + * Returns formatted props for panel item + * @param item + */ + protected getPanelItemProps(item: Item): Dictionary { + if (item.allowedValues != null) { + return { + ...item, + + select: { + items: item.allowedValues.map((value) => ({label: value, value})), + + '@actionChange': (_ctx: bDropdown, value: unknown): void => { + if (item.label == null) { + return; + } + + this.onItemChangeMod(item.label, value); + } + } + }; + } + + return item; + } + + /** + * Change selected component mod + * + * @param _key + * @param _value + */ + protected onItemChangeMod(_key: string, _value: unknown): void { + // TODO: use inspected app + } + /** * Update show empty */ diff --git a/packages/devtools-core/src/features/components/b-components-panel/interface.ts b/packages/devtools-core/src/features/components/b-components-panel/interface.ts index b85939f..2f2e1ef 100644 --- a/packages/devtools-core/src/features/components/b-components-panel/interface.ts +++ b/packages/devtools-core/src/features/components/b-components-panel/interface.ts @@ -8,12 +8,21 @@ import type { Item as Super, ComponentMeta } from 'components/base/b-tree/b-tree'; +export interface ItemOption { + label: string; + value: unknown; +} + export interface Item extends Super { data?: unknown; path?: string; children?: Item[]; + + allowedValues?: string[]; + + warning?: string; } export type ComponentData = { @@ -33,6 +42,6 @@ export type ComponentData = { hierarchy: string[]; } & Pick< - ComponentMeta, 'componentName' | 'props' | 'fields' | 'computedFields' | 'systemFields' + ComponentMeta, 'componentName' | 'props' | 'fields' | 'computedFields' | 'systemFields' | 'mods' >; diff --git a/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ss b/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ss index 5d45c53..30d607b 100644 --- a/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ss +++ b/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ss @@ -4,9 +4,27 @@ - template index() extends ['i-block'].index - block body - {{ label }}{{ data != null ? ': ' : null }} + < .&__label + {{ label }} - < template v-if = data != null + < span v-if = data != null || Object.size(field.get('select.items')) > 0 + \: + + < span.&__warning-icon & + v-if = warning != null | + :-hint = warning | + :class = provide.hintClasses('bottom-right') + . + < .g-icon v-icon:warning + + < b-dropdown.&__value & + v-if = Object.size(field.get('select.items')) > 0 | + :v-attrs = select | + :cancellable = false | + :value = data + . + + < span.&__value v-else-if = data != null < template v-if = isFunction(data) < b-button @click = () => showFunction(data) Function diff --git a/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.styl b/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.styl new file mode 100644 index 0000000..b152c6f --- /dev/null +++ b/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.styl @@ -0,0 +1,12 @@ +@import "components/super/i-block/i-block.styl" + +b-components-panel-item extends i-block + display flex + word-break normal + + &__label + display flex + + &__warning-icon + &__value + margin-left 4px diff --git a/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ts b/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ts index 4062ad8..97293ee 100644 --- a/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ts +++ b/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ts @@ -7,6 +7,9 @@ */ import iBlock, { component, prop } from 'components/super/i-block/i-block'; +import type { PanelItemSelect } from 'features/components/b-components-panel/modules/b-components-panel-item/interface'; + +export * from 'features/components/b-components-panel/modules/b-components-panel-item/interface'; @component() export default class bComponentsPanelItem extends iBlock { @@ -16,6 +19,12 @@ export default class bComponentsPanelItem extends iBlock { @prop() data: unknown; + @prop({type: Array}) + select?: PanelItemSelect; + + @prop({type: String}) + warning?: string; + isFunction(data: unknown): boolean { return String(data) === 'Function' && Object.hasOwnProperty.call(data, 'declaration'); } diff --git a/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/index.js b/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/index.js index 347041d..0abb628 100644 --- a/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/index.js +++ b/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/index.js @@ -9,4 +9,6 @@ 'use strict'; package('b-components-panel-item') - .extends('i-block'); + .extends('i-block') + .dependencies('b-dropdown', 'b-button') + .libs('components/directives/icon'); diff --git a/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/interface.ts b/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/interface.ts new file mode 100644 index 0000000..c6da694 --- /dev/null +++ b/packages/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/interface.ts @@ -0,0 +1,13 @@ +/*! + * V4Fire DevTools + * https://github.com/V4Fire/DevTools + * + * Released under the MIT license + * https://github.com/V4Fire/DevTools/blob/main/LICENSE + */ + +import type bDropdown from 'components/form/b-dropdown/b-dropdown'; + +export interface PanelItemSelect extends Dictionary { + items: bDropdown['items']; +} diff --git a/packages/devtools-core/src/features/components/b-components-panel/modules/helpers.ts b/packages/devtools-core/src/features/components/b-components-panel/modules/helpers.ts index ac321de..8e52688 100644 --- a/packages/devtools-core/src/features/components/b-components-panel/modules/helpers.ts +++ b/packages/devtools-core/src/features/components/b-components-panel/modules/helpers.ts @@ -8,10 +8,66 @@ import { getType } from '@v4fire/devtools-backend'; -import { normalizeComponentName } from 'core/helpers'; +import { NBSP, normalizeComponentName } from 'core/helpers'; import type { Item, ComponentData } from 'features/components/b-components-panel/interface'; +interface PanelItem { + name: string; + getData(data: ComponentData, key: string): {value: unknown; allowedValues?: Item['allowedValues']; warning?: Item['warning']}; + getDict(data: ComponentData): ComponentData[keyof ComponentData]; +} + +/** + * The panel items that should display for the selected component + */ +const panelItems: PanelItem[] = [ + { + name: 'props', + getData: (data, key) => ({value: data.values[key]}), + getDict: (data) => data.props + }, + { + name: 'fields', + getData: (data, key) => ({value: data.values[key]}), + getDict: (data) => data.fields + }, + { + name: 'computedFields', + getData: (data, key) => ({value: data.values[key]}), + getDict: (data) => data.computedFields + }, + { + name: 'mods', + getData: (data, key) => { + let value = Object.isDictionary(data.values.mods) ? data.values.mods[key] : undefined; + + if (key in data.mods && Array.isArray(data.mods[key])) { + const allowedValues = data.mods[key]!.map((decl) => { + let declFormatted = String(decl); + + if (Array.isArray(decl)) { + declFormatted = String(decl[0]); + value ??= declFormatted; + } + + return declFormatted; + }); + + return {value, allowedValues}; + } + + return {value, warning: `Undeclared${NBSP}modifier`}; + }, + getDict: (data) => Object.mixin({}, {}, data.values.mods, data.mods) + }, + { + name: 'systemFields', + getData: (data, key) => ({value: data.values[key]}), + getDict: (data) => data.systemFields + } +]; + /** * Creates items from component data * @param data @@ -23,13 +79,12 @@ export function createItems(data: ComponentData): Item[] { [block, ...rest] = data.componentName.split('-'), selfRegex = new RegExp(`^(i|${block})-${rest.join('-')}-?`); - ['props', 'fields', 'computedFields', 'systemFields'].forEach((name) => { - const dict = data[name]; + panelItems.forEach(({name, getData, getDict}) => { + const dict = getDict(data); const map = new Map(); const children: Item[] = []; Object.keys(dict).forEach((key) => { - if (key.startsWith('$')) { return; } @@ -40,12 +95,15 @@ export function createItems(data: ComponentData): Item[] { // Match intermediate classes isSelf = src == null || src.match(selfRegex) != null; - const [value, valueChildren] = prepareValue(data.values[key], key); + const {value: valueByKey, allowedValues, warning} = getData(data, key); + const [value, valueChildren] = prepareValue(valueByKey, key); const item: Item = { label: key, data: value, - children: valueChildren + children: valueChildren, + allowedValues, + warning }; if (isSelf) { @@ -63,15 +121,15 @@ export function createItems(data: ComponentData): Item[] { }); data.hierarchy.forEach((parent) => { - const items = map.get(parent); + const childItems = map.get(parent); map.delete(parent); - if (items != null) { + if (childItems != null) { children.push({ label: parent.camelize(false), folded: true, - children: items + children: childItems }); } }); diff --git a/packages/devtools-extension/components-lock.json b/packages/devtools-extension/components-lock.json index 0b65844..ff21c92 100644 --- a/packages/devtools-extension/components-lock.json +++ b/packages/devtools-extension/components-lock.json @@ -1,5 +1,5 @@ { - "hash": "86d3b4dc248c2675c64578b462b3519e5ad9fedfa6b2d047d8a61eb9df11351f", + "hash": "63d5c3bbc40479cff0829239c37b43c0a2a5a98e14bf6983e5d3a703cf1515e1", "data": { "%data": "%data:Map", "%data:Map": [ @@ -198,25 +198,41 @@ "declaration": { "name": "b-components-panel-item", "parent": "i-block", - "dependencies": [], - "libs": [] + "dependencies": [ + "b-dropdown", + "b-button" + ], + "libs": [ + "components/directives/icon" + ] }, "name": "b-components-panel-item", "parent": "i-block", - "dependencies": [], - "libs": [], + "dependencies": [ + "b-dropdown", + "b-button" + ], + "libs": [ + "components/directives/icon" + ], "resolvedLibs": { "%data": "%data:Set", - "%data:Set": [] + "%data:Set": [ + "components/directives/icon" + ] }, "resolvedOwnLibs": { "%data": "%data:Set", - "%data:Set": [] + "%data:Set": [ + "components/directives/icon" + ] }, "type": "block", "mixin": false, "logic": "node_modules/@v4fire/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ts", - "styles": [], + "styles": [ + "node_modules/@v4fire/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.styl" + ], "tpl": "node_modules/@v4fire/devtools-core/src/features/components/b-components-panel/modules/b-components-panel-item/b-components-panel-item.ss", "etpl": null } @@ -333,6 +349,40 @@ "etpl": null } ], + [ + "b-dropdown", + { + "index": "node_modules/@v4fire/devtools-core/src/components/form/b-dropdown/index.js", + "declaration": { + "name": "b-dropdown", + "parent": "b-select", + "dependencies": [], + "libs": [] + }, + "name": "b-dropdown", + "parent": "b-select", + "dependencies": [], + "libs": [], + "resolvedLibs": { + "%data": "%data:Set", + "%data:Set": [ + "components/directives/icon" + ] + }, + "resolvedOwnLibs": { + "%data": "%data:Set", + "%data:Set": [] + }, + "type": "block", + "mixin": false, + "logic": "node_modules/@v4fire/devtools-core/src/components/form/b-dropdown/b-dropdown.ts", + "styles": [ + "node_modules/@v4fire/devtools-core/src/components/form/b-dropdown/b-dropdown.styl" + ], + "tpl": "node_modules/@v4fire/devtools-core/src/components/form/b-dropdown/b-dropdown.ss", + "etpl": null + } + ], [ "b-dummy", { diff --git a/packages/devtools-extension/src/features/components/b-components-panel/b-components-panel.ts b/packages/devtools-extension/src/features/components/b-components-panel/b-components-panel.ts index f3b0421..d65c45a 100644 --- a/packages/devtools-extension/src/features/components/b-components-panel/b-components-panel.ts +++ b/packages/devtools-extension/src/features/components/b-components-panel/b-components-panel.ts @@ -5,23 +5,35 @@ * Released under the MIT license * https://github.com/V4Fire/DevTools/blob/main/LICENSE */ + +import type { ComponentQuery } from '@v4fire/devtools-backend'; + import { devtoolsEval } from 'core/browser-api'; -import { component } from 'components/super/i-block/i-block'; +import iBlock, { component, ComponentElement } from 'components/super/i-block/i-block'; import Super from '@super/features/components/b-components-panel/b-components-panel'; +export * from 'features/components/b-components-panel/interface'; + @component() export default class bComponentsPanel extends Super { + protected override onItemChangeMod(key: string, value: unknown): void { + const {componentId, componentName} = this.componentData; + + devtoolsEval(evalSetComponentMod, [key, value, {componentId, componentName}]) + .catch(stderr); + } + protected override onInspect(): void { const {componentId, componentName} = this.componentData; - devtoolsEval(evalInspect, [componentId, componentName]) + devtoolsEval(evalInspect, [{componentId, componentName}]) .catch(stderr); } } -function evalInspect(componentId: string, componentName: string): void { +function evalInspect(query: ComponentQuery): void { // eslint-disable-next-line @typescript-eslint/method-signature-style const {inspect} = <{inspect?: (el: Element) => void} & Global>globalThis; @@ -31,7 +43,7 @@ function evalInspect(componentId: string, componentName: string): void { return; } - const node = globalThis.__V4FIRE_DEVTOOLS_BACKEND__.findComponentNode(componentId, componentName); + const node = globalThis.__V4FIRE_DEVTOOLS_BACKEND__.findComponentNode(query); if (node != null) { inspect(node); @@ -41,3 +53,17 @@ function evalInspect(componentId: string, componentName: string): void { alert('Component\'s node not found'); } } + +function evalSetComponentMod(key: string, value: unknown, query: ComponentQuery) { + const node = globalThis.__V4FIRE_DEVTOOLS_BACKEND__.findComponentNode(query); + + if (node == null) { + return; + } + + const {component} = >node; + + if (component != null) { + void component.setMod(key, value); + } +} diff --git a/packages/devtools-extension/src/features/components/b-components-tree/b-components-tree.ts b/packages/devtools-extension/src/features/components/b-components-tree/b-components-tree.ts index e2cf257..cbc00f6 100644 --- a/packages/devtools-extension/src/features/components/b-components-tree/b-components-tree.ts +++ b/packages/devtools-extension/src/features/components/b-components-tree/b-components-tree.ts @@ -6,6 +6,7 @@ * https://github.com/V4Fire/DevTools/blob/main/LICENSE */ +import type { ComponentQuery } from '@v4fire/devtools-backend'; import { devtoolsEval } from 'core/browser-api'; import { component, hook, system } from 'components/super/i-block/i-block'; @@ -31,7 +32,7 @@ export default class bComponentsTree extends Super { if (item != null) { devtoolsEval( evalHighlightActive, - [this.highlightedComponentId !== componentId, componentId, item.componentName] + [this.highlightedComponentId !== componentId, {componentId, componentName: item.componentName}] ) .catch(stderr); } @@ -45,7 +46,7 @@ export default class bComponentsTree extends Super { */ protected override onItemMouseEnter(item: Item): void { this.highlightedComponentId = item.value; - devtoolsEval(evalShowComponentHighlight, [item.value, item.componentName]).catch(stderr); + devtoolsEval(evalShowComponentHighlight, [{componentId: item.value, componentName: item.componentName}]).catch(stderr); } /** @@ -56,21 +57,21 @@ export default class bComponentsTree extends Super { } } -function evalHighlightActive(autoHide: boolean, ...args: [string, string]): void { +function evalHighlightActive(autoHide: boolean, query: ComponentQuery): void { const backend = globalThis.__V4FIRE_DEVTOOLS_BACKEND__; - const node = backend.findComponentNode(...args); + const node = backend.findComponentNode(query); // @ts-expect-error Non-standard API node?.scrollIntoViewIfNeeded(false); - backend.componentHighlight.show(...args); + backend.componentHighlight.show(query); if (autoHide) { backend.componentHighlight.hide({delay: 1500, animate: true}); } } -function evalShowComponentHighlight(...args: [string, string]): void { - globalThis.__V4FIRE_DEVTOOLS_BACKEND__.componentHighlight.show(...args); +function evalShowComponentHighlight(query: ComponentQuery): void { + globalThis.__V4FIRE_DEVTOOLS_BACKEND__.componentHighlight.show(query); } function evalHideComponentHighlight(): void { diff --git a/packages/devtools-extension/src/pages/p-components/p-components.ts b/packages/devtools-extension/src/pages/p-components/p-components.ts index ec50f7a..1d8c56a 100644 --- a/packages/devtools-extension/src/pages/p-components/p-components.ts +++ b/packages/devtools-extension/src/pages/p-components/p-components.ts @@ -142,7 +142,7 @@ function evalComponentMeta(value: string, name?: string): Nullable { 'LANG_PACKS' ]); - const node = globalThis.__V4FIRE_DEVTOOLS_BACKEND__.findComponentNode(value, name); + const node = globalThis.__V4FIRE_DEVTOOLS_BACKEND__.findComponentNode({componentId: value, componentName: name}); if (node == null) { return null; @@ -154,7 +154,7 @@ function evalComponentMeta(value: string, name?: string): Nullable { throw new Error('DOM node doesn\'t have component property'); } - const {componentName, props, fields, computedFields, systemFields} = component.unsafe.meta; + const {componentName, props, fields, computedFields, systemFields, mods} = component.unsafe.meta; const values = {}; @@ -174,7 +174,17 @@ function evalComponentMeta(value: string, name?: string): Nullable { parent = parent.parentMeta; } - const result = {componentId: value, componentName, props, fields, computedFields, systemFields, hierarchy, values}; + const result = { + componentId: value, + componentName, + props, + fields, + computedFields, + systemFields, + mods, + hierarchy, + values + }; return globalThis.__V4FIRE_DEVTOOLS_BACKEND__.serialize( result,