PlAnimateLighting
A light travelling around the outside of something. It draws attention with light rather than by moving anything, which is the only way this library has of saying "here" without also saying "and it moved".
import { PlAnimateLighting } from 'plass-ui';
<PlAnimateLighting size="lg" color="primary">
<PlCard size="lg" title="Recommended">
…
</PlCard>
</PlAnimateLighting>;import 'package:plass_ui/plass_ui.dart';
const PlAnimateLighting(
size: PlassSize.lg,
child: PlCard(size: PlassSize.lg, title: Text('Recommended'), child: Text('…')),
);Props
| Prop | Type | Default | Description |
|---|---|---|---|
| colorshared | 'primary' | 'secondary' | 'success' | 'warning' | 'danger' | 'info' | 'primary' | Which family the light is drawn in. The arc turns between that family two ends as it travels, exactly as a solid fill does |
| glow | string | — | A CSS colour, when a semantic family is not what is wanted. Overrides color, and the arc stops turning — one colour has nowhere to turn to |
| sizeshared | 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'md' | The radius the light follows. It has to match what is inside, or the glow will cut a corner the content has rounded off |
| spread | number | 3 | How far past the content the light reaches, in pixels |
| arc | number | 50 | How much of the outline is lit at once, in degrees. Small is a travelling spark; large is a sweep |
| blur | number | 5 | How soft the light is, in pixels. At 0 it is a hard-edged wedge, which reads as a graphic rather than as light |
| reverse | boolean | false | Runs the light the other way round |
| durationshared | number | 3000 | How long one run takes, in milliseconds. A number, never a CSS string |
| delayshared | number | 0 | How long before it starts, in milliseconds |
| easingshared | string | the house curve | The easing curve, written the way CSS writes it |
| repeatshared | number | 'infinite' | 'infinite' | How many times it runs. 'infinite' rather than Infinity, because that word is what reaches CSS |
| alternateshared | boolean | false | Runs every other pass backwards, so a repeat returns instead of jumping |
| pausedshared | boolean | false | Holds the animation where it is |
| triggershared | 'mount' | 'visible' | 'hover' | 'manual' | 'mount' | What starts it: mount as soon as it is on the page, visible when it is scrolled into view, hover while the pointer or focus is on it, manual only when play says so |
| playshared | boolean | — | Runs it when trigger is manual. Each false → true starts it over |
| onceshared | boolean | true | With trigger="visible", whether it runs only the first time. Off, it runs again every time the element comes back into view |
| thresholdshared | number | 0.2 | With trigger="visible", how much of the element has to be on screen before it counts as visible, from 0 to 1 |
| render | ReactElement | (props, state) => ReactElement | — | Renders something other than a <div> |
| Prop | Type | Default | Description |
|---|---|---|---|
| colorshared | PlassColor | PlassColor.primary | Which family the light is drawn in. The arc turns between that family two ends as it travels, exactly as a solid fill does |
| glow | Color? | — | A CSS colour, when a semantic family is not what is wanted. Overrides color, and the arc stops turning — one colour has nowhere to turn to |
| sizeshared | PlassSize | PlassSize.md | The radius the light follows. It has to match what is inside, or the glow will cut a corner the content has rounded off |
| spread | double | 3 | How far past the content the light reaches, in pixels |
| arc | double | 50 | How much of the outline is lit at once, in degrees. Small is a travelling spark; large is a sweep |
| blur | double | 5 | How soft the light is, in pixels. At 0 it is a hard-edged wedge, which reads as a graphic rather than as light |
| reverse | bool | false | Runs the light the other way round |
| durationshared | Duration | Duration(milliseconds: 3000) | How long one run takes, in milliseconds. A number, never a CSS string |
| delayshared | Duration | Duration.zero | How long before it starts, in milliseconds |
| curveshared | Curve? | the house curve | The easing curve, written the way CSS writes it |
| repeatshared | int? | null | How many times it runs. null is what never stops: there is no 'infinite' to write, and -1 would be a sentinel a caller has to look up |
| alternateshared | bool | false | Runs every other pass backwards, so a repeat returns instead of jumping |
| pausedshared | bool | false | Holds the animation where it is |
| triggershared | PlassAnimateTrigger | PlassAnimateTrigger.mount | What starts it: mount as soon as it is on the page, visible when it is scrolled into view, hover while the pointer or focus is on it, manual only when play says so |
| playshared | bool | false | Runs it when trigger is manual. Each false → true starts it over |
| onceshared | bool | true | With trigger="visible", whether it runs only the first time. Off, it runs again every time the element comes back into view |
| thresholdshared | double | 0.2 | With trigger="visible", how much of the element has to be on screen before it counts as visible, from 0 to 1 |
| child * | Widget | — | What is lit |
Every native <div> attribute passes straight through. color is excluded from the pass-through because it is a Plass prop here, and render swaps the element for another one.
glow is a Color? rather than a CSS colour string. spread and blur are doubles in logical pixels, and arc is degrees.
size has to agree with the radius of what is inside it. The glow follows the wrapper's own corners, so an lg card in an xs Lighting shows light poking out of four corners the card has already rounded away.
The light sits behind the content rather than on it, in a stacking context of its own, so nothing inside is altered or overlaid and the content stays exactly as legible as it was.
The ten shared settings — duration, delay, easing, repeat, alternate, paused, trigger, play, once, threshold — are the same on every PlAnimate* component, except that repeat defaults to 'infinite' here.
Examples
color
The arc turns between the two ends of the family as it travels, which is the same rule every filled surface in the library follows: a flat coloured arc would be paint, and nothing here is paint. glow takes one CSS colour instead when a semantic family is not what is wanted, and then there is nothing for the arc to turn to.
arc, blur and spread
How much of the outline is lit at once, how soft the light is, and how far past the content it reaches. A small arc is a spark running round an edge; a large one is a sweep. At blur={0} it stops being light and becomes a graphic.
Accessibility
- Under
prefers-reduced-motionthe arc stops travelling and becomes an even glow. The decoration survives; the motion does not. - The light says nothing to a screen reader, and it should not have to. Whatever it is marking — the row that is processing, the plan being recommended — needs to be stated in the content as well.
- One per screen. A page with three things glowing has no one thing that is live.
- When the platform has animations turned off (
MediaQuery.disableAnimations) the arc stops travelling and becomes an even glow. The decoration survives; the motion does not. - The light says nothing to a screen reader, and it should not have to. Whatever it is marking needs to be stated in the content as well.
- One per screen. A screen with three things glowing has no one thing that is live.
Differences from the React build
| React | Flutter | Why |
|---|---|---|
glow as a CSS colour string | Color? | The framework already has the type. |
a conic gradient on a ::before | a SweepGradient on a Positioned layer behind the child | There are no pseudo-elements. The layer is first in a Stack with clipBehavior: Clip.none, so the glow reaches past the content and still sits under it. |
@property on the angle so the from is animatable | GradientRotation on the sweep | What moves is the gradient's own rotation, not the layer's — rotating the layer would swing its corners out past the content on every quarter turn, which is the same reason the CSS animates the angle rather than the element. |
filter: blur() | ImageFiltered | The framework's own name for the same filter. |
render | — | Flutter has no polymorphic element. |
duration, delay in milliseconds | Duration | The framework already has the type. |
easing as a CSS string | curve, a Curve | Dart's own name for the same thing. |
repeat: number | 'infinite' | int?, null never stops | There is no 'infinite' to write, and -1 would be a sentinel a caller has to look up. |
trigger="visible" via IntersectionObserver | watches the nearest Scrollable | There is no observer here; with no scrollable above it there is nothing to watch, so it runs. |
prefers-reduced-motion | MediaQuery.disableAnimations | The platform's own signal. |
className, style | — | There is no class list and no style attribute to pass through. |