Lesson 6 of 14
Anatomy: parts, kinds and slots
What a part is, how parts nest by path, when a part is present, and what a slot promises.
#The idea
A part says what it is, where it sits, whether it is there, and what it holds. Those four facts are the whole of anatomy, and every one of them is a statement a reader can resolve without asking anyone.
#What this lesson adds
An icon part before the label, and a prop to feed it:
milda
icon : string "A glyph shown before the label, by name."
milda
part icon: icon { content bind icon ink on-accent when variant = Secondary { ink text } when variant = Ghost { ink accent } }
#What to notice
- A part's name is a path.
iconandlabelare children of the root because their names have no dotted prefix. Lesson 7 writespart Header.Title: the childTitleof the partHeader. The prefix is the parent; the path is the only place nesting is written down. - Kinds are a short closed list. container, item, text, control, input, output, icon, content, fragment, table, row, cell, instance, foreign. An icon part is an icon on every platform; what draws it is the target's decision.
- An icon's content is the glyph's name.
content bind icontakes it from the prop, and the part renders only while the prop is given. A part can also be present only under a condition of its own, writtenpresent when <predicate>; lesson 8 uses it for an error hint. Present means rendered, not visible: an absent part is not in the tree at all. - Where a part came from is recorded. A part the archetype declares has the default origin and is printed without one; a part you add is
origin author. The editor uses this to know what it may offer to remove. - Text is , never . is the paint facet for a type style; a word that meant two things depending on its argument would read fine and parse wrong.
- A slot has an arity and a contract.
slot of content defaulton the label means: exactly one fill, free content, and this is where positional children go. and are the other arities;of Badgewould restrict the fill to one component.
#What the generator makes of it
The icon became {icon && <Icon name={icon} />} before the label span, drawing from a generated Icon module that lesson 12 fills with real glyphs.
#Try it
Give the Button a part badge: instance after the label, then read lesson 7 to find out what to put in it. Or make the label slot and see what the panel says about an icon-only button.
Words in this lesson
- What the part IS, in neutral terms.
- A dotted path addresses something by name: a token (
space.sm), a part (Header.Title), a context value. - The part exists only while the predicate holds - not hidden, absent.
- Where the part came from: provenance.
- The text the part shows: fixed, bound to a prop, or chosen by conditions.
- The part is a hole the consumer fills: the label of a button, the items of a menu.
Open a word for its entry, or read them all in the reference.
#The file at the end of this lesson
milda
milda 0.10 prelude 0.0.2 meta { name "Acme" } context-group ColorScheme { Light Dark } context-group Variant { Primary Secondary Ghost } foundations { layer Base { token violet/100 : color = hex(ede9fe) token violet/500 : color = hex(8b5cf6) token violet/600 : color = hex(7c3aed) token violet/700 : color = hex(6d28d9) token violet/900 : color = hex(4c1d95) token gray/50 : color = hex(f8fafc) token gray/200 : color = hex(e2e8f0) token gray/500 : color = hex(64748b) token gray/800 : color = hex(1e293b) token gray/900 : color = hex(0f172a) token green/500 : color = hex(22c55e) token amber/500 : color = hex(f59e0b) token white : color = hex(ffffff) } layer Semantic { token accent : color = alias by ColorScheme { default -> violet.600; Dark -> violet.500 } token accent-hover : color = alias by ColorScheme { default -> violet.700; Dark -> violet.600 } token accent-subtle : color = alias by ColorScheme { default -> violet.100; Dark -> violet.900 } token on-accent : color = alias by ColorScheme { default -> white } token surface : color = alias by ColorScheme { default -> white; Dark -> gray.900 } token text : color = alias by ColorScheme { default -> gray.900; Dark -> gray.50 } token text-muted : color = alias by ColorScheme { default -> gray.500 } token line : color = alias by ColorScheme { default -> gray.200; Dark -> gray.800 } token success : color = alias by ColorScheme { default -> green.500 } token warning : color = alias by ColorScheme { default -> amber.500 } token space/xs : spacing = 4px token space/sm : spacing = 8px token space/md : spacing = 12px token space/lg : spacing = 16px token space/xl : spacing = 24px token radius/sm : radius = 6px token radius/lg : radius = 12px token radius/pill : radius = pill token hairline : border = 1px token size/sm : font-size = 13px token size/md : font-size = 15px token size/lg : font-size = 18px token weight/medium : font-weight = 500 token weight/bold : font-weight = 700 } } component Button "The primary action, in three emphases." { archetype Button props { variant : context Variant = Primary "Which emphasis the button carries." disabled : boolean = false loading : boolean = false "Shows a spinner in place of the label." loadingLabel : string required when loading "Read out while the spinner replaces the label." label : string = "Get started" icon : string "A glyph shown before the label, by name." } events { click } part Button: container { emits { click on activate } bind state disabled disabled bind state loading loading layout { stack row; gap space.sm; align center; distribute center } fill accent ink on-accent border accent hairline corner radius.sm inset space.sm space.lg when variant = Secondary { fill surface ink text border line hairline } when variant = Ghost { fill surface ink accent border surface hairline } state hovered { fill accent-hover border accent-hover hairline } state hovered when variant = Secondary { fill accent-subtle } state hovered when variant = Ghost { fill accent-subtle border accent-subtle hairline } state focus-visible { ring accent } state disabled { opacity 50 } } part icon: icon { content bind icon ink on-accent when variant = Secondary { ink text } when variant = Ghost { ink accent } } part label: text { slot of content default content bind label text size.md weight weight.medium } }