at main
33 folders
1 file
Replace intent with the shared semantic colour contract (#309)
* Replace the intent colour contract with shared semantic roles
The public contract exposed an asymmetric `color.intent` tree: neutral,
accent, and danger received a full interactive ramp while info, success,
and warning received a feedback-only kit. That described how components
happened to use colour rather than what each colour styles and means.
Replace it with a property-first contract shared by all six roles. Every
role now gets subtle and solid background ramps with rest/hover/pressed,
a resting and a stronger interactive foreground, a guaranteed on-solid
foreground, and one state-free border — 60 leaves keyed off a single
canonical `SEMANTIC_ROLES` list that generation, mapping, validation,
diagnostics, and tooling all read.
`FAMILY_REQUIREMENTS` collapses to one uniform capability set, so all six
families are now gated on on-solid contrast where only neutral, accent,
and danger were before. This moves no existing colour: not one family
needed adapting, and steps 3-8, 11, and 12 generate identically for
info, success, and warning. The golden diff is additive only.
The validation matrix is now uniform per role: 90 hard checks (8
functional text, 60 role foregrounds, 18 on-solid, 2 focus, 2 control)
and 12 advisory semantic-border checks per mode.
`rest` is an explicit leaf because a path cannot be both a string leaf
and the parent of `hover` and `pressed`. Solid pressed deliberately
reuses solid hover; components carry the press through depth, finish, or
transform.
Refs #298, #299, #305
* Migrate components to the shared semantic colour contract
Move every consumer off `color.intent` onto the new background,
foreground, and border paths. Each old path has an exact new equivalent
resolving to an identical value, so this is visually a no-op: 218 of 222
visual captures are pixel-identical, and the four that differ are Token
Board captures whose height changed because the contract grew.
Button and IconButton keep their subtle, solid, ghost, hover, pressed,
disabled, pending, focus, material, and forced-colours behaviour. Button
derives its ramp type from the contract now rather than mirroring a
hand-flattened shape. Link uses the resting foreground at rest and the
stronger hover foreground for both hover and press, since the shared
contract carries no separate pressed content colour.
Fields and Combobox controls use the state-free accent and danger borders
while the functional focus ring stays independent on `border.focus`.
Selection stays a component pattern: selected options compose the accent
subtle ramp with a weight change and a check icon rather than a public
selected colour token. Disabled and pending controls preserve their
resting colours and suppress interaction states.
Add the coverage the specification asks for and the suites lacked:
Button's subtle ramp and its disabled suppression, a Field browser test
for the required indicator and error tone, and Combobox's
selected-plus-keyboard-focus composition.
Note that the advisory semantic borders sit at 1.62-2.19:1, below the 3:1
non-text gate, so they must never be a required state's only cue. The
three pre-existing violations of that rule are unchanged here and remain
tracked in #247.
Refs #298, #300, #301, #302, #303
* Document the shared semantic colour roles
Teach one shared role model instead of action and feedback intent groups:
the six roles and their meanings, the background and foreground state
grammar, the state-free borders, and the contrast guarantees. Publish the
old-to-new migration table, which is now the only place the old paths
appear.
Replace the intent-colours example with a role-colours example that shows
subtle and solid swatches per role, so the page demonstrates that every
role carries the full capability set.
Migrate the raw CSS consumers in the docs app, and fix a mis-cased
`--luke-color-intent-neutral-surface-subtleHover` reference that never
resolved against a real generated variable.
Correct the generation document: the loading skeleton maps to neutral
step 8, as implemented and tested, not step 7.
Refs #298, #304
Rework multi-part recipes to a slotted recipe() architecture (#223)
* Rework multi-part recipes to a slotted recipe() architecture
Replace the flat multi-part recipe exports with a HeroUI/Tailwind-Variants-style
recipe() helper (issue #215). field and textInput from @luke-ui/react/recipes are
now slotted recipes: select variants at the outer call, then read each slot, e.g.
field({ necessityIndicator, tone }).label(className) and textInput({ size }).group().
Slot functions take only an optional extra class. combobox migrates to one internal
slotted recipe with a shared size group. Types are inferred from each config; no
Vanilla Extract implementation types (RuntimeFn/StyleRule) leak into the public .d.ts.
recipe() runs at build time in a .css.ts, decomposing a slotted config into one
recipeInLayer-equivalent recipe per slot in declaration order, so the emitted CSS and
class names are byte-identical to the previous hand-written recipes. The returned
callable is registered with Vanilla Extract's function serializer so it survives the
.css.ts build boundary. Single-base extend inheritance is supported.
The composed ComboboxField and TextField components are unchanged: they keep reusing
the Field primitive internally and gain the migrated recipes through the primitives
they render.
Pre-1.0 breaking change to @luke-ui/react/recipes. Removed with no aliases: fieldLabel,
fieldMessage, textInputGroup, textInputControl, textInputAdornmentStart,
textInputAdornmentEnd. The *Variants types are kept.
* Delete changesets
* Simplify props
* Improve types and comments
Consolidate polymorphic APIs onto elementType and render (#123)
* Consolidate polymorphic APIs onto elementType and render
Drop the hand-rolled `as` prop (used only by LoadingSkeleton) in favour
of `elementType`, the react-aria-components convention already used by
Text, Heading, and Numeral. `as` and `elementType` did the same job
(pick the DOM tag); this removes the duplicate, non-idiomatic path.
Also extract Box's local `BoxRender` type into a shared, documented
`RenderProp` type. react-aria-components does not publicly export its
render-function type, so this is the canonical Luke UI definition,
stopping the next component from inventing another render-prop variant.
Net API surface: `elementType` = which tag, `render` = take over
rendering. Two orthogonal, RAC-aligned APIs, no bespoke `as`.
- LoadingSkeleton: `as` -> `elementType` (component, stories, docs, example)
- heading-context: fix stale JSDoc example that referenced `as`
- Box: use shared RenderProp<'div'> instead of local BoxRender
- add packages/@luke-ui/react/src/types/render-prop.ts
* Reflow loading-skeleton docs prose to satisfy formatter
Replace intent with the shared semantic colour contract (#309)
* Replace the intent colour contract with shared semantic roles
The public contract exposed an asymmetric `color.intent` tree: neutral,
accent, and danger received a full interactive ramp while info, success,
and warning received a feedback-only kit. That described how components
happened to use colour rather than what each colour styles and means.
Replace it with a property-first contract shared by all six roles. Every
role now gets subtle and solid background ramps with rest/hover/pressed,
a resting and a stronger interactive foreground, a guaranteed on-solid
foreground, and one state-free border — 60 leaves keyed off a single
canonical `SEMANTIC_ROLES` list that generation, mapping, validation,
diagnostics, and tooling all read.
`FAMILY_REQUIREMENTS` collapses to one uniform capability set, so all six
families are now gated on on-solid contrast where only neutral, accent,
and danger were before. This moves no existing colour: not one family
needed adapting, and steps 3-8, 11, and 12 generate identically for
info, success, and warning. The golden diff is additive only.
The validation matrix is now uniform per role: 90 hard checks (8
functional text, 60 role foregrounds, 18 on-solid, 2 focus, 2 control)
and 12 advisory semantic-border checks per mode.
`rest` is an explicit leaf because a path cannot be both a string leaf
and the parent of `hover` and `pressed`. Solid pressed deliberately
reuses solid hover; components carry the press through depth, finish, or
transform.
Refs #298, #299, #305
* Migrate components to the shared semantic colour contract
Move every consumer off `color.intent` onto the new background,
foreground, and border paths. Each old path has an exact new equivalent
resolving to an identical value, so this is visually a no-op: 218 of 222
visual captures are pixel-identical, and the four that differ are Token
Board captures whose height changed because the contract grew.
Button and IconButton keep their subtle, solid, ghost, hover, pressed,
disabled, pending, focus, material, and forced-colours behaviour. Button
derives its ramp type from the contract now rather than mirroring a
hand-flattened shape. Link uses the resting foreground at rest and the
stronger hover foreground for both hover and press, since the shared
contract carries no separate pressed content colour.
Fields and Combobox controls use the state-free accent and danger borders
while the functional focus ring stays independent on `border.focus`.
Selection stays a component pattern: selected options compose the accent
subtle ramp with a weight change and a check icon rather than a public
selected colour token. Disabled and pending controls preserve their
resting colours and suppress interaction states.
Add the coverage the specification asks for and the suites lacked:
Button's subtle ramp and its disabled suppression, a Field browser test
for the required indicator and error tone, and Combobox's
selected-plus-keyboard-focus composition.
Note that the advisory semantic borders sit at 1.62-2.19:1, below the 3:1
non-text gate, so they must never be a required state's only cue. The
three pre-existing violations of that rule are unchanged here and remain
tracked in #247.
Refs #298, #300, #301, #302, #303
* Document the shared semantic colour roles
Teach one shared role model instead of action and feedback intent groups:
the six roles and their meanings, the background and foreground state
grammar, the state-free borders, and the contrast guarantees. Publish the
old-to-new migration table, which is now the only place the old paths
appear.
Replace the intent-colours example with a role-colours example that shows
subtle and solid swatches per role, so the page demonstrates that every
role carries the full capability set.
Migrate the raw CSS consumers in the docs app, and fix a mis-cased
`--luke-color-intent-neutral-surface-subtleHover` reference that never
resolved against a real generated variable.
Correct the generation document: the loading skeleton maps to neutral
step 8, as implemented and tested, not step 7.
Refs #298, #304
Delete the recipe code nothing uses, and the leftovers (#272)
The recipe engine had two features with no consumers. `extend` was
declared on both config shapes and implemented across three functions,
including the recursive config merging that was also the only untested
logic in the file. Slotted compound variants were similar: the four
slot-using recipes declare no compound variants, and the two recipes that
do are both single part. Deleting both takes recipe.ts from 457 to 354
lines. Single-part compound variants stay, because button and text use
them. Re-add either the day a second recipe needs it.
Delete the nine hand-written Text variant types rather than deriving
them. Four string unions and three key arrays duplicated what the recipe
already knows with nothing type-checking the two against each other, so
adding a wrap value or a colour role would have gone stale silently. All
nine were exported publicly with no consumers, invisible to knip because
the barrel is an entry point. Text's own component already derives its
prop types by indexing TextVariants, and button, field and icon already
export only the aggregate, so the barrel now matches that convention.
input-states.css.ts emits no CSS at all, yet the suffix marked it as
having side effects and kept it out of consumer tree shaking. Renamed to
input-states.ts.
The barrel exported loadingSkeleton as a plain class string among twelve
callable recipes, which invited a consumer to call it; it is now
loadingSkeletonClassName. Renaming rather than wrapping it in recipe()
keeps the emitted CSS untouched. Two recipes also both exported something
named `icon`, so icon-button's is now iconButtonIcon.
The emitted stylesheet is byte-identical at 78007 bytes and the v2
goldens are unchanged, which is expected: the deleted code paths were
never exercised, and the renames do not reach content-hashed class names.
Replace intent with the shared semantic colour contract (#309)
* Replace the intent colour contract with shared semantic roles
The public contract exposed an asymmetric `color.intent` tree: neutral,
accent, and danger received a full interactive ramp while info, success,
and warning received a feedback-only kit. That described how components
happened to use colour rather than what each colour styles and means.
Replace it with a property-first contract shared by all six roles. Every
role now gets subtle and solid background ramps with rest/hover/pressed,
a resting and a stronger interactive foreground, a guaranteed on-solid
foreground, and one state-free border — 60 leaves keyed off a single
canonical `SEMANTIC_ROLES` list that generation, mapping, validation,
diagnostics, and tooling all read.
`FAMILY_REQUIREMENTS` collapses to one uniform capability set, so all six
families are now gated on on-solid contrast where only neutral, accent,
and danger were before. This moves no existing colour: not one family
needed adapting, and steps 3-8, 11, and 12 generate identically for
info, success, and warning. The golden diff is additive only.
The validation matrix is now uniform per role: 90 hard checks (8
functional text, 60 role foregrounds, 18 on-solid, 2 focus, 2 control)
and 12 advisory semantic-border checks per mode.
`rest` is an explicit leaf because a path cannot be both a string leaf
and the parent of `hover` and `pressed`. Solid pressed deliberately
reuses solid hover; components carry the press through depth, finish, or
transform.
Refs #298, #299, #305
* Migrate components to the shared semantic colour contract
Move every consumer off `color.intent` onto the new background,
foreground, and border paths. Each old path has an exact new equivalent
resolving to an identical value, so this is visually a no-op: 218 of 222
visual captures are pixel-identical, and the four that differ are Token
Board captures whose height changed because the contract grew.
Button and IconButton keep their subtle, solid, ghost, hover, pressed,
disabled, pending, focus, material, and forced-colours behaviour. Button
derives its ramp type from the contract now rather than mirroring a
hand-flattened shape. Link uses the resting foreground at rest and the
stronger hover foreground for both hover and press, since the shared
contract carries no separate pressed content colour.
Fields and Combobox controls use the state-free accent and danger borders
while the functional focus ring stays independent on `border.focus`.
Selection stays a component pattern: selected options compose the accent
subtle ramp with a weight change and a check icon rather than a public
selected colour token. Disabled and pending controls preserve their
resting colours and suppress interaction states.
Add the coverage the specification asks for and the suites lacked:
Button's subtle ramp and its disabled suppression, a Field browser test
for the required indicator and error tone, and Combobox's
selected-plus-keyboard-focus composition.
Note that the advisory semantic borders sit at 1.62-2.19:1, below the 3:1
non-text gate, so they must never be a required state's only cue. The
three pre-existing violations of that rule are unchanged here and remain
tracked in #247.
Refs #298, #300, #301, #302, #303
* Document the shared semantic colour roles
Teach one shared role model instead of action and feedback intent groups:
the six roles and their meanings, the background and foreground state
grammar, the state-free borders, and the contrast guarantees. Publish the
old-to-new migration table, which is now the only place the old paths
appear.
Replace the intent-colours example with a role-colours example that shows
subtle and solid swatches per role, so the page demonstrates that every
role carries the full capability set.
Migrate the raw CSS consumers in the docs app, and fix a mis-cased
`--luke-color-intent-neutral-surface-subtleHover` reference that never
resolved against a real generated variable.
Correct the generation document: the loading skeleton maps to neutral
step 8, as implemented and tested, not step 7.
Refs #298, #304
Replace intent with the shared semantic colour contract (#309)
* Replace the intent colour contract with shared semantic roles
The public contract exposed an asymmetric `color.intent` tree: neutral,
accent, and danger received a full interactive ramp while info, success,
and warning received a feedback-only kit. That described how components
happened to use colour rather than what each colour styles and means.
Replace it with a property-first contract shared by all six roles. Every
role now gets subtle and solid background ramps with rest/hover/pressed,
a resting and a stronger interactive foreground, a guaranteed on-solid
foreground, and one state-free border — 60 leaves keyed off a single
canonical `SEMANTIC_ROLES` list that generation, mapping, validation,
diagnostics, and tooling all read.
`FAMILY_REQUIREMENTS` collapses to one uniform capability set, so all six
families are now gated on on-solid contrast where only neutral, accent,
and danger were before. This moves no existing colour: not one family
needed adapting, and steps 3-8, 11, and 12 generate identically for
info, success, and warning. The golden diff is additive only.
The validation matrix is now uniform per role: 90 hard checks (8
functional text, 60 role foregrounds, 18 on-solid, 2 focus, 2 control)
and 12 advisory semantic-border checks per mode.
`rest` is an explicit leaf because a path cannot be both a string leaf
and the parent of `hover` and `pressed`. Solid pressed deliberately
reuses solid hover; components carry the press through depth, finish, or
transform.
Refs #298, #299, #305
* Migrate components to the shared semantic colour contract
Move every consumer off `color.intent` onto the new background,
foreground, and border paths. Each old path has an exact new equivalent
resolving to an identical value, so this is visually a no-op: 218 of 222
visual captures are pixel-identical, and the four that differ are Token
Board captures whose height changed because the contract grew.
Button and IconButton keep their subtle, solid, ghost, hover, pressed,
disabled, pending, focus, material, and forced-colours behaviour. Button
derives its ramp type from the contract now rather than mirroring a
hand-flattened shape. Link uses the resting foreground at rest and the
stronger hover foreground for both hover and press, since the shared
contract carries no separate pressed content colour.
Fields and Combobox controls use the state-free accent and danger borders
while the functional focus ring stays independent on `border.focus`.
Selection stays a component pattern: selected options compose the accent
subtle ramp with a weight change and a check icon rather than a public
selected colour token. Disabled and pending controls preserve their
resting colours and suppress interaction states.
Add the coverage the specification asks for and the suites lacked:
Button's subtle ramp and its disabled suppression, a Field browser test
for the required indicator and error tone, and Combobox's
selected-plus-keyboard-focus composition.
Note that the advisory semantic borders sit at 1.62-2.19:1, below the 3:1
non-text gate, so they must never be a required state's only cue. The
three pre-existing violations of that rule are unchanged here and remain
tracked in #247.
Refs #298, #300, #301, #302, #303
* Document the shared semantic colour roles
Teach one shared role model instead of action and feedback intent groups:
the six roles and their meanings, the background and foreground state
grammar, the state-free borders, and the contrast guarantees. Publish the
old-to-new migration table, which is now the only place the old paths
appear.
Replace the intent-colours example with a role-colours example that shows
subtle and solid swatches per role, so the page demonstrates that every
role carries the full capability set.
Migrate the raw CSS consumers in the docs app, and fix a mis-cased
`--luke-color-intent-neutral-surface-subtleHover` reference that never
resolved against a real generated variable.
Correct the generation document: the loading skeleton maps to neutral
step 8, as implemented and tested, not step 7.
Refs #298, #304
Replace intent with the shared semantic colour contract (#309)
* Replace the intent colour contract with shared semantic roles
The public contract exposed an asymmetric `color.intent` tree: neutral,
accent, and danger received a full interactive ramp while info, success,
and warning received a feedback-only kit. That described how components
happened to use colour rather than what each colour styles and means.
Replace it with a property-first contract shared by all six roles. Every
role now gets subtle and solid background ramps with rest/hover/pressed,
a resting and a stronger interactive foreground, a guaranteed on-solid
foreground, and one state-free border — 60 leaves keyed off a single
canonical `SEMANTIC_ROLES` list that generation, mapping, validation,
diagnostics, and tooling all read.
`FAMILY_REQUIREMENTS` collapses to one uniform capability set, so all six
families are now gated on on-solid contrast where only neutral, accent,
and danger were before. This moves no existing colour: not one family
needed adapting, and steps 3-8, 11, and 12 generate identically for
info, success, and warning. The golden diff is additive only.
The validation matrix is now uniform per role: 90 hard checks (8
functional text, 60 role foregrounds, 18 on-solid, 2 focus, 2 control)
and 12 advisory semantic-border checks per mode.
`rest` is an explicit leaf because a path cannot be both a string leaf
and the parent of `hover` and `pressed`. Solid pressed deliberately
reuses solid hover; components carry the press through depth, finish, or
transform.
Refs #298, #299, #305
* Migrate components to the shared semantic colour contract
Move every consumer off `color.intent` onto the new background,
foreground, and border paths. Each old path has an exact new equivalent
resolving to an identical value, so this is visually a no-op: 218 of 222
visual captures are pixel-identical, and the four that differ are Token
Board captures whose height changed because the contract grew.
Button and IconButton keep their subtle, solid, ghost, hover, pressed,
disabled, pending, focus, material, and forced-colours behaviour. Button
derives its ramp type from the contract now rather than mirroring a
hand-flattened shape. Link uses the resting foreground at rest and the
stronger hover foreground for both hover and press, since the shared
contract carries no separate pressed content colour.
Fields and Combobox controls use the state-free accent and danger borders
while the functional focus ring stays independent on `border.focus`.
Selection stays a component pattern: selected options compose the accent
subtle ramp with a weight change and a check icon rather than a public
selected colour token. Disabled and pending controls preserve their
resting colours and suppress interaction states.
Add the coverage the specification asks for and the suites lacked:
Button's subtle ramp and its disabled suppression, a Field browser test
for the required indicator and error tone, and Combobox's
selected-plus-keyboard-focus composition.
Note that the advisory semantic borders sit at 1.62-2.19:1, below the 3:1
non-text gate, so they must never be a required state's only cue. The
three pre-existing violations of that rule are unchanged here and remain
tracked in #247.
Refs #298, #300, #301, #302, #303
* Document the shared semantic colour roles
Teach one shared role model instead of action and feedback intent groups:
the six roles and their meanings, the background and foreground state
grammar, the state-free borders, and the contrast guarantees. Publish the
old-to-new migration table, which is now the only place the old paths
appear.
Replace the intent-colours example with a role-colours example that shows
subtle and solid swatches per role, so the page demonstrates that every
role carries the full capability set.
Migrate the raw CSS consumers in the docs app, and fix a mis-cased
`--luke-color-intent-neutral-surface-subtleHover` reference that never
resolved against a real generated variable.
Correct the generation document: the loading skeleton maps to neutral
step 8, as implemented and tested, not step 7.
Refs #298, #304
Rework multi-part recipes to a slotted recipe() architecture (#223)
* Rework multi-part recipes to a slotted recipe() architecture
Replace the flat multi-part recipe exports with a HeroUI/Tailwind-Variants-style
recipe() helper (issue #215). field and textInput from @luke-ui/react/recipes are
now slotted recipes: select variants at the outer call, then read each slot, e.g.
field({ necessityIndicator, tone }).label(className) and textInput({ size }).group().
Slot functions take only an optional extra class. combobox migrates to one internal
slotted recipe with a shared size group. Types are inferred from each config; no
Vanilla Extract implementation types (RuntimeFn/StyleRule) leak into the public .d.ts.
recipe() runs at build time in a .css.ts, decomposing a slotted config into one
recipeInLayer-equivalent recipe per slot in declaration order, so the emitted CSS and
class names are byte-identical to the previous hand-written recipes. The returned
callable is registered with Vanilla Extract's function serializer so it survives the
.css.ts build boundary. Single-base extend inheritance is supported.
The composed ComboboxField and TextField components are unchanged: they keep reusing
the Field primitive internally and gain the migrated recipes through the primitives
they render.
Pre-1.0 breaking change to @luke-ui/react/recipes. Removed with no aliases: fieldLabel,
fieldMessage, textInputGroup, textInputControl, textInputAdornmentStart,
textInputAdornmentEnd. The *Variants types are kept.
* Delete changesets
* Simplify props
* Improve types and comments
Replace intent with the shared semantic colour contract (#309)
* Replace the intent colour contract with shared semantic roles
The public contract exposed an asymmetric `color.intent` tree: neutral,
accent, and danger received a full interactive ramp while info, success,
and warning received a feedback-only kit. That described how components
happened to use colour rather than what each colour styles and means.
Replace it with a property-first contract shared by all six roles. Every
role now gets subtle and solid background ramps with rest/hover/pressed,
a resting and a stronger interactive foreground, a guaranteed on-solid
foreground, and one state-free border — 60 leaves keyed off a single
canonical `SEMANTIC_ROLES` list that generation, mapping, validation,
diagnostics, and tooling all read.
`FAMILY_REQUIREMENTS` collapses to one uniform capability set, so all six
families are now gated on on-solid contrast where only neutral, accent,
and danger were before. This moves no existing colour: not one family
needed adapting, and steps 3-8, 11, and 12 generate identically for
info, success, and warning. The golden diff is additive only.
The validation matrix is now uniform per role: 90 hard checks (8
functional text, 60 role foregrounds, 18 on-solid, 2 focus, 2 control)
and 12 advisory semantic-border checks per mode.
`rest` is an explicit leaf because a path cannot be both a string leaf
and the parent of `hover` and `pressed`. Solid pressed deliberately
reuses solid hover; components carry the press through depth, finish, or
transform.
Refs #298, #299, #305
* Migrate components to the shared semantic colour contract
Move every consumer off `color.intent` onto the new background,
foreground, and border paths. Each old path has an exact new equivalent
resolving to an identical value, so this is visually a no-op: 218 of 222
visual captures are pixel-identical, and the four that differ are Token
Board captures whose height changed because the contract grew.
Button and IconButton keep their subtle, solid, ghost, hover, pressed,
disabled, pending, focus, material, and forced-colours behaviour. Button
derives its ramp type from the contract now rather than mirroring a
hand-flattened shape. Link uses the resting foreground at rest and the
stronger hover foreground for both hover and press, since the shared
contract carries no separate pressed content colour.
Fields and Combobox controls use the state-free accent and danger borders
while the functional focus ring stays independent on `border.focus`.
Selection stays a component pattern: selected options compose the accent
subtle ramp with a weight change and a check icon rather than a public
selected colour token. Disabled and pending controls preserve their
resting colours and suppress interaction states.
Add the coverage the specification asks for and the suites lacked:
Button's subtle ramp and its disabled suppression, a Field browser test
for the required indicator and error tone, and Combobox's
selected-plus-keyboard-focus composition.
Note that the advisory semantic borders sit at 1.62-2.19:1, below the 3:1
non-text gate, so they must never be a required state's only cue. The
three pre-existing violations of that rule are unchanged here and remain
tracked in #247.
Refs #298, #300, #301, #302, #303
* Document the shared semantic colour roles
Teach one shared role model instead of action and feedback intent groups:
the six roles and their meanings, the background and foreground state
grammar, the state-free borders, and the contrast guarantees. Publish the
old-to-new migration table, which is now the only place the old paths
appear.
Replace the intent-colours example with a role-colours example that shows
subtle and solid swatches per role, so the page demonstrates that every
role carries the full capability set.
Migrate the raw CSS consumers in the docs app, and fix a mis-cased
`--luke-color-intent-neutral-surface-subtleHover` reference that never
resolved against a real generated variable.
Correct the generation document: the loading skeleton maps to neutral
step 8, as implemented and tested, not step 7.
Refs #298, #304
Consolidate polymorphic APIs onto elementType and render (#123)
* Consolidate polymorphic APIs onto elementType and render
Drop the hand-rolled `as` prop (used only by LoadingSkeleton) in favour
of `elementType`, the react-aria-components convention already used by
Text, Heading, and Numeral. `as` and `elementType` did the same job
(pick the DOM tag); this removes the duplicate, non-idiomatic path.
Also extract Box's local `BoxRender` type into a shared, documented
`RenderProp` type. react-aria-components does not publicly export its
render-function type, so this is the canonical Luke UI definition,
stopping the next component from inventing another render-prop variant.
Net API surface: `elementType` = which tag, `render` = take over
rendering. Two orthogonal, RAC-aligned APIs, no bespoke `as`.
- LoadingSkeleton: `as` -> `elementType` (component, stories, docs, example)
- heading-context: fix stale JSDoc example that referenced `as`
- Box: use shared RenderProp<'div'> instead of local BoxRender
- add packages/@luke-ui/react/src/types/render-prop.ts
* Reflow loading-skeleton docs prose to satisfy formatter