PlAnimateBlink
Content pulsing between full opacity and a floor. The cycle is symmetric (full, faint, full), so however many times it runs, it ends where it started.
import { PlAnimateBlink } from 'plass-ui';
<PlAnimateBlink min={0.45}>
<PlChip color="warning">Awaiting approval</PlChip>
</PlAnimateBlink>;import 'package:plass_ui/plass_ui.dart';
const PlAnimateBlink(
min: 0.45,
child: PlChip(color: PlassColor.warning, child: Text('Awaiting approval')),
);Props
| Prop | Type | Default | Description |
|---|---|---|---|
| min | number | 0 | How faint it gets at the bottom of the cycle, between 0 and 1. Raise it for something that has to stay readable while it pulses |
| durationshared | number | 1000 | 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 |
| timelineshared | 'auto' | 'view' | 'auto' | What advances the animation: the clock, or the reader's scroll position. view ignores duration, delay, repeat and trigger, and runs against range instead |
| rangeshared | string | 'entry 0% cover 45%' | As CSS writes an animation-range. Only read when timeline is view |
| staggershared | number | 0 | Milliseconds added to each child's delay. 0 plays the box itself; anything else moves the effect onto the children and takes it off the box |
| durationStepshared | number | 0 | Milliseconds added to each child's duration. Negative is allowed; floored at 0 |
| reverseshared | boolean | false | Runs the set from the last child to the first. Only the order turns round; each child still plays forwards |
| render | ReactElement | (props, state) => ReactElement | — | Renders something other than a <div> |
| Prop | Type | Default | Description |
|---|---|---|---|
| min | double | 0 | How faint it gets at the bottom of the cycle, between 0 and 1. Raise it for something that has to stay readable while it pulses |
| durationshared | Duration | Duration(milliseconds: 1000) | 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 pulses |
Every native <div> attribute passes straight through, and render swaps the element for another one.
repeat is an int? and it is left at its default here, which is null — the value that never stops. There is no mode and no fade: a blink is a cycle rather than an arrival.
There is no mode and no fade. A blink is a cycle rather than an arrival, so it has no direction to run in and nothing to fade separately from.
repeat defaults to 'infinite' here and to 1 everywhere else, because a single blink is a flicker and nobody asks for a flicker. The rest of the shared settings — duration, delay, easing, alternate, paused, trigger, play, once, threshold — mean what they mean on every other PlAnimate* component.
Three more move the effect off the box and onto the things inside it: stagger holds each child back by its position, durationStep gives each one a longer or shorter run than the last, and reverse starts from the end of the set. They are on all six single-keyframe effects and are shown on the PlAnimateFade page. timeline="view" and range are there too, and hand the effect to the reader's scroll position instead of the clock.
Examples
min
How faint it gets at the bottom of the cycle. At 0 the content disappears; raise it for anything that has to stay readable while it pulses, which is most things — a word that is only there half the time is a word somebody will miss.
repeat
A count is the way to draw attention to something once, rather than forever. The cycle is symmetric, so a run that ends leaves the content exactly as it found it.
Accessibility
- Under
prefers-reduced-motionthe animation is dropped entirely and the content sits at full opacity. Sominmust never be the only thing carrying the message — if it is urgent, say so in words as well. - Something that never stops moving in the corner of a page somebody is reading is the one kind of motion the rest of this library refuses. Prefer a count over
'infinite', and prefer a colour over either. - Keep it well away from three flashes a second. This is a slow pulse by default and it should stay one.
- When the platform has animations turned off (
MediaQuery.disableAnimations) the effect is dropped and the content sits at full opacity. Sominmust never be the only thing carrying the message — if it is urgent, say so in words as well. - Something that never stops moving in the corner of a screen somebody is reading is the one kind of motion the rest of this package refuses. Prefer a count over a
nullrepeat, and prefer a colour over either. - Keep it well away from three flashes a second. This is a slow pulse by default and it should stay one.
Differences from the React build
| React | Flutter | Why |
|---|---|---|
repeat="infinite" | repeat: null | The default here, and the value that never stops. |
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. |
stagger, durationStep, reverse | — | The React build writes the effect onto the children themselves, so the caller's own layout is untouched. Flutter has no stylesheet to lay a set out with, so a staggered effect would have to own the row or the column as well — which is what PlAnimateAppear is, and six more of it would be six more of it. |
timeline="view" | — | animation-timeline is a CSS property with no counterpart here. A scroll-linked effect in Flutter is an AnimationController driven from a ScrollPosition, which is an application's own wiring rather than something a widget takes as a prop. |
className, style | — | There is no class list and no style attribute to pass through. |