Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: flexbox #166

Open
MichaelMure opened this issue Jan 23, 2023 · 6 comments · May be fixed by #173
Open

feat: flexbox #166

MichaelMure opened this issue Jan 23, 2023 · 6 comments · May be fixed by #173

Comments

@MichaelMure
Copy link

Expanding on #162 (comment), I thought that it would make sense as its own issue. Disclaimer: I'm a lipgloss noob.

Here is a proof of concept to illustrate what I'm talking about. Obviously, a lot could be changed or improved.

func TestExample(t *testing.T) {
	style1 := NewStyle().
		FlexGrow(2).
		Border(blockBorder, true).
		SetString("content 1")

	style2 := NewStyle().
		FlexGrow(1).
		Border(doubleBorder, true).
		SetString("content 2")

	fmt.Println(Flexbox(80, 40, style1, style2))
}

Botched implementation:

// Flexbox requires to have used Style.SetString beforehand.
func Flexbox(width, height int, styles ...Style) string {
	if len(styles) == 0 {
		return ""
	}
	if len(styles) == 1 {
		return styles[0].String()
	}

	// crazy flexbox voodoo, botched example with flex-grow:
	var totalGrow int
	for _, style := range styles {
		totalGrow += style.GetFlexGrow()
	}
	for _, style := range styles {
		style.Width(width * style.GetFlexGrow() / totalGrow)
	}

	var rendered []string
	for _, style := range styles {
		rendered = append(rendered, style.String())
	}

	// we would not actually use that:
	return JoinHorizontal(Bottom, rendered...)
}

const (
	flexGrowKey = iota + strikethroughSpacesKey + 1
)

func (s Style) FlexGrow(i int) Style {
	if i < 0 {
		panic("negative flex grow")
	}
	s.set(flexGrowKey, i)
	return s
}

func (s Style) GetFlexGrow() int {
	return s.getAsInt(flexGrowKey)
}

Rendered as:

███████████████████████████████████████████████████████╔══════════════════════════╗
█content 1                                            █║content 2                 ║
███████████████████████████████████████████████████████╚══════════════════════════╝
@MichaelMure
Copy link
Author

Flexbox algorithm is described in section 9: https://drafts.csswg.org/css-flexbox/#layout-algorithm

@meowgorithm
Copy link
Member

Hi! Before we get too deep into this have you looked at stickers at all? It was built for the Bubble Tea ecosystem and contains both a generic flexbox implementation and a flexbox table.

@MichaelMure
Copy link
Author

I've looked at it, but:

  • it doesn't really look lipgloss native to me, more like a relatively complex standalone component. There is no inheritance of flex properties like in CSS or native lipgloss ... This kind of small things seems to limit the flexibility and usefulness.
  • it doesn't implement any wrapping. It's more a responsive table than flexbox.

@MichaelMure
Copy link
Author

FYI, I'm making some progress on this (see master...MichaelMure:lipgloss:flexbox for curiosity and advice), but the CSSWG spec is hardly digestible.

@MichaelMure
Copy link
Author

FYI, I still have some issue with the box model (I ignored the border making the actual size of the box grow for now), but it's close to work!

container := NewStyle().
	Border(normalBorder).
	FlexWrap(FlexWrapWrap).
	FlexJustifyContent(FlexJustifyContentSpaceAround).
	Width(100)

style1 := NewStyle().
	Border(blockBorder, true).
	SetString("content 1\n\nfooo")

style2 := NewStyle().
	Border(doubleBorder, true).
	Padding(2).
	SetString("content 2")

style3 := NewStyle().
	Width(40).
	Border(doubleBorder, true).
	SetString("content 3\n\nfoobar\nbarfoo")

style4 := NewStyle().
	Width(60).
	Border(doubleBorder, true).
	SetString("content 4\n\nfoobar\nbarfoo")

fmt.Println(Flexbox(container, style1, style2, style3, style4))

image

@MichaelMure
Copy link
Author

image

@MichaelMure MichaelMure linked a pull request Feb 26, 2023 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants