flet-box 1.1.0 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/commands/checkUi.js +276 -45
- package/bin/commands/create.js +4 -0
- package/bin/commands/createScreen.js +1 -1
- package/bin/commands/runBundle.js +1 -1
- package/bin/utils/colors.js +0 -8
- package/bin/utils/helpers.js +0 -5
- package/bin/utils/images/jpeg.js +2 -3
- package/bin/utils/templates.js +78 -73
- package/docs/README.md +2 -0
- package/docs/cli/README.md +18 -1
- package/docs/guides/README.md +5 -2
- package/docs/guides/accessibility.md +282 -0
- package/docs/guides/clean-ui.md +53 -8
- package/docs/guides/minification-and-protection.md +1 -1
- package/docs/guides/mobile-and-platforms.md +51 -0
- package/docs/guides/utilities.md +116 -4
- package/docs/guides/widget-structure.md +30 -0
- package/docs/tools/README.md +1 -1
- package/docs/tools/animation.md +134 -11
- package/docs/tools/device.md +75 -3
- package/docs/tools/text-and-time.md +116 -6
- package/docs/widget/Accordion.md +2 -0
- package/docs/widget/AnimatedBox.md +46 -20
- package/docs/widget/AnimatedText.md +13 -7
- package/docs/widget/Badge.md +1 -0
- package/docs/widget/COMMON_PROPS.md +26 -3
- package/docs/widget/Chart.md +1 -0
- package/docs/widget/Checkbox.md +7 -1
- package/docs/widget/CircularChart.md +2 -0
- package/docs/widget/Drawer.md +1 -0
- package/docs/widget/GridView.md +4 -1
- package/docs/widget/Input.md +2 -0
- package/docs/widget/InstallButton.md +1 -0
- package/docs/widget/Markdown.md +4 -0
- package/docs/widget/Rating.md +2 -0
- package/docs/widget/Slider.md +2 -0
- package/docs/widget/Stack.md +6 -5
- package/docs/widget/Stepper.md +2 -0
- package/docs/widget/Tooltip.md +3 -1
- package/package.json +3 -2
- package/skills/fletbox-design/SKILL.md +390 -14
- package/skills/fletbox-motion/SKILL.md +145 -47
- package/skills/fletbox-rules/SKILL.md +140 -1
- package/src/animations/AnimatedBox.js +321 -226
- package/src/animations/MatrixRain.js +7 -1
- package/src/animations/ParallaxBox.js +13 -10
- package/src/animations/animate.js +269 -106
- package/src/animations/color.js +91 -0
- package/src/animations/easings.js +275 -0
- package/src/animations/index.js +21 -0
- package/src/animations/motion.js +204 -0
- package/src/animations/transitions.js +327 -0
- package/src/core/runApp.js +0 -6
- package/src/helpers/boxEdges.js +69 -0
- package/src/helpers/html.js +39 -0
- package/src/index.d.ts +377 -25
- package/src/index.js +77 -0
- package/src/navigations/AdaptiveScaffold.js +6 -2
- package/src/navigations/AppBar.js +16 -7
- package/src/navigations/BottomNavigation.js +24 -1
- package/src/navigations/CollapsibleSideBar.js +0 -1
- package/src/navigations/Drawer.js +32 -1
- package/src/navigations/DrawerItem.js +1 -1
- package/src/navigations/Router.js +0 -1
- package/src/navigations/Scaffold.js +9 -3
- package/src/navigations/Tabs.js +104 -31
- package/src/services/RamStore.js +1 -2
- package/src/tools/breakpoints.js +113 -0
- package/src/tools/createList.js +0 -2
- package/src/tools/fonts.js +99 -0
- package/src/tools/index.js +74 -1
- package/src/tools/margin.js +5 -63
- package/src/tools/padding.js +5 -63
- package/src/tools/print.js +0 -8
- package/src/tools/scale.js +9 -2
- package/src/tools/time.js +56 -15
- package/src/tools/useState.js +1 -54
- package/src/utils/fieldFont.js +77 -0
- package/src/utils/focusRing.js +73 -0
- package/src/utils/focusScope.js +113 -0
- package/src/utils/markdownParser.js +7 -9
- package/src/utils/readableInk.js +7 -1
- package/src/utils/stackLayout.js +55 -0
- package/src/utils/styleInjector.js +25 -0
- package/src/utils/syntaxHighlight.js +1 -17
- package/src/utils/themes.js +15 -0
- package/src/utils/visualEffects.js +49 -47
- package/src/widget-factory/createWidget.js +16 -3
- package/src/widget-factory/effects.js +76 -3
- package/src/widget-factory/reactiveValue.js +0 -7
- package/src/widget-factory/tools.js +26 -143
- package/src/widget-factory/translateProps.js +5 -0
- package/src/widget-factory/widgetFactory.js +1 -1
- package/src/widgets/Accordion.js +70 -12
- package/src/widgets/AdMob.js +1 -1
- package/src/widgets/AdSense.js +1 -1
- package/src/widgets/AlertDialog.js +11 -9
- package/src/widgets/Avatar.js +10 -1
- package/src/widgets/Badge.js +7 -1
- package/src/widgets/BottomSheet.js +39 -5
- package/src/widgets/Chart.js +41 -9
- package/src/widgets/Checkbox.js +59 -9
- package/src/widgets/Chip.js +13 -1
- package/src/widgets/CircularBar.js +17 -5
- package/src/widgets/CircularChart.js +24 -2
- package/src/widgets/CodeViewer.js +5 -3
- package/src/widgets/Dropdown.js +223 -20
- package/src/widgets/GridView.js +17 -1
- package/src/widgets/Icon.js +21 -0
- package/src/widgets/Input.js +75 -44
- package/src/widgets/InstallButton.js +8 -2
- package/src/widgets/ListTile.js +6 -5
- package/src/widgets/ListView.js +21 -7
- package/src/widgets/Markdown.js +25 -44
- package/src/widgets/Modal.js +43 -6
- package/src/widgets/Pagination.js +35 -3
- package/src/widgets/ProgressBar.js +18 -0
- package/src/widgets/Radio.js +7 -0
- package/src/widgets/Rating.js +104 -16
- package/src/widgets/Skeleton.js +9 -5
- package/src/widgets/Slider.js +87 -7
- package/src/widgets/SnackBar.js +30 -1
- package/src/widgets/Stack.js +25 -13
- package/src/widgets/Stepper.js +112 -64
- package/src/widgets/Switch.js +10 -1
- package/src/widgets/Tooltip.js +93 -10
- package/src/widgets/TreeView.js +5 -5
- package/src/create-index.sh +0 -237
- package/src/widget-factory/pixTool.js +0 -40
- package/src/widget-factory/stringTool.js +0 -26
package/docs/tools/device.md
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
# Device & environment
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
|
-
Detect what your app is running on: screen, orientation, operating system, and clipboard access. These helpers read the browser and stay in sync when the window changes.
|
|
4
|
+
Detect what your app is running on: screen, orientation, operating system, and clipboard access. These helpers read the browser and stay in sync when the window changes. The same page carries the two halves a responsive screen needs — the **breakpoint** vocabulary (`BREAKPOINTS`, `currentBreakpoint`, `atLeast`, `pick`, `onBreakpointChange`), which says *which layout this viewport wants*, and `loadFont`, which makes a `fontFamily` prop real.
|
|
5
5
|
|
|
6
6
|
## When to use
|
|
7
7
|
- Layout that changes between phone and desktop (`device`, `dimensions`).
|
|
8
|
+
- One value per viewport (`pick({ xs: 8, md: 16 })`), or a decision that has to agree with `AdaptiveScaffold` (`atLeast("md")`).
|
|
9
|
+
- Rebuild a screen when the viewport *crosses a step*, not when it moves a pixel (`onBreakpointChange`).
|
|
8
10
|
- Show platform-specific UI (`os`).
|
|
9
11
|
- Copy and paste text with one call (`clipboard`).
|
|
10
12
|
- Walk the widget tree (`addNavigation`).
|
|
13
|
+
- Load a webfont before you name it in `fontFamily` (`loadFont`, `fontsReady`).
|
|
11
14
|
|
|
12
15
|
## Import
|
|
13
16
|
|
|
14
17
|
```javascript
|
|
15
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
device, os, dimensions, width, height, clipboard,
|
|
20
|
+
BREAKPOINTS, BREAKPOINT_NAMES, breakpointForWidth,
|
|
21
|
+
currentBreakpoint, atLeast, pick, onBreakpointChange,
|
|
22
|
+
loadFont, fontsReady,
|
|
23
|
+
} from "flet-box";
|
|
16
24
|
```
|
|
17
25
|
|
|
18
26
|
## Objects
|
|
@@ -42,6 +50,67 @@ import { device, os, dimensions, width, height, clipboard } from "flet-box";
|
|
|
42
50
|
|
|
43
51
|
`width` and `height` are also exported directly as numbers.
|
|
44
52
|
|
|
53
|
+
### Breakpoints
|
|
54
|
+
|
|
55
|
+
`dimensions` answers "how wide is the window"; a screen almost always wants the
|
|
56
|
+
next question, "which layout does that width ask for". One table answers it, and
|
|
57
|
+
`md` is 768 — the same line `AdaptiveScaffold` draws between a drawer and a
|
|
58
|
+
permanent sidebar, so a screen and its shell cannot disagree.
|
|
59
|
+
|
|
60
|
+
| Function | Signature | Description |
|
|
61
|
+
| --- | --- | --- |
|
|
62
|
+
| `BREAKPOINTS` | `{ xs, sm, md, lg, xl }` | The widths in **CSS pixels** (0 · 560 · 768 · 1024 · 1280). A viewport is not a framework unit: it does not scale with the reader's font, and pretending otherwise puts a phone layout on a desktop. |
|
|
63
|
+
| `BREAKPOINT_NAMES` | `['xs' … 'xl']` | The same names in width order. |
|
|
64
|
+
| `currentBreakpoint()` | `() => Breakpoint` | The step the live window is in. `"xs"` where there is no window, so a Node import never throws. |
|
|
65
|
+
| `breakpointForWidth(px)` | `(px: number) => Breakpoint` | The pure read behind it — a test, or a width that is not the viewport (an embed's container). |
|
|
66
|
+
| `atLeast(name)` | `(name: Breakpoint) => boolean` | `atLeast("md")` is the sentence a two-column layout needs. |
|
|
67
|
+
| `pick(values, fallback?)` | `(Record<Breakpoint, T>, T) => T` | A value per step. An unnamed step inherits the nearest smaller one: `pick({ xs: 8, md: 16 })` reads 8, 8, 16, 16, 16. |
|
|
68
|
+
| `onBreakpointChange(listener)` | `(cb) => () => void` | Fires when the *name* changes, not on every pixel of a resize. Returns the unsubscribe; hand it to the widget's `onUnmount` so the subscription dies with the screen. |
|
|
69
|
+
|
|
70
|
+
```javascript
|
|
71
|
+
// One screen, two shapes, no second codebase.
|
|
72
|
+
const gutter = pick({ xs: 16, md: 24, lg: 32 });
|
|
73
|
+
|
|
74
|
+
const items = atLeast("md")
|
|
75
|
+
? [listPane, detailPane]
|
|
76
|
+
: [currentPane];
|
|
77
|
+
|
|
78
|
+
const [name, setName] = useState("bp", currentBreakpoint());
|
|
79
|
+
const header = Column({ padding: gutter, children: [Text({ text: name })] });
|
|
80
|
+
header.onUnmount(onBreakpointChange(setName));
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
A breakpoint is a *decision*, not a device. `device.isMobile()` reads a user
|
|
84
|
+
agent, which a desktop in a narrow window cannot change and a tablet on desktop
|
|
85
|
+
mode will not admit; `currentBreakpoint()` reads the width the app actually has.
|
|
86
|
+
Use the width for layout and the UA only for a genuinely platform question (touch
|
|
87
|
+
long-press, a native back gesture).
|
|
88
|
+
|
|
89
|
+
### Fonts
|
|
90
|
+
|
|
91
|
+
`fontFamily` is a name. If the bytes of that face are not on the machine, the
|
|
92
|
+
browser paints its fallback and the app ships a typeface nobody chose.
|
|
93
|
+
|
|
94
|
+
| Function | Signature | Description |
|
|
95
|
+
| --- | --- | --- |
|
|
96
|
+
| `loadFont(family, options?)` | `(string, { weights?, url?, display? }) => Promise<boolean>` | Ask for a family. `weights` is required for a Google family if you want anything but 400 — a heading needs its weight asked for by name. `url` loads your own stylesheet instead of a provider's, which is the same-origin answer an offline launch keeps. Resolves `false` when the face could not be had; the screen keeps its fallback instead of failing. |
|
|
97
|
+
| `fontsReady()` | `() => Promise<boolean>` | Wait for the faces already started. Use it before a canvas paint or an export, where text that reflows *after* the drawing is a visible bug. |
|
|
98
|
+
|
|
99
|
+
```javascript
|
|
100
|
+
import { Text, loadFont } from "flet-box";
|
|
101
|
+
|
|
102
|
+
const body = Text({ text: "Reading", fontFamily: "Georgia, serif" });
|
|
103
|
+
|
|
104
|
+
// One request per family, whoever asks first.
|
|
105
|
+
loadFont("Inter", { weights: [400, 600] }).then((ok) => {
|
|
106
|
+
if (ok) body.style.fontFamily = "Inter, Georgia, serif";
|
|
107
|
+
});
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
> A webfont is a network request. A self-hosted `@font-face` in the app's own CSS
|
|
111
|
+
> is free of that and is the right answer for a product; a provider URL is fine
|
|
112
|
+
> for a demo and is what a tunnel, a firewall or an offline launch breaks on.
|
|
113
|
+
|
|
45
114
|
### `os`
|
|
46
115
|
|
|
47
116
|
| Method | Returns | Description |
|
|
@@ -111,7 +180,10 @@ dimensions.addListener(({ width, height }) => {
|
|
|
111
180
|
|
|
112
181
|
## Notes
|
|
113
182
|
|
|
114
|
-
- `dimensions` subscribes to window resize internally; `addListener` returns an **unsubscribe function** — call it when the feature is destroyed to avoid leaks. Same for `device.onResize`/`onOrientationChange`.
|
|
183
|
+
- `dimensions` subscribes to window resize internally; `addListener` returns an **unsubscribe function** — call it when the feature is destroyed to avoid leaks. Same for `device.onResize`/`onOrientationChange` and `onBreakpointChange`.
|
|
184
|
+
- `onBreakpointChange` keeps **one** window listener for the whole app and fires only when the step name changes. Subscribing per card would still be one listener, but each callback would run on every pixel — a `Row` that re-renders on a pixel can change the scrollbar and resize the window again.
|
|
185
|
+
- `BREAKPOINTS` are pixels by design. Everything else about a FletBox screen is a framework unit that grows with the reader's font; the viewport is the browser's own number and the layout switch has to be in the same currency as the window.
|
|
186
|
+
- `loadFont` is idempotent per family and never rejects: a blocked request resolves `false`, and the app keeps its fallback. It writes a `<link>` into `document.head`, so a page with a strict CSP needs that host allowed — a self-hosted `url` avoids the question entirely.
|
|
115
187
|
- `clipboard.read()` requires a user gesture in most browsers (it uses the same rules as `navigator.clipboard`).
|
|
116
188
|
- `addNavigation` is idempotent — calling it twice on a widget is safe, and widgets already expose these members when they are built by the factory.
|
|
117
189
|
- `os` also detects mobile/desktop families, which `device` derives for touch+screen decisions.
|
|
@@ -1,17 +1,32 @@
|
|
|
1
1
|
# Text & time
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
|
-
Small pure helpers for strings, dates, and
|
|
4
|
+
Small pure helpers for strings, dates, waiting and repeating. They take a value
|
|
5
|
+
and return a formatted one — no side effects, except the four that hand back a
|
|
6
|
+
timer id or a promise.
|
|
5
7
|
|
|
6
8
|
## When to use
|
|
7
9
|
- Normalize user names or titles before display (`capitalize`, `truncate`).
|
|
8
|
-
- Show friendly dates and "2 minutes ago" labels.
|
|
10
|
+
- Show friendly dates, weekday names and "2 minutes ago" labels.
|
|
11
|
+
- Step a date by a calendar day, or measure the gap between two.
|
|
12
|
+
- Wait for a condition or an element without writing the poll loop twice.
|
|
9
13
|
- Format audio/video positions in player UIs.
|
|
10
14
|
|
|
11
15
|
## Import
|
|
12
16
|
|
|
13
17
|
```javascript
|
|
14
|
-
import {
|
|
18
|
+
import {
|
|
19
|
+
capitalize,
|
|
20
|
+
truncate,
|
|
21
|
+
formatDate,
|
|
22
|
+
formatDateLong,
|
|
23
|
+
addDays,
|
|
24
|
+
dateDiff,
|
|
25
|
+
relativeTime,
|
|
26
|
+
seconds,
|
|
27
|
+
sleep,
|
|
28
|
+
everySecond,
|
|
29
|
+
} from "flet-box";
|
|
15
30
|
```
|
|
16
31
|
|
|
17
32
|
## Functions
|
|
@@ -20,6 +35,12 @@ import { capitalize, truncate, formatDate, relativeTime } from "flet-box";
|
|
|
20
35
|
|
|
21
36
|
| Function | Signature | Returns | Description |
|
|
22
37
|
| --- | --- | --- | --- |
|
|
38
|
+
| `startsWith` | `startsWith(str, prefix)` | `boolean` | Whether `str` begins with `prefix`. |
|
|
39
|
+
| `endsWith` | `endsWith(str, suffix)` | `boolean` | Whether `str` ends with `suffix`. |
|
|
40
|
+
| `includes` | `includes(str, substr)` | `boolean` | Whether `str` contains `substr`. |
|
|
41
|
+
| `split` | `split(str, separator)` | `string[]` | Text into parts. |
|
|
42
|
+
| `join` | `join(arr, separator?)` | `string` | Parts back into text. |
|
|
43
|
+
| `trim` | `trim(str)` | `string` | Leading and trailing whitespace removed. |
|
|
23
44
|
| `capitalize` | `capitalize(str)` | `string` | First letter uppercase. |
|
|
24
45
|
| `capitalizeWords` | `capitalizeWords(str)` | `string` | First letter of every word uppercase. |
|
|
25
46
|
| `lowerCase` | `lowerCase(str)` | `string` | All lowercase. |
|
|
@@ -27,13 +48,66 @@ import { capitalize, truncate, formatDate, relativeTime } from "flet-box";
|
|
|
27
48
|
| `reverseString` | `reverseString(str)` | `string` | Reversed text. |
|
|
28
49
|
| `truncate` | `truncate(str, length?, suffix?)` | `string` | Cut to `length` characters and append `suffix` (default `"..."`). |
|
|
29
50
|
|
|
51
|
+
### Units
|
|
52
|
+
|
|
53
|
+
Every one of these takes a count and returns **milliseconds**, so it reads as a
|
|
54
|
+
sentence at the call site: `waitFor(seconds(30))`, `now() - days(2)`.
|
|
55
|
+
|
|
56
|
+
| Function | Signature | Returns |
|
|
57
|
+
| --- | --- | --- |
|
|
58
|
+
| `seconds` | `seconds(n)` | `n * 1000` |
|
|
59
|
+
| `minutes` | `minutes(n)` | `n * 60 * 1000` |
|
|
60
|
+
| `hours` | `hours(n)` | `n * 60 * 60 * 1000` |
|
|
61
|
+
| `days` | `days(n)` | `n * 24 * 60 * 60 * 1000` |
|
|
62
|
+
| `weeks` | `weeks(n)` | `7 * days(n)` |
|
|
63
|
+
| `months` | `months(n)` | `30 * days(n)` — an approximation, on purpose |
|
|
64
|
+
| `years` | `years(n)` | `365 * days(n)` — an approximation, on purpose |
|
|
65
|
+
|
|
66
|
+
`months()` and `years()` are calendar lies told for arithmetic: use them for a
|
|
67
|
+
cache window or a retry backoff, never for an age or a birthday.
|
|
68
|
+
|
|
30
69
|
### Dates & time
|
|
31
70
|
|
|
32
71
|
| Function | Signature | Returns | Description |
|
|
33
72
|
| --- | --- | --- | --- |
|
|
34
|
-
| `formatDate` | `formatDate(date, format?)` | `string` | Format a date/string/number as text. |
|
|
35
|
-
| `relativeTime` | `relativeTime(date)` | `string` | A human label, e.g. `"2 minutes ago"`. |
|
|
36
73
|
| `now` | `now()` | `number` | Timestamp in milliseconds. |
|
|
74
|
+
| `today` | `today()` | `string` | This day as `"YYYY-MM-DD"`. |
|
|
75
|
+
| `yesterday` | `yesterday()` | `string` | Yesterday as `"YYYY-MM-DD"`. |
|
|
76
|
+
| `tomorrow` | `tomorrow()` | `string` | Tomorrow as `"YYYY-MM-DD"`. |
|
|
77
|
+
| `dayOfWeek` | `dayOfWeek(date)` | `string` | Full weekday name, e.g. `"Monday"`. |
|
|
78
|
+
| `monthName` | `monthName(date)` | `string` | Full month name, e.g. `"January"`. |
|
|
79
|
+
| `isToday` | `isToday(date)` | `boolean` | Same calendar day as now. |
|
|
80
|
+
| `isYesterday` | `isYesterday(date)` | `boolean` | The day before now. |
|
|
81
|
+
| `isTomorrow` | `isTomorrow(date)` | `boolean` | The day after now. |
|
|
82
|
+
| `isWeekend` | `isWeekend(date)` | `boolean` | Saturday or Sunday. |
|
|
83
|
+
| `isLeapYear` | `isLeapYear(year)` | `boolean` | Whether a four-digit year has a February 29. |
|
|
84
|
+
| `formatDate` | `formatDate(date, format?)` | `string` | Tokens `YYYY MM DD HH mm ss`; anything else passes through. |
|
|
85
|
+
| `formatDateLong` | `formatDateLong(date, locale?)` | `string` | `"Monday, January 15, 2024"`. |
|
|
86
|
+
| `formatDateShort` | `formatDateShort(date, locale?)` | `string` | `"Jan 15, 2024"`. |
|
|
87
|
+
| `formatTime` | `formatTime(date)` | `string` | 24-hour `"14:05:30"`. |
|
|
88
|
+
| `formatTimeAmPm` | `formatTimeAmPm(date)` | `string` | 12-hour `"02:05:30 PM"`. |
|
|
89
|
+
| `parseDate` | `parseDate(str, format?)` | `Date` | Reads `"15/01/2024"` with `"DD/MM/YYYY"`. |
|
|
90
|
+
| `dateDiff` | `dateDiff(a, b, unit?)` | `number` | Absolute difference; `unit` is one of the names above. |
|
|
91
|
+
| `addDays` | `addDays(date, n)` | `Date` | `n` calendar days along (negative goes back). |
|
|
92
|
+
| `addHours` / `addMinutes` / `addSeconds` | `addHours(date, n)` | `Date` | Elapsed time, not calendar time. |
|
|
93
|
+
| `subtractDays` / `subtractHours` / `subtractMinutes` / `subtractSeconds` | `subtractDays(date, n)` | `Date` | The same steps backwards. |
|
|
94
|
+
| `timeAgo` | `timeAgo(date)` | `string` | `"5 minutes ago"`, `"just now"` under a second. |
|
|
95
|
+
| `relativeTime` | `relativeTime(date)` | `string` | Alias of `timeAgo`. |
|
|
96
|
+
| `timeAgoLocale` | `timeAgoLocale(date, locale?)` | `string` | The same label in `"en"` or `"es"` — `"hace 1 hora"`. |
|
|
97
|
+
| `waitFor` | `waitFor(ms)` | `Promise<void>` | Resolves after `ms`. |
|
|
98
|
+
| `wait` / `sleep` | `sleep(ms)` | `Promise<void>` | Aliases of `waitFor`. |
|
|
99
|
+
| `waitUntil` | `waitUntil(condition, timeout?, interval?)` | `Promise<true>` | Polls `condition`; **throws** at the timeout (default 30s, 1s apart). |
|
|
100
|
+
| `waitForElement` | `waitForElement(selector, timeout?, interval?)` | `Promise<Element>` | Polls the DOM; needs a document, so call it from a screen (default 10s, 0.5s apart). |
|
|
101
|
+
| `timer` | `timer(label)` | `{ stop, elapsed }` | `stop()` logs and returns the milliseconds; `elapsed()` reads without logging. |
|
|
102
|
+
| `every` | `every(ms, callback)` | `number` | `setInterval` with the duration first. Release the id it returns. |
|
|
103
|
+
| `everySecond` / `everyMinute` / `everyHour` / `everyDay` | `everySecond(callback)` | `number` | The same, at a named period. |
|
|
104
|
+
|
|
105
|
+
`date` is a `Date`, a timestamp, or a string. A bare `"YYYY-MM-DD"` is read as a
|
|
106
|
+
**calendar day in the reader's own zone**, so `isToday(today())` is true on every
|
|
107
|
+
machine; a string with an offset or a `Z` is read as an instant, and a formatter
|
|
108
|
+
then prints it in local time. `addDays` counts days on the calendar, which is why
|
|
109
|
+
it survives a DST night, while `addHours` counts real elapsed time — the right
|
|
110
|
+
choice for a countdown and the wrong one for "this time next week".
|
|
37
111
|
|
|
38
112
|
### Media time
|
|
39
113
|
|
|
@@ -58,6 +132,40 @@ Text({
|
|
|
58
132
|
// "Hello Fletbox — 2 minutes ago"
|
|
59
133
|
```
|
|
60
134
|
|
|
135
|
+
### A due date, read as a day
|
|
136
|
+
|
|
137
|
+
```javascript
|
|
138
|
+
import { addDays, dateDiff, dayOfWeek, formatDate, isWeekend, timeAgoLocale } from "flet-box";
|
|
139
|
+
|
|
140
|
+
const due = addDays(new Date(), 7);
|
|
141
|
+
const label = `${dayOfWeek(due)}, ${formatDate(due, "DD MMM")} · in ${dateDiff(new Date(), due, "days")} days`;
|
|
142
|
+
const note = isWeekend(due) ? " (it lands on a weekend)" : "";
|
|
143
|
+
|
|
144
|
+
Text({ text: label + note });
|
|
145
|
+
Text({ text: timeAgoLocale(Date.now() - seconds(90), "es") }); // "hace 1 minuto"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Waiting, and releasing what repeats
|
|
149
|
+
|
|
150
|
+
```javascript
|
|
151
|
+
import { Column, Text, everySecond, formatTime, now, seconds, useState, waitUntil } from "flet-box";
|
|
152
|
+
|
|
153
|
+
export const ClockScreen = () => {
|
|
154
|
+
const [clock, setClock] = useState("clock", formatTime(now()));
|
|
155
|
+
const root = Column({ children: [Text({ text: clock })] });
|
|
156
|
+
|
|
157
|
+
const tick = everySecond(() => setClock(formatTime(now())));
|
|
158
|
+
// R6: a repeating helper hands back an id, and the screen releases it.
|
|
159
|
+
root.onUnmount(() => clearInterval(tick));
|
|
160
|
+
|
|
161
|
+
waitUntil(() => navigator.onLine, seconds(30), seconds(1))
|
|
162
|
+
.then(() => setClock("back online"))
|
|
163
|
+
.catch(() => setClock("still offline")); // waitUntil throws at its timeout
|
|
164
|
+
|
|
165
|
+
return root;
|
|
166
|
+
};
|
|
167
|
+
```
|
|
168
|
+
|
|
61
169
|
### Full example
|
|
62
170
|
|
|
63
171
|
```javascript
|
|
@@ -69,7 +177,9 @@ const label = formatMediaProgress(90, 300); // "1:30 / 5:00"
|
|
|
69
177
|
|
|
70
178
|
## Notes
|
|
71
179
|
|
|
72
|
-
- `formatDate(date, format?)` accepts a `Date`, a timestamp, or a date string
|
|
180
|
+
- `formatDate(date, format?)` accepts a `Date`, a timestamp, or a date string. The tokens it reads are `YYYY MM DD HH mm ss`; it has no `ddd`, so build a weekday name with `dayOfWeek()`.
|
|
181
|
+
- `waitUntil()` and `waitForElement()` **throw** on their timeout — await them inside a `try`, or attach a `.catch`.
|
|
182
|
+
- `every()`, `everySecond()` and friends return a `setInterval` id. Per the working contract, whatever a screen registers it also releases in `onUnmount`.
|
|
73
183
|
- The media-time helpers are used by the [Audio](../widget/Audio.md) and [Video](../widget/Video.md) widgets.
|
|
74
184
|
- All functions return new values — inputs are never modified.
|
|
75
185
|
|
package/docs/widget/Accordion.md
CHANGED
|
@@ -130,6 +130,8 @@ const faq = Accordion({
|
|
|
130
130
|
|
|
131
131
|
- onToggle receives the new expanded boolean whenever the header is activated.
|
|
132
132
|
- disabled blocks toggling, and animate: false skips the open/close transition.
|
|
133
|
+
- A shut panel still shows its edge: the header keeps the divider and the
|
|
134
|
+
- 'contained' variant paints the raised plate, so it never reads as plain text.
|
|
133
135
|
|
|
134
136
|
## Related widgets
|
|
135
137
|
|
|
@@ -9,9 +9,9 @@ Use it to animate a widget's position, transform, color, or size without hand-wr
|
|
|
9
9
|
## Quick start
|
|
10
10
|
|
|
11
11
|
```javascript
|
|
12
|
-
import { AnimatedBox, Text
|
|
12
|
+
import { AnimatedBox, Text } from "flet-box";
|
|
13
13
|
|
|
14
|
-
const
|
|
14
|
+
const badge = AnimatedBox({
|
|
15
15
|
child: Text({ text: "Hello" }),
|
|
16
16
|
animations: [{ effect: "scale", from: 1, to: 1.2 }],
|
|
17
17
|
});
|
|
@@ -23,10 +23,10 @@ const pulse = AnimatedBox({
|
|
|
23
23
|
|
|
24
24
|
| Prop | Type | Description |
|
|
25
25
|
| --- | --- | --- |
|
|
26
|
-
| `animations` | `AnimationStep[]` |
|
|
26
|
+
| `animations` | `AnimationStep[]` | The steps to play, each `{ effect, from, to }` plus its own `duration`, `delay`, `loop` and `reverse`. |
|
|
27
27
|
| `child` | `Widget` | A single child widget. Alias: `children` for a list. |
|
|
28
|
-
| `timing` | `string` | Timing function for the animation. |
|
|
29
|
-
| `delay` | `string` |
|
|
28
|
+
| `timing` | `string` | Timing function for the animation, passed straight to CSS. |
|
|
29
|
+
| `delay` | `number \| string` | Default delay for the steps that do not name one: milliseconds as a number, or a CSS time as a string (`"0.2s"`). |
|
|
30
30
|
| `fillMode` | `string` | How styles persist before and after the animation (CSS `fill-mode`). |
|
|
31
31
|
| `top` | `number \| string` | The `top` value for the widget. |
|
|
32
32
|
| `right` | `number \| string` | The `right` value for the widget. |
|
|
@@ -87,9 +87,14 @@ import { AnimatedBox, Text } from "flet-box";
|
|
|
87
87
|
|
|
88
88
|
const toast = AnimatedBox({
|
|
89
89
|
child: Text({ text: "Saved" }),
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
90
|
+
// Each step keeps its own clock: the fade is over while the lift is still moving.
|
|
91
|
+
animations: [
|
|
92
|
+
{ effect: "opacity", from: 0, to: 1, duration: 200 },
|
|
93
|
+
{ effect: "translateY", from: 16, to: 0, duration: 400, delay: 120 },
|
|
94
|
+
{ effect: "backgroundColor", from: "#fef3c7", to: "#ffffff", duration: 600 },
|
|
95
|
+
],
|
|
96
|
+
timing: "ease-out",
|
|
97
|
+
delay: 200,
|
|
93
98
|
fillMode: "forwards",
|
|
94
99
|
top: 16,
|
|
95
100
|
right: 16,
|
|
@@ -98,24 +103,45 @@ const toast = AnimatedBox({
|
|
|
98
103
|
|
|
99
104
|
## Tips
|
|
100
105
|
|
|
101
|
-
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
106
|
+
- A step is `{ effect, from, to }`, where the effect is one of `scale`, `scaleX`,
|
|
107
|
+
`scaleY`, `rotate`, `rotateX`, `rotateY`, `rotateZ`, `skewX`, `skewY`, `translateX`,
|
|
108
|
+
`translateY`, `translateZ`, `opacity`, `color`, `backgroundColor`, `borderColor`,
|
|
109
|
+
`borderWidth`, `borderRadius`, `width`, `height`, `boxShadow`, `background` or
|
|
110
|
+
`textGradient` (the margin and padding steps work as well). A name outside that list
|
|
111
|
+
does nothing, silently.
|
|
112
|
+
- Each step's `duration`, `delay` and `loop` are read off **that step**:
|
|
113
|
+
a 600 ms `scale` and a 400 ms `opacity` in one entrance run together for 600 ms,
|
|
114
|
+
with the fade holding from 400 ms on. Times are milliseconds as a number
|
|
115
|
+
(`duration: 400`) or a CSS time as a string (`delay: "0.4s"`); a bare number as a
|
|
116
|
+
`delay` used to make the whole `animation` shorthand invalid, which read as the
|
|
117
|
+
widget not animating at all.
|
|
118
|
+
- `reverse: true` makes a step swing back to `from` instead of holding `to`; with
|
|
119
|
+
`loop: true` it breathes.
|
|
120
|
+
- A looping step and a one-shot step cannot share one `@keyframes` rule — repeating
|
|
121
|
+
the rule repeats the entrance — so they are generated as two rules. Two rules
|
|
122
|
+
cannot compose one `transform`, so keep every transform step in one group: mixing
|
|
123
|
+
a looping `rotate` with a one-shot `translateY` moves only one of them, and the
|
|
124
|
+
widget warns about it.
|
|
125
|
+
- A length is a framework unit, not a pixel: `translateY: 20` is `20 / base-font-size`
|
|
126
|
+
rem, so the movement grows with the reader's font like the rest of the UI.
|
|
127
|
+
- `top`, `right`, `bottom` and `left` are forwarded to the child's dataset as
|
|
128
|
+
positioning hints for layout systems.
|
|
107
129
|
|
|
108
130
|
## Accessibility
|
|
109
131
|
|
|
110
|
-
-
|
|
111
|
-
-
|
|
132
|
+
- Nothing to do here: the engine reads `prefers-reduced-motion` and the
|
|
133
|
+
[motion mode](../tools/animation.md#reduced-motion), and a looping or entering
|
|
134
|
+
step collapses to one frame that lands on its `to` values, so content is never
|
|
135
|
+
held invisible behind an animation the reader refused.
|
|
112
136
|
|
|
113
137
|
## Behavior
|
|
114
138
|
|
|
115
|
-
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
-
|
|
139
|
+
- Every step's `from` is written on the element before its rule starts, including
|
|
140
|
+
the ones that begin later — so there is no flash of the final state before the
|
|
141
|
+
keyframes run, and no flash of the *first* step's end while a delayed step waits.
|
|
142
|
+
- Generated `@keyframes` are named by their content and injected once, so a sequence
|
|
143
|
+
repeated — or one word staggered across `AnimatedText` letters — reuses one rule
|
|
144
|
+
instead of adding a `<style>` per call.
|
|
119
145
|
|
|
120
146
|
## Related widgets
|
|
121
147
|
|
|
@@ -24,9 +24,9 @@ const title = AnimatedText({
|
|
|
24
24
|
| Prop | Type | Description |
|
|
25
25
|
| --- | --- | --- |
|
|
26
26
|
| `child` | `Widget` | A single child widget. Alias: `children` for a list. |
|
|
27
|
-
| `animations` | `AnimationStep[]` |
|
|
27
|
+
| `animations` | `AnimationStep[]` | The steps to play, each `{ effect, from, to }` plus its own `duration`, `delay`, `loop` and `reverse`. |
|
|
28
28
|
| `sameTime` | `boolean` | Runs child animations at the same time. |
|
|
29
|
-
| `delayBetween` | `number` | Stagger
|
|
29
|
+
| `delayBetween` | `number` | Stagger between each child animation, in seconds (`0.05` is 50 ms). |
|
|
30
30
|
| `orientation` | `'row' \| 'column'` | Orientation of the widget or control. |
|
|
31
31
|
|
|
32
32
|
### Common props
|
|
@@ -92,11 +92,17 @@ const title = AnimatedText({
|
|
|
92
92
|
|
|
93
93
|
## Tips
|
|
94
94
|
|
|
95
|
-
- child must be a Text widget, because its text is split into single-character
|
|
96
|
-
|
|
97
|
-
- Set sameTime: false and control delayBetween to create a wave; use
|
|
98
|
-
|
|
99
|
-
|
|
95
|
+
- `child` must be a Text widget, because its text is split into single-character
|
|
96
|
+
widgets that inherit the original props.
|
|
97
|
+
- Set `sameTime: false` and control `delayBetween` to create a wave; use
|
|
98
|
+
`sameTime: true` for a synchronized pop. `delayBetween` is in **seconds** —
|
|
99
|
+
`0.05` staggers the letters 50 ms apart, while `5` is a five-second wait per
|
|
100
|
+
character.
|
|
101
|
+
- The letters share one generated `@keyframes` rule and each carries its own delay,
|
|
102
|
+
so a staggered headline costs one rule, not one per character.
|
|
103
|
+
- `orientation: "column"` stacks the letters vertically for vertical-word effects.
|
|
104
|
+
- Each step is [AnimatedBox's](AnimatedBox.md) step, so a per-letter `duration`
|
|
105
|
+
belongs to the step, not to the widget.
|
|
100
106
|
|
|
101
107
|
## Accessibility
|
|
102
108
|
|
package/docs/widget/Badge.md
CHANGED
|
@@ -114,6 +114,7 @@ const inbox = Badge({
|
|
|
114
114
|
|
|
115
115
|
- showZero: false hides the marker entirely when value is 0.
|
|
116
116
|
- A borderWidth with a matching borderColor creates a clean cutout against the child.
|
|
117
|
+
- The wrapper is the child's box: it shrinks to the child and refuses a flex parent's cross-axis stretch, so every `position` anchors on a corner of the child and not on the edge of the row it happens to sit in.
|
|
117
118
|
|
|
118
119
|
## Related widgets
|
|
119
120
|
|
|
@@ -47,6 +47,7 @@ natural. Each group below maps to the same underlying style or behavior:
|
|
|
47
47
|
| `flexDirection` | `direction` | CSS `flex-direction` |
|
|
48
48
|
| `justifyContent` | `justify` | CSS `justify-content` |
|
|
49
49
|
| `alignItems` | `align` | CSS `align-items` |
|
|
50
|
+
| `alignSelf` | `selfAlign` | CSS `align-self` (one child's own answer to `alignItems`) |
|
|
50
51
|
| `flexWrap` | `wrap` | CSS `flex-wrap` |
|
|
51
52
|
| `lineHeight` | `lineH` | CSS `line-height` |
|
|
52
53
|
| `letterSpacing` | `letterSpace` | CSS `letter-spacing` |
|
|
@@ -70,9 +71,31 @@ These expand to two sides at once (numeric values are pixels):
|
|
|
70
71
|
## Layout and display
|
|
71
72
|
|
|
72
73
|
`display`, `flexDirection` (`direction`), `justifyContent` (`justify`),
|
|
73
|
-
`alignItems` (`align`), `
|
|
74
|
-
`
|
|
75
|
-
`position` (`pos`), `top`, `right`, `bottom`, `left`,
|
|
74
|
+
`alignItems` (`align`), `alignSelf` (`selfAlign`), `flexWrap` (`wrap`), `flex`,
|
|
75
|
+
`flexGrow`, `flexShrink`, `flexBasis`, `gap`, `boxSizing`, `overflow`,
|
|
76
|
+
`overflowX`, `overflowY`, `position` (`pos`), `top`, `right`, `bottom`, `left`,
|
|
77
|
+
`inset`, `zIndex` (`z`).
|
|
78
|
+
|
|
79
|
+
### One child, its own alignment
|
|
80
|
+
|
|
81
|
+
`alignItems` is the parent's answer for every child; `alignSelf` is one child's
|
|
82
|
+
answer for itself. The values are CSS's: `'auto'` (inherit the parent),
|
|
83
|
+
`'flex-start'`, `'center'`, `'flex-end'`, `'baseline'`, `'stretch'`. It goes on
|
|
84
|
+
the child, on any widget — `alignSelf` is a `CommonProps` entry, not a layout
|
|
85
|
+
prop — and it is what keeps a short label from being stretched to the full height
|
|
86
|
+
of a row of inputs:
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
Row({
|
|
90
|
+
alignItems: 'stretch',
|
|
91
|
+
gap: 8,
|
|
92
|
+
children: [
|
|
93
|
+
Input({ label: 'Coupon', value: '', onChange: () => {} }),
|
|
94
|
+
// The row stretches its children; this one refuses.
|
|
95
|
+
Button({ text: 'Apply', onPress: () => {}, alignSelf: 'flex-end' }),
|
|
96
|
+
],
|
|
97
|
+
});
|
|
98
|
+
```
|
|
76
99
|
|
|
77
100
|
### Stack positioning
|
|
78
101
|
|
package/docs/widget/Chart.md
CHANGED
|
@@ -136,6 +136,7 @@ const trend = Chart({
|
|
|
136
136
|
## Behavior
|
|
137
137
|
|
|
138
138
|
- The canvas redraws when data, labels, type or styling props change.
|
|
139
|
+
- Grid lines and their labels sit on one round step (1, 2 or 5 times a power of ten), so the numbers agree with the lines they name.
|
|
139
140
|
- Candle charts read open, high, low and close in that order from each data object.
|
|
140
141
|
|
|
141
142
|
## Related widgets
|
package/docs/widget/Checkbox.md
CHANGED
|
@@ -28,6 +28,7 @@ const terms = Checkbox({
|
|
|
28
28
|
| `size` | `number` | Overall size preset or pixel value, depending on the widget. |
|
|
29
29
|
| `activeColor` | `Color` | Color used in the active state. |
|
|
30
30
|
| `label` | `string` | Label or caption shown near the control. |
|
|
31
|
+
| `variant` | `'outlined' \| 'filled'` | How the checked state reads: `outlined` keeps the box hollow with the tick in `activeColor`, `filled` turns the box into an `activeColor` plate and takes the tick to whichever ink reads on it. |
|
|
31
32
|
|
|
32
33
|
### Common props
|
|
33
34
|
|
|
@@ -80,10 +81,11 @@ const remember = Checkbox({
|
|
|
80
81
|
import { Checkbox } from "flet-box";
|
|
81
82
|
|
|
82
83
|
const updates = Checkbox({
|
|
83
|
-
checked:
|
|
84
|
+
checked: true,
|
|
84
85
|
label: "Email me product updates",
|
|
85
86
|
size: 24,
|
|
86
87
|
activeColor: "#7c3aed",
|
|
88
|
+
variant: "filled",
|
|
87
89
|
disabled: false,
|
|
88
90
|
onCheck: (checked) => {
|
|
89
91
|
console.log("updates:", checked);
|
|
@@ -95,6 +97,7 @@ const updates = Checkbox({
|
|
|
95
97
|
|
|
96
98
|
- Use Checkbox inside forms where several options may be true together; use Switch for one immediate on/off setting.
|
|
97
99
|
- onCheck fires with the new boolean, so write it straight into your state.
|
|
100
|
+
- A filled checkbox needs no second color: `activeColor` is the plate and the tick reads itself on it.
|
|
98
101
|
|
|
99
102
|
## Accessibility
|
|
100
103
|
|
|
@@ -104,6 +107,9 @@ const updates = Checkbox({
|
|
|
104
107
|
|
|
105
108
|
- Uncontrolled when checked is omitted; the widget tracks its own state and reports changes through onCheck.
|
|
106
109
|
- The returned element exposes setChecked(value) and getChecked() for programmatic control.
|
|
110
|
+
- `size` is the edge of the drawn box; the press target around it stays 40 units and does not shrink with it.
|
|
111
|
+
- The box carries a step of the radius scale (4 by default, 8 from `size: 28`), and a `borderRadius` rounds the box rather than the invisible target around it.
|
|
112
|
+
- `variant: 'filled'` changes the checked state only: the box becomes an `activeColor` plate and the tick takes whichever ink reads on it. An unchecked box keeps its rim, because a filled box that means off is a button.
|
|
107
113
|
|
|
108
114
|
## Related widgets
|
|
109
115
|
|
|
@@ -148,6 +148,8 @@ const chart = CircularChart({
|
|
|
148
148
|
## Behavior
|
|
149
149
|
|
|
150
150
|
- centerContent accepts a string or a widget rendered in the donut hole.
|
|
151
|
+
- The hole is the page showing through, not a filled disc, so a donut reads
|
|
152
|
+
- as a ring on any surface.
|
|
151
153
|
- onHover receives (slice | null, index) as the pointer moves between slices, and
|
|
152
154
|
- onComplete fires when the entry sweep finishes.
|
|
153
155
|
|
package/docs/widget/Drawer.md
CHANGED
|
@@ -116,6 +116,7 @@ openDrawer();
|
|
|
116
116
|
- The drawer keeps itself sized to the viewport on resize (`dimensions.addListener`), and `destroy()` removes that listener and the `keydown` handler.
|
|
117
117
|
- When you pass `drawer` to a [Scaffold](Scaffold.md), a `menu` icon in the [AppBar](AppBar.md) opens it, `closeDrawerOnNavigate` can close it on route change, and the shell tears it down with its `_cleanup`.
|
|
118
118
|
- Keydown (`Escape`) and resize listeners are only active while the drawer exists or is open — no leaks on the normal lifecycle.
|
|
119
|
+
- The panel paints the screen edge to edge and pads its content by `env(safe-area-inset-*)`, so on a notched phone the `header` clears the status bar and the `footer` clears the home indicator without the background leaving a gap. Nothing has to be configured, and the `width`/`height` of the panel stay what you passed: the padding is inside the box (`border-box`). On a device with no inset the values are `0`, so the drawer looks exactly as it did.
|
|
119
120
|
|
|
120
121
|
## Related widgets
|
|
121
122
|
- [DrawerItem](DrawerItem.md)
|
package/docs/widget/GridView.md
CHANGED
|
@@ -41,6 +41,7 @@ const grid = GridView({
|
|
|
41
41
|
| `columns` | `number` | Number of grid columns. |
|
|
42
42
|
| `spacing` | `number` | Space between grid items. |
|
|
43
43
|
| `itemHeight` | `number` | Height of each grid cell. |
|
|
44
|
+
| `children` | `Widget[] \| Widget` | The cells themselves, laid out `columns` per row. The same contract as `data` + `renderItem` read the other way round: pass built widgets here, or the items plus a builder. `data` wins when both are given. |
|
|
44
45
|
|
|
45
46
|
### Common props
|
|
46
47
|
|
|
@@ -115,7 +116,7 @@ const grid = GridView({
|
|
|
115
116
|
|
|
116
117
|
- `columns` sets the number of columns and `spacing` sets the gap between cells.
|
|
117
118
|
- `itemHeight` fixes each cell's height, which is what makes virtualization possible.
|
|
118
|
-
-
|
|
119
|
+
- Give it `data` + `renderItem` when the cells are built from values, and `children` when you already have the widgets: the two are the same contract read from either end.
|
|
119
120
|
|
|
120
121
|
## Accessibility
|
|
121
122
|
|
|
@@ -124,6 +125,8 @@ const grid = GridView({
|
|
|
124
125
|
## Behavior
|
|
125
126
|
|
|
126
127
|
- GridView is implemented as ListView with grid wrapping enabled, so it shares the same scrolling and update APIs.
|
|
128
|
+
- Each cell is stretched to fill its slot: `itemHeight` tall, with half of `spacing` on every side so two neighbours meet at exactly one gutter. A cell that asks for its own height keeps it.
|
|
129
|
+
- The number of columns is fixed, not a breakpoint: cells are percentages of the container, so the grid adapts to the width it is given.
|
|
127
130
|
- Rows outside the viewport are removed, so keep per-tile state out of the DOM and in widget state when needed.
|
|
128
131
|
|
|
129
132
|
## Related widgets
|
package/docs/widget/Input.md
CHANGED
|
@@ -127,6 +127,7 @@ const password = Input({
|
|
|
127
127
|
|
|
128
128
|
- Match type to the data (email, password, search) so mobile keyboards adapt.
|
|
129
129
|
- Set validation and showValidationMessage to get inline feedback without extra code.
|
|
130
|
+
- The trailing controls are Icon glyphs from the Material face the app links in its own index.html, drawn in the theme's secondary ink. An emoji in that slot ignores the colour, the font and the size the field sets.
|
|
130
131
|
|
|
131
132
|
## Accessibility
|
|
132
133
|
|
|
@@ -137,6 +138,7 @@ const password = Input({
|
|
|
137
138
|
|
|
138
139
|
- onChange fires on every keystroke; onEnter fires when the user presses Enter.
|
|
139
140
|
- clearable and passwordToggle add trailing controls that manage the value for you.
|
|
141
|
+
- passwordToggle swaps visibility for visibility_off and moves the button's accessible name with the state.
|
|
140
142
|
|
|
141
143
|
## Related widgets
|
|
142
144
|
|
|
@@ -23,6 +23,7 @@ const install = InstallButton({
|
|
|
23
23
|
| Prop | Type | Description |
|
|
24
24
|
| --- | --- | --- |
|
|
25
25
|
| `text` | `string` | Visible text content. |
|
|
26
|
+
| `icon` | `string` | Name of the icon to render. |
|
|
26
27
|
| `variant` | `'filled' \| 'outlined' \| 'text'` | Visual variation or style preset. |
|
|
27
28
|
| `size` | `'small' \| 'medium' \| 'large'` | Overall size preset or pixel value, depending on the widget. |
|
|
28
29
|
| `borderRadius` | `number` | Rounds the corners of the widget. |
|
package/docs/widget/Markdown.md
CHANGED
|
@@ -161,6 +161,10 @@ const guide = Markdown({
|
|
|
161
161
|
- CSS into each other.
|
|
162
162
|
- Rendered HTML is sanitized before insert; allowDangerousHtml stays false by default
|
|
163
163
|
- for untrusted input.
|
|
164
|
+
- Inline code writes the palette's readable red, so 12px words clear 4.5:1 on the code
|
|
165
|
+
- plate in both themes.
|
|
166
|
+
- A link takes the palette's readable blue, because in light `primary` is the page's
|
|
167
|
+
- own ink and the link would vanish into the sentence.
|
|
164
168
|
|
|
165
169
|
## Related widgets
|
|
166
170
|
|
package/docs/widget/Rating.md
CHANGED
|
@@ -117,6 +117,8 @@ const rating = Rating({
|
|
|
117
117
|
|
|
118
118
|
- onChange receives the numeric value each time the user picks a rating.
|
|
119
119
|
- readOnly disables onChange while keeping the current value visible.
|
|
120
|
+
- An unfilled star uses the palette's control grey and a filled one its readable
|
|
121
|
+
- amber, so both states clear 3:1 against the surface they sit on.
|
|
120
122
|
|
|
121
123
|
## Related widgets
|
|
122
124
|
|
package/docs/widget/Slider.md
CHANGED
|
@@ -123,6 +123,7 @@ const price = Slider({
|
|
|
123
123
|
|
|
124
124
|
- onChanged fires continuously while dragging; use onChangeEnd for the value to commit, such as a filter request.
|
|
125
125
|
- Set step to snap to meaningful increments instead of every integer.
|
|
126
|
+
- On a vertical slider, width is the rail's length and height its thickness.
|
|
126
127
|
|
|
127
128
|
## Accessibility
|
|
128
129
|
|
|
@@ -132,6 +133,7 @@ const price = Slider({
|
|
|
132
133
|
|
|
133
134
|
- Dragging the track or thumb updates the value and fires onChanged; releasing fires onChangeEnd once.
|
|
134
135
|
- The returned element exposes value, min, max, step, setValue() and getValue(), and disconnects its ResizeObserver on unmount.
|
|
136
|
+
- During a drag the fill follows the pointer with no easing; the 0.1s ease belongs to a value that changes by itself, from a key press or setValue().
|
|
135
137
|
|
|
136
138
|
## Related widgets
|
|
137
139
|
|