chjj / blessed

A high-level terminal interface library for node.js.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

options.style references and style propagation

cancerberoSgx opened this issue · comments

This is actually 1 issue and one question or feature request. I know there is not much people listening but nevertheless I want to keep track of this here:

  1. Issue. User provided configuration object options.style is being used internally by instances to maintain their state. This makes impossible for the user to reuse options objects or have a base one and leads in unexpected behavior where visual element state like focus or hover gets "bound" between several of them.

Since the options are not cloned and sub-values are referenced / associated inside element instances, if several user calls to for create elements use the same option object base, even if they are spread (i.e blessed.box({...baseOptions, ...}), blessed.checkbox({...baseOptions, ...}), etc . all the elements will have the same state for focus or hover (so overing one of them will make all of them have the same hover style. It seems the visual state is stored in the same options object that the user provides !! I see screen.js modifying element.style. For example in element.js the hover state is being maintained at `options.effects.hover``
I tried to clone the options argument at the beginning of Element constructor but It didn't work.

This forces the user to provide a full new options object on each blessed.xxx() call. If they want to have a base option object to extend this issue makes it difficult, particlarly for large apps. Maybe some documentation could help. I'm still investigating, but I wanted to ask if somebody has the same problem or any tip and if a PR on this would be accepted.

The second problem is more a question, does somebody knows if it's possible that node's descendants to inherits options from their ancestors, particularly style ? For example, if I want to implement skins, I need to manually pass the same style.bg to all descendants - perhaps somebody thought of a way of accomplishing this automatically ?

Thanks! This library is awesome! Any tip is most appreciated, Keep it up!

perhaps related to #225

commented

I know this is an old issue, but this is definitely still an issue in blessed. I just ran into it because my UI has several boxes that you can tab between. Because they share the same border styles (white normal, blue when focused), I wanted to create a single object to handle the styles. Since blessed doesn't clone that style object or anything before it starts using it for internal state, all of my boxes thought they were focused.

This issue helped me figure out what was going on. My short term solution was to write a simple deep cloning function and used that to wrap my styles. Here's the function:

function reduceSource(accumulator, [key, value]) {
  if (typeof value === 'object') {
    accumulator[key] = deepClone(value)
  } else {
    accumulator[key] = value
  }

  return accumulator
}

export function deepClone(source) {
  return Object.entries(source).reduce(reduceSource, {})
}

...and this is what the implementation looks like:

const BOX_STYLE = {
  border: { fg: 'white' },
  focus: {
    border: { fg: 'blue' },
  },
  selected: {
    bg: 'blue',
  },
}

const box = new blessed.box({
  style: deepClone(BOX_STYLE),
})