flet-box 1.0.7 → 1.0.8

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.
Files changed (136) hide show
  1. package/bin/cli.js +13 -0
  2. package/bin/commands/checkApi.js +13 -1
  3. package/bin/commands/checkUi.js +1369 -0
  4. package/bin/commands/create.js +49 -5
  5. package/bin/commands/createBundle.js +21 -0
  6. package/bin/commands/runServer.js +11 -2
  7. package/bin/utils/pwaShell.js +137 -0
  8. package/bin/utils/templates.js +1373 -434
  9. package/docs/README.md +2 -0
  10. package/docs/cli/README.md +62 -1
  11. package/docs/guides/README.md +2 -0
  12. package/docs/guides/clean-ui.md +211 -0
  13. package/docs/guides/minification-and-protection.md +1 -1
  14. package/docs/guides/online-updates.md +48 -0
  15. package/docs/tools/README.md +1 -1
  16. package/docs/tools/animation.md +1 -1
  17. package/docs/tools/markdown.md +3 -3
  18. package/docs/tools/theme.md +41 -1
  19. package/docs/widget/Accordion.md +3 -0
  20. package/docs/widget/AdMob.md +4 -1
  21. package/docs/widget/AdSense.md +3 -0
  22. package/docs/widget/AnimatedBox.md +6 -3
  23. package/docs/widget/AnimatedText.md +3 -0
  24. package/docs/widget/Audio.md +3 -0
  25. package/docs/widget/Avatar.md +3 -0
  26. package/docs/widget/Badge.md +3 -0
  27. package/docs/widget/Button.md +3 -0
  28. package/docs/widget/COMMON_PROPS.md +52 -0
  29. package/docs/widget/Card.md +3 -0
  30. package/docs/widget/Carousel.md +3 -0
  31. package/docs/widget/Chart.md +3 -0
  32. package/docs/widget/Checkbox.md +3 -0
  33. package/docs/widget/Chip.md +3 -0
  34. package/docs/widget/CircularBar.md +3 -0
  35. package/docs/widget/CircularChart.md +3 -0
  36. package/docs/widget/CodeViewer.md +3 -0
  37. package/docs/widget/Column.md +3 -0
  38. package/docs/widget/Container.md +3 -0
  39. package/docs/widget/DataTable.md +3 -0
  40. package/docs/widget/Divider.md +3 -0
  41. package/docs/widget/DraggBox.md +3 -0
  42. package/docs/widget/Dropdown.md +3 -0
  43. package/docs/widget/DroppBox.md +3 -0
  44. package/docs/widget/FloatingActionButton.md +3 -0
  45. package/docs/widget/GridView.md +3 -0
  46. package/docs/widget/Icon.md +3 -0
  47. package/docs/widget/Image.md +3 -0
  48. package/docs/widget/Input.md +3 -0
  49. package/docs/widget/Inspector.md +2 -2
  50. package/docs/widget/InstallButton.md +3 -0
  51. package/docs/widget/ListTile.md +3 -0
  52. package/docs/widget/ListView.md +3 -0
  53. package/docs/widget/Maps.md +3 -0
  54. package/docs/widget/Markdown.md +3 -0
  55. package/docs/widget/MatrixRain.md +3 -0
  56. package/docs/widget/Pagination.md +3 -0
  57. package/docs/widget/ParallaxBox.md +3 -0
  58. package/docs/widget/ProgressBar.md +3 -0
  59. package/docs/widget/QRCode.md +3 -0
  60. package/docs/widget/Radio.md +4 -1
  61. package/docs/widget/Rating.md +3 -0
  62. package/docs/widget/Row.md +3 -0
  63. package/docs/widget/Skeleton.md +3 -0
  64. package/docs/widget/Slider.md +3 -0
  65. package/docs/widget/Stack.md +3 -0
  66. package/docs/widget/Stepper.md +3 -0
  67. package/docs/widget/Switch.md +3 -0
  68. package/docs/widget/Tabs.md +5 -5
  69. package/docs/widget/Text.md +3 -0
  70. package/docs/widget/Tooltip.md +3 -0
  71. package/docs/widget/TreeView.md +3 -0
  72. package/docs/widget/Video.md +3 -0
  73. package/package.json +2 -2
  74. package/src/animations/AnimatedBox.js +4 -1
  75. package/src/animations/MatrixRain.js +3 -3
  76. package/src/index.d.ts +64 -8
  77. package/src/index.js +1 -0
  78. package/src/navigations/AppBar.js +7 -12
  79. package/src/navigations/BottomNavigation.js +8 -13
  80. package/src/navigations/CollapsibleSideBar.js +30 -8
  81. package/src/navigations/Drawer.js +16 -14
  82. package/src/navigations/DrawerItem.js +3 -1
  83. package/src/navigations/Scaffold.js +26 -12
  84. package/src/navigations/Tabs.js +104 -59
  85. package/src/tools/color.js +54 -0
  86. package/src/tools/index.js +9 -1
  87. package/src/tools/scale.js +41 -0
  88. package/src/tools/shadow.js +20 -0
  89. package/src/utils/index.js +1 -0
  90. package/src/utils/readableInk.js +19 -0
  91. package/src/utils/syntaxHighlight.js +78 -10
  92. package/src/utils/themes.js +217 -54
  93. package/src/utils/units.js +33 -11
  94. package/src/widget-factory/effects.js +56 -5
  95. package/src/widget-factory/processProps.js +10 -1
  96. package/src/widget-factory/remTool.js +15 -29
  97. package/src/widget-factory/stackPosition.js +18 -3
  98. package/src/widget-factory/translateProps.js +28 -0
  99. package/src/widgets/Accordion.js +20 -23
  100. package/src/widgets/AdMob.js +7 -2
  101. package/src/widgets/Avatar.js +18 -12
  102. package/src/widgets/Badge.js +3 -2
  103. package/src/widgets/BottomSheet.js +14 -13
  104. package/src/widgets/Button.js +69 -30
  105. package/src/widgets/Card.js +6 -2
  106. package/src/widgets/Carousel.js +12 -10
  107. package/src/widgets/Chart.js +28 -5
  108. package/src/widgets/Checkbox.js +76 -18
  109. package/src/widgets/Chip.js +31 -10
  110. package/src/widgets/CircularBar.js +7 -7
  111. package/src/widgets/CircularChart.js +26 -8
  112. package/src/widgets/CodeViewer.js +93 -20
  113. package/src/widgets/DataTable.js +17 -11
  114. package/src/widgets/DraggBox.js +2 -1
  115. package/src/widgets/Dropdown.js +26 -13
  116. package/src/widgets/DroppBox.js +4 -2
  117. package/src/widgets/FloatingActionButton.js +13 -7
  118. package/src/widgets/Icon.js +3 -1
  119. package/src/widgets/Input.js +30 -23
  120. package/src/widgets/Inspector.js +54 -1
  121. package/src/widgets/InstallButton.js +6 -4
  122. package/src/widgets/ListTile.js +4 -3
  123. package/src/widgets/ListView.js +30 -12
  124. package/src/widgets/Markdown.js +37 -26
  125. package/src/widgets/Modal.js +14 -11
  126. package/src/widgets/Pagination.js +16 -11
  127. package/src/widgets/ProgressBar.js +6 -4
  128. package/src/widgets/Radio.js +73 -15
  129. package/src/widgets/Rating.js +24 -6
  130. package/src/widgets/Skeleton.js +31 -31
  131. package/src/widgets/Slider.js +29 -18
  132. package/src/widgets/SnackBar.js +35 -39
  133. package/src/widgets/Stepper.js +13 -9
  134. package/src/widgets/Switch.js +59 -18
  135. package/src/widgets/Tooltip.js +12 -10
  136. package/src/widgets/TreeView.js +27 -15
package/docs/README.md CHANGED
@@ -14,6 +14,7 @@ This documentation is one continuous book. Start at **Chapter 0** and follow the
14
14
  | 9 | [State, Router & Services](guides/state.md) | Shared state, navigation routes, storage, and HTTP | Intermediate |
15
15
  | 10 | [Tools & Utilities](tools/README.md) | The helper functions that ship with the framework | Intermediate |
16
16
  | 11 | [The CLI](cli/README.md) | Create, run, and build projects with `flet-box` | Intermediate |
17
+ | 12 | [Clean UI](guides/clean-ui.md) | The design system every app ships with and the gate that enforces it | Intermediate |
17
18
  | A | [Appendices](guides/minification-and-protection.md) | Minification, mobile, compatibility, embedding, online updates (OTA) | Advanced |
18
19
 
19
20
  > **Levels.** *Beginner:* start here and read in order. *Intermediate:* continue in order — you are comfortable with widgets. *Advanced:* for when you ship, skip on a first read.
@@ -50,6 +51,7 @@ Front cover (this page)
50
51
  → Animation helpers · tools/animation.md
51
52
  → Utilities guide · guides/utilities.md
52
53
  → The CLI · cli/README.md
54
+ → Clean UI · guides/clean-ui.md
53
55
  → Appendices (minification → mobile → compatibility → embedding → online updates)
54
56
  → The end of the book
55
57
  ```
@@ -62,6 +62,33 @@ http://localhost:8000
62
62
 
63
63
  The default project includes screens, an app bar, a drawer, routing, and the files needed to start experimenting.
64
64
 
65
+ ### Pointing the project at its repository
66
+
67
+ `flet-box create` writes a GitHub Pages workflow into every project. Pass the
68
+ repository with `--repo` and the same address is filled in everywhere it is
69
+ needed:
70
+
71
+ ```bash
72
+ flet-box create my-app --repo kuko53348/my-app
73
+ ```
74
+
75
+ That sets `update.url` in `fletbox.config.json` (what an installed app polls for
76
+ an over-the-air update), names the site at the top of
77
+ `.github/workflows/build.yml`, and prints the address in the closing summary:
78
+
79
+ ```text
80
+ ⬆️ OTA updates: https://kuko53348.github.io/my-app/
81
+ CI: .github/workflows/build.yml publishes the web to GitHub Pages on every push.
82
+ It goes live at: https://kuko53348.github.io/my-app/
83
+ Enable it once: Settings → Pages → Source: GitHub Actions. The job prints the URL.
84
+ ```
85
+
86
+ The first positional argument is always the project name; a flag that arrives
87
+ before it is read as the name. Without `--repo` nothing is invented — the
88
+ placeholder stays in both files and the workflow says which two to edit. The
89
+ reason the workflow log, not the header, is the authority on the live address is
90
+ explained in [The Pages address of a generated app](../guides/online-updates.md).
91
+
65
92
  ## Project templates
66
93
 
67
94
  FletBox provides four project templates.
@@ -500,6 +527,36 @@ command converts it anyway and says so in the report: keep the JPEG — or a Web
500
527
  from a tool that carries a codec — for that picture, and let `to-png` do the flat
501
528
  art, the logos and the icons.
502
529
 
530
+ ## Check the UI
531
+
532
+ `flet-box check-ui` reads your app's own `src/` and reports the design mistakes a
533
+ static pass can prove: a hand-typed color literal instead of a token, a size that
534
+ is not on the 8-based scale, a tap target below the Fitts floor, a form field with
535
+ no label, and text whose contrast against the fill it sits on is below WCAG AA.
536
+
537
+ ```bash
538
+ flet-box check-ui # scan ./src
539
+ flet-box check-ui --root ../my-app # scan another project
540
+ flet-box check-ui --tokens # print the measured token contrast table
541
+ flet-box check-ui --strict # contrast warnings fail too
542
+ flet-box check-ui --json # machine-readable findings
543
+ ```
544
+
545
+ Aliases: `flet-box ui`, `flet-box checkUi`. The command exits `1` when it finds an
546
+ error, or when it finds a warning with `--strict`, so it works as a CI gate.
547
+
548
+ Every prop name the checker uses comes from the installed package's own prop
549
+ registry, so it cannot invent an API while judging yours. The scale, the radii and
550
+ the tap minimum are the framework's own numbers, read from its `scale` module —
551
+ the same table the widget defaults are drawn from.
552
+
553
+ What it deliberately does not judge: taste, hierarchy, and whether the screen
554
+ solves the user's problem. `flet-box create` writes the rules as a skill file
555
+ alongside the app, and that file says so.
556
+
557
+ The full contract — the 21 rules, every finding code, and how to fix one — is
558
+ [Chapter 12, Clean UI](../guides/clean-ui.md).
559
+
503
560
  ## Command reference
504
561
 
505
562
 
@@ -510,6 +567,7 @@ art, the logos and the icons.
510
567
  | `flet-box create <name> --full` | Creates a project with drawer and bottom navigation. |
511
568
  | `flet-box create <name> --sidebar` | Creates a desktop sidebar project. |
512
569
  | `flet-box create <name> --adaptive` | Creates a mobile and desktop project. |
570
+ | `flet-box create <name> --repo <user>/<repo>` | Sets the GitHub Pages address, the OTA URL and the workflow header from the repo. |
513
571
  | `flet-box screen <name>` | Creates one screen. |
514
572
  | `flet-box screen <number>` | Creates up to ten screens. |
515
573
  | `flet-box component <name>` | Creates one component. |
@@ -529,6 +587,9 @@ art, the logos and the icons.
529
587
  | `flet-box to-png --dry-run` | Reports what would happen, writes nothing. |
530
588
  | `flet-box to-png --replace` | Deletes each source after its PNG was written and read back. |
531
589
  | `flet-box to-png --optimize` | Re-packs the PNGs already in the folder, and only when that makes them smaller. |
590
+ | `flet-box check-ui` | Runs the clean-UI gate over `src/`: tokens, scale, tap targets, labels, contrast. |
591
+ | `flet-box check-ui --tokens` | Prints the measured contrast of every color token, on the background and on the surface. |
592
+ | `flet-box check-ui --strict` | Makes the contrast warnings fail the run, not just the errors. |
532
593
  | `flet-box pkg` | Opens the package manager. |
533
594
  | `flet-box --version` | Shows the CLI version. |
534
595
  | `flet-box --help` | Shows the command list. |
@@ -618,7 +679,7 @@ npm install --save-dev esbuild
618
679
  ## Continue reading
619
680
 
620
681
  - **Previous:** [FletBox utilities](../guides/utilities.md)
621
- - **Next:** [Minify and protect a FletBox build](../guides/minification-and-protection.md) — Appendix A
682
+ - **Next:** [Clean UI](../guides/clean-ui.md) — Chapter 12
622
683
  - **Index:** [Guides index](../guides/README.md) · [The FletBox Book](../README.md)
623
684
 
624
685
  You are reading **Chapter 11 · The CLI**.
@@ -9,6 +9,8 @@ This directory is the **conceptual index** of FletBox: how to build apps, set up
9
9
  - **[Routing with FletBox](router.md)** — Chapter 9 · fixed paths, dynamic parameters, queries, history, and route subscriptions.
10
10
  - **[Frontend services](frontend-services.md)** — Chapter 9 · the practical walkthrough of the three storage layers (`RamStore`, `Session`, `Storage`) and the HTTP client.
11
11
  - **[FletBox utilities](utilities.md)** — Chapter 10 · layout/theme/format helpers and validator tools.
12
+ - **[The CLI](../cli/README.md)** — Chapter 11 · create, run, and build projects with `flet-box`.
13
+ - **[Clean UI](clean-ui.md)** — Chapter 12 · the token scale, the 21 rules, and the `flet-box check-ui` gate that enforces them.
12
14
  - **[Widget structure](widget-structure.md)** — the canonical, modular shape every widget follows (and how new ones are added).
13
15
 
14
16
  ## Appendices (Advanced — for shipping)
@@ -0,0 +1,211 @@
1
+ # Clean UI — the system contract
2
+
3
+ A FletBox screen is not decorated, it is extended: every app copies the widget
4
+ defaults, and every later screen copies the screen before it. This page is the
5
+ contract that makes the copy look like one product — the numbers, the tokens,
6
+ and the two commands that prove a screen obeys them.
7
+
8
+ It is the published version of the rule file that ships inside every generated
9
+ app, so the app's agent and the framework's documentation cannot disagree.
10
+
11
+ ## The two gates
12
+
13
+ A generated project has two checks, and they answer different questions:
14
+
15
+ ```bash
16
+ npm run check # is the API real? widgets, props, imports
17
+ npm run ui # does the screen follow these rules?
18
+ npm run ui -- --tokens # measured contrast of every token, on both surfaces
19
+ npm run dev # then look at it: the checker has no eyes
20
+ ```
21
+
22
+ `npm run check` (`flet-box check-api`) is about correctness — an invented prop
23
+ fails the build. `npm run ui` (`flet-box check-ui`) is about the system — a
24
+ `padding: 21` is valid JavaScript and a design defect at the same time. Neither
25
+ one replaces opening the page.
26
+
27
+ ## Where the rules live
28
+
29
+ | Home | What it holds |
30
+ | --- | --- |
31
+ | `.claude/skills/fletbox-clean-ui/SKILL.md` | The 21 numbered rules below, written for the agent that builds the screen. Mirrored to `.qoder/skills/…` and `.cursor/rules/fletbox-clean-ui.mdc`. |
32
+ | `AGENTS.md` §4 of the app | The short version: one brand color per screen, no hex literals, spacing and radius only from the scale. |
33
+ | `src/tools/scale.js` in the framework | The tables themselves — `SPACING_SCALE`, `RADIUS_SCALE`, `TYPE_SCALE`, `TAP_MINIMUM`, `PILL`, `LABEL_TEXT`. |
34
+ | `bin/commands/checkUi.js` | The gate. It re-exports those same tables instead of keeping its own copy. |
35
+
36
+ That last line matters more than it looks. A gate that carries its own numbers
37
+ drifts from the widgets, and the app then gets told to be clean by values the
38
+ components it uses do not follow. The defaults and the checker read one table.
39
+
40
+ ## The scale
41
+
42
+ | Dimension | Allowed values |
43
+ | --- | --- |
44
+ | Spacing | `0 · 4 · 8 · 12 · 16 · 18 · 24 · 32 · 40 · 48 · 64 · 96` |
45
+ | Radius | `0 · 4 · 8 · 12 · 16 · 999` — `999` is a pill, `0` a flush edge; both are decisions |
46
+ | Type | `12 · 14 · 16 · 18 · 24 · 32 · 40 · 48` |
47
+ | Tap minimum | `40` — Fitts: the smallest pressable box a finger reliably hits |
48
+ | Label text | `14` — the reading size a control's own label may not fall under |
49
+
50
+ Type steps are two apart on purpose: a 15 next to a 16 reads as a mistake, not
51
+ as hierarchy. The same logic gives the scale its gaps — a value between two
52
+ steps is a shape no other element in the app has.
53
+
54
+ ## Every number is a framework unit
55
+
56
+ A number on a size prop is not a CSS pixel. It goes through `toREM`
57
+ (`src/utils/units.js`) and reaches the page as `value / 16` rem, so `40` is 40px
58
+ at the default base and 60px for a reader who raised their browser font to 24.
59
+ That is what makes one build fit a phone, a tablet and a desktop, and it is why
60
+ the Fitts floor here is 40 rem-units rather than the 44px the guidelines quote:
61
+ a target written in rem obeys the accessibility setting, a fixed pixel shrinks
62
+ in relative terms the moment the type grows.
63
+
64
+ `toREM` also rewrites a length someone spelled out in pixels — `"8px 12px"`
65
+ becomes `"0.5rem 0.75rem"` — while anything that is not made only of pixel
66
+ tokens (`"50%"`, `"calc(100% - 8px)"`, `"2px solid red"`) passes through
67
+ untouched.
68
+
69
+ Pixels stay pixels where a pixel is the honest unit:
70
+
71
+ - canvas backing stores (`QRCode`, `Chart`, `CircularBar`, `CircularChart`),
72
+ - Maps' projected tile and pin space,
73
+ - anything measured from the DOM (`offsetWidth`, `getBoundingClientRect`, scroll offsets),
74
+ - the hairline `borderWidth`, and shadow depth (`SHADOW_LEVELS`), because a
75
+ shadow that scales with the font stops matching the surface it lifts,
76
+ - a virtualised row's scroll math — `ListView` converts `itemSize + gap` through
77
+ the live root font size so the slot a row gets and the row's own box agree.
78
+
79
+ The framework keeps this honest with its own gate, `scripts/check-widget-scale.mjs`
80
+ (part of `npm test`): a length written straight to `el.style.*` that is neither
81
+ `toREM(...)` nor measured geometry fails the build.
82
+
83
+ ## The 21 rules
84
+
85
+ When two of them conflict, take them in this order: **consistency · clarity ·
86
+ accessibility · usability · scalability · maintainability · conversion**.
87
+
88
+ | # | Rule | What it forbids |
89
+ | --- | --- | --- |
90
+ | 00 | The two gates | Shipping a screen neither `check` nor `ui` has run against. |
91
+ | 01 | System before component | Deciding a value case by case; define the token, then the component, then the screen. |
92
+ | 02 | Consistency is sacred | An arbitrary difference — a second card radius, a second button height. |
93
+ | 03 | Design tokens only | A hex literal, a `px` string, a value off the scale. |
94
+ | 04 | Hierarchy in three seconds | More than one primary action competing on a screen. |
95
+ | 05 | One purpose per screen | A screen that needs "and" to describe it. |
96
+ | 06 | Reduce cognitive load | Choices with no default, fields that could be inferred, copy that explains the interface. |
97
+ | 07 | Spacing communicates relationship | Related things sitting farther apart than unrelated ones. |
98
+ | 08 | Typography is structure | More than one size per element, body copy centered, a line that runs past ~75 characters. |
99
+ | 09 | Color carries meaning | Brand color used for decoration, or a destructive action in the same fill as a safe one. |
100
+ | 10 | Depth is a scale | An `elevation` number on a widget that never reads it, or a hand-typed `boxShadow`. |
101
+ | 11 | Accessibility is a floor | Text under WCAG AA contrast, a tap target under 40, an image with no `alt` decision. |
102
+ | 12 | Every interaction has four states | A control or list with no loading, empty, error or success path. |
103
+ | 13 | Forms prevent the error | Validation that only reports after a failed submit; an unlabeled field or toggle. |
104
+ | 14 | Destructive actions designed last | A delete that is the closest, fastest, most colorful thing on the screen. |
105
+ | 15 | Reduce interaction cost | Taps, scrolls and keystrokes that carry no information. |
106
+ | 16 | Respect the platform | Fighting the browser's own conventions — back, scroll, text selection. |
107
+ | 17 | The review | Shipping before reading your own diff as the user. |
108
+ | 18 | Where these books are wrong | Following a guideline that measurement disagrees with. |
109
+ | 19 | What no checker can see | Taste, hierarchy in the wild, whether the screen solves the problem. |
110
+ | 20 | The loop | Fixing the checker instead of the code, or leaving a rule you had to break undocumented. |
111
+
112
+ ## What `flet-box check-ui` proves
113
+
114
+ The gate reads your `src/` and reports what a static pass can prove. Prop names
115
+ come from the installed package's own registry, so it cannot invent an API while
116
+ judging yours. Each finding carries a code, and the code maps to a rule above.
117
+
118
+ ### Errors (exit 1)
119
+
120
+ | Code | Rule | What it catches |
121
+ | --- | --- | --- |
122
+ | `RAW_COLOR` | 03 | A color literal on a widget outside `src/database/themes.js`. |
123
+ | `OFF_SCALE_SPACING` | 07 | A padding, margin, gap or size off the spacing scale — including inside a `"12px 20px"` shorthand. |
124
+ | `OFF_SCALE_RADIUS` | 03 | A corner radius that is not a scale step. |
125
+ | `OFF_SCALE_TYPE` | 08 | A font size off the type scale. |
126
+ | `SMALL_TAP_TARGET` | 11 | A pressable widget under the Fitts floor, including a bare `Icon` with `onPress`. |
127
+ | `LOW_CONTRAST` | 11 | Text measured below AA against the fill it actually sits on. |
128
+ | `UNLABELED_FIELD` | 13 | An `Input` or `Dropdown` with neither a `label` nor a `placeholder`. |
129
+ | `UNLABELED_TOGGLE` | 13 | A `Switch`, `Checkbox` or `Radio` with nothing to say what it toggles. |
130
+ | `DESTRUCTIVE_COLOR` | 14 | A delete/remove verb rendered in the brand fill instead of the danger one. |
131
+ | `UNREADABLE` | — | A file the scanner could not parse, reported rather than skipped. |
132
+
133
+ ### Warnings (fail with `--strict`)
134
+
135
+ | Code | Rule | What it catches |
136
+ | --- | --- | --- |
137
+ | `LOW_CONTRAST_SOFT` | 11 | Text that clears AA only because of its size. |
138
+ | `LOW_CONTRAST_UI` | 11 | A graphic that carries meaning below 3:1. |
139
+ | `LOW_CONTRAST_ON_SURFACE` | 11 | Text measured against `background` and `surface` at once, when the fill is inherited. |
140
+ | `HAND_MIXED_COLOR` | 03 | `colors.primary + "22"` — a one-off shade no other screen can reuse. |
141
+ | `DEAD_ELEVATION` | 10 | A numeric `elevation` on a widget that never reads it: CSS drops the bare number and the box stays flat in silence. |
142
+ | `IMAGE_NO_ALT` | 11 | An `Image` with no `alt` — `alt: ""` is a decision, a missing prop is an oversight. |
143
+ | `ICON_ONLY_CONTROL` | 15 | A pressable glyph with no name; wrap it in `Tooltip({ text, child })`. |
144
+ | `CENTERED_BODY_TEXT` | 08 | A paragraph centered; a paragraph needs a left edge to find the next line. |
145
+ | `GENERIC_ACTION_LABEL` | 06 | "OK", "Submit", "Click here" — a label that says nothing about what pressing it does. |
146
+ | `CONFIRM_ORDER` | 14 | A destructive button placed before Cancel in the same row. |
147
+ | `UNCONSTRAINED_FORM_WIDTH` | 08 | A form block whose fields run to the full width of a desktop window. |
148
+
149
+ ### Informational
150
+
151
+ | Code | Rule | What it says |
152
+ | --- | --- | --- |
153
+ | `SMALL_PRESET` | 11 | `size: "small"` on a control that is the screen's main action (~30px). |
154
+ | `CROWDED_FORM` | 06 | Many fields in one file: group them, or split the task. |
155
+ | `LIST_WITHOUT_STATE` | 12 | A list with no loading, empty or failed state in this file. |
156
+ | `MULTIPLE_PRIMARY_ACTIONS` | 04 | Several filled buttons on one screen. |
157
+
158
+ ## Running the gate
159
+
160
+ ```bash
161
+ flet-box check-ui # scan ./src
162
+ flet-box check-ui --root ../my-app # scan another project
163
+ flet-box check-ui --tokens # print the measured token contrast table
164
+ flet-box check-ui --strict # warnings fail too
165
+ flet-box check-ui --json # machine-readable findings
166
+ ```
167
+
168
+ Aliases: `flet-box ui`, `flet-box checkUi`. Exit code is `1` when an error is
169
+ present (or a warning, with `--strict`), so it fits in CI as the app's
170
+ `npm run ui`.
171
+
172
+ `--tokens` is the one worth reading before you pick colors. It prints the
173
+ measured ratio of every token against `background` and `surface` — for the
174
+ palette in use, so switch the theme and read it again if you ship both. A brand
175
+ color that looks fine and measures 2.15:1 (`colors.warning`, decoration only)
176
+ becomes a number instead of an argument, and the table already tells you which
177
+ tokens clear AA body text, which are large-text-or-UI only, and on which fill
178
+ writing text is a mistake.
179
+
180
+ ## Fixing a finding
181
+
182
+ Fix the code, not the checker. A finding you keep needs one sentence of
183
+ justification — in the commit or in the file — because the next person, human or
184
+ agent, will otherwise copy the exception as if it were the rule.
185
+
186
+ And a rule you had to break is information about the rule: if the exception was
187
+ right twice, it is a defect in the scale, not in the app.
188
+
189
+ ## What no checker can see
190
+
191
+ `check-ui` has no eyes. It cannot tell you that the screen is ugly, that the
192
+ hierarchy reads wrong at a glance, or that the flow does not solve the user's
193
+ problem. Those are rules 17 and 19, and they are the ones that need a person.
194
+ Run the gate, then open the page.
195
+
196
+ ## Related pages
197
+
198
+ - [FletBox utilities](utilities.md) — the theme and layout helpers the tokens come from.
199
+ - [Themes](../tools/theme.md) — `registerPalette`, the call that gets your brand onto the page.
200
+ - [The CLI](../cli/README.md) — every command, including `check-api` and `unpack`.
201
+ - [Widget structure](widget-structure.md) — how a widget is built, and where its defaults live.
202
+
203
+ ---
204
+
205
+ ## Continue reading
206
+
207
+ - **Previous:** [The CLI](../cli/README.md) — Chapter 11
208
+ - **Next:** [Minify and protect a FletBox build](minification-and-protection.md) — Appendix A
209
+ - **Index:** [Guides index](README.md) · [The FletBox Book](../README.md)
210
+
211
+ You are reading **Chapter 12 · Clean UI**.
@@ -255,6 +255,6 @@ Minification reduces the web payload inside the native application. It does not
255
255
 
256
256
  ## Continue reading
257
257
 
258
- - **Previous:** [The FletBox CLI](../cli/README.md)
258
+ - **Previous:** [Clean UI](clean-ui.md) — Chapter 12
259
259
  - **Next:** [Build FletBox for mobile and other platforms](mobile-and-platforms.md) — Appendix B
260
260
  - **Index:** [Guides index](README.md) · [The FletBox Book](../README.md)
@@ -136,6 +136,54 @@ To configure it by hand, create `fletbox.config.json`:
136
136
  }
137
137
  ```
138
138
 
139
+ ## The Pages address of a generated app
140
+
141
+ The URL you paste into `update.url` is not a guess: `flet-box create` knows the
142
+ address the app will be published to and prints it when it finishes.
143
+
144
+ ```bash
145
+ flet-box create my-app --repo kuko53348/my-app
146
+ ```
147
+
148
+ That `--repo` (or the same value typed at the interactive prompt) does three
149
+ things at once:
150
+
151
+ - sets `update.url` in `fletbox.config.json` to `https://kuko53348.github.io/my-app/`;
152
+ - writes that address into the header of the generated `.github/workflows/build.yml`;
153
+ - prints it in the closing summary, with the one-time setting Pages needs.
154
+
155
+ Without `--repo` nothing is invented. `fletbox.config.json` keeps the generic
156
+ placeholder `https://TU-USUARIO.github.io/TU-REPO/`, the workflow header names a
157
+ guess built from the folder name, and the workflow says so in its own comment:
158
+ write the real address in both files that state it.
159
+
160
+ **The workflow log is the authority.** The header names the address you typed at
161
+ scaffold time; the `Where this lives` step prints the address the run *actually*
162
+ belongs to, read from GitHub itself:
163
+
164
+ ```text
165
+ site: https://kuko53348.github.io/my-app/ <- from the running repo
166
+ header: https://TU-USUARIO.github.io/my-app/ <- from the file
167
+ version: 1.0.3
168
+ ```
169
+
170
+ When those two disagree, trust `site:`. They disagree when the repository was
171
+ created with a different name than the folder, or when the app was never pushed.
172
+ Note the owner is lower-cased: GitHub Pages serves the site under the
173
+ lower-cased login, so `Kuko53348` in your remote is `kuko53348` in the URL.
174
+
175
+ **A green run that 404s has one cause.** The deploy job can only write to Pages
176
+ after you enable the destination once: **Settings → Pages → Build and deployment
177
+ → Source: GitHub Actions**. Until you do, every run succeeds and no site exists —
178
+ which is exactly what the `Where this lives` step prints in the log, so a failed
179
+ release is never mistaken for a broken bundle.
180
+
181
+ The address is a **sub-path** (`/<repo>/`), and that is why the bundle uses
182
+ relative asset paths: the same `www/` a phone polls for updates is the one served
183
+ under any path, with no rebuild for a custom domain or a rename. If you do move to
184
+ a custom domain, change `update.url` in `fletbox.config.json` and rebuild — the
185
+ native shell keeps the old bundle until the manifest tells it otherwise.
186
+
139
187
  ## Shipping extra files (release assets)
140
188
 
141
189
  OTA swaps **one file**: `src/app.js`. Anything your app reads from disk at runtime — markdown pages, JSON data, per-tenant config — keeps the copy baked into the build the device installed. So an app installed three releases ago can run a bundle that was updated over the air and still be missing files the current catalog refers to. The symptom is not a crash, it is a "this page does not exist" for content that clearly exists online.
@@ -98,7 +98,7 @@ Helpers for shaping collections and generating data.
98
98
 
99
99
  - `parseMarkdown(md)`, `parseInlineMarkdown(md)` — reserved placeholders that pass text through unchanged (real rendering is `markdownToWidgets`/`parseInlineToWidgets`).
100
100
  - `markdownToWidgets(md)` / `parseMarkdownToWidgets(md)` — markdown string → widgets (alias names for the same function).
101
- - `tokenize(code)`, `generateHighlightedHtml(code)`, `highlightColors` — syntax highlighting.
101
+ - `tokenize(code)`, `generateHighlightedHtml(code, palette?)`, `highlightColors` — syntax highlighting (light and dark token maps; the highlighter picks one from the active theme).
102
102
  - `escapeHtml(text)` — escape untrusted text before inserting it as HTML.
103
103
 
104
104
  ## Visual effects
@@ -31,7 +31,7 @@ one style would otherwise fight, and the older animation would resume after the
31
31
 
32
32
  ## Widgets
33
33
 
34
- - `AnimatedBox({ animations, timing, delay, fillMode, child, top, right, bottom, left })` — animates a child widget. `animations` is an array of `{ effect, from, to, duration }` entries; effects include `backgroundColor`, `color`, `borderRadius`, `opacity`, `scale`, `translate`, `rotate`, `width`, `height`, spacing, `boxShadow`, and gradients.
34
+ - `AnimatedBox({ animations, timing, delay, fillMode, child, top, right, bottom, left })` — animates a child widget. `animations` is an array of `{ effect, from, to, duration }` entries; each plays once and holds `to` at the end (add `reverse: true` to cycle back, and `loop: true` to repeat); effects include `backgroundColor`, `color`, `borderRadius`, `opacity`, `scale`, `translate`, `rotate`, `width`, `height`, spacing, `boxShadow`, and gradients.
35
35
  - `AnimatedText({ child, animations, sameTime, delayBetween, orientation })` — animates a `Text` widget (letters split per animation).
36
36
  - `MatrixRain({ chars, fontSize, speed, fadeAmount, resetProbability, useDynamicColor, position, zIndex })` — the falling-characters canvas effect (returns a `canvas`).
37
37
  - `ParallaxBox({ type, speed, direction, maxOffset, reverse, child })` — content that moves; `type` is `"scroll"`, `"mouse"`, or `"hover"`, `direction` is `"vertical"`, `"horizontal"`, or `"both"`.
@@ -24,9 +24,9 @@ import { parseMarkdown, markdownToWidgets, escapeHtml } from "flet-box";
24
24
  | `parseMarkdown` | `parseMarkdown(text)` | `string` | Reserved API: currently returns the input unchanged. Use `markdownToWidgets`. |
25
25
  | `parseInlineMarkdown` | `parseInlineMarkdown(text)` | `string` | Reserved API: currently returns the input unchanged. Use `parseInlineToWidgets`. |
26
26
  | `tokenize` | `tokenize(code)` | `{ type, value }[]` | Split code into token objects. |
27
- | `generateHighlightedHtml` | `generateHighlightedHtml(code)` | `string` | Code → highlighted HTML. |
27
+ | `generateHighlightedHtml` | `generateHighlightedHtml(code, palette?)` | `string` | Code → highlighted HTML. Picks the light or dark token map automatically; pass a map to override. |
28
28
  | `escapeHtml` | `escapeHtml(text)` | `string` | Escape `<`, `>`, `&`, quotes so text is safe as HTML. |
29
- | `highlightColors` | const | `Record<string, string>` | The token color map used by the highlighter. |
29
+ | `highlightColors` | const | `Record<string, string>` | The dark-theme token map (One Dark scale). |
30
30
 
31
31
  `markdownToWidgets` options: `{ codeMaxHeight?: number, codeFontSize?: number }`.
32
32
 
@@ -61,7 +61,7 @@ const safe = escapeHtml(userInput); // safe to put into innerHTML
61
61
  - `markdownToWidgets` builds real widget elements (headings, paragraphs, code blocks, lists) that you can place inside any container — this is what the `Markdown` widget uses.
62
62
  - `parseMarkdown` and `parseInlineMarkdown` are reserved placeholders that currently pass text through unchanged; the widget rendering is `markdownToWidgets`/`parseInlineToWidgets`.
63
63
  - `escapeHtml` should be used for **any** text you insert into the DOM that you did not write yourself. Never trust raw input.
64
- - `tokenize` returns flat token objects and is the base for custom highlighters; `highlightColors` lets you theme them.
64
+ - `tokenize` returns flat token objects and is the base for custom highlighters; `generateHighlightedHtml` reads the active theme, and its second argument accepts a token map when you paint your own surface.
65
65
 
66
66
  ## Related pages
67
67
  - [Themes](theme.md) — previous chapter.
@@ -11,7 +11,7 @@ FletBox ships a built-in color system: `colors` is the palette of the current th
11
11
  ## Import
12
12
 
13
13
  ```javascript
14
- import { colors, setTheme, toggleTheme, subscribeTheme, ThemeProvider } from "flet-box";
14
+ import { colors, setTheme, registerPalette, toggleTheme, subscribeTheme, ThemeProvider } from "flet-box";
15
15
  ```
16
16
 
17
17
  ## Functions
@@ -19,6 +19,7 @@ import { colors, setTheme, toggleTheme, subscribeTheme, ThemeProvider } from "fl
19
19
  | Function | Signature | Returns | Description |
20
20
  | --- | --- | --- | --- |
21
21
  | `setTheme` | `setTheme('light' \| 'dark')` | `Record<string, string>` | Switch the active palette. |
22
+ | `registerPalette` | `registerPalette(themeName, palette)` | `Record<string, string>` | Merge brand tokens into a named palette and repaint the page. |
22
23
  | `getTheme` | `getTheme()` | `string` | The active theme name. |
23
24
  | `toggleTheme` | `toggleTheme()` | `string` | Flip light/dark and return the new name. |
24
25
  | `getColor` | `getColor(name, opacity?)` | `string` | Resolve a token (optionally with alpha). |
@@ -38,9 +39,47 @@ Every token is available on `colors`:
38
39
  - **Surfaces:** `background`, `surface`, `card`, `overlay`.
39
40
  - **Text:** `text`, `textSecondary`, `textDisabled`, `divider`, `border`, `shadow`.
40
41
  - **Tints:** `gray50` … `gray900`, plus the soft backgrounds `errorBg`, `successBg`, `warningBg`, `infoBg`.
42
+ - **Glass:** `glass` (the translucent surface) and `glassBorder` (its rim), meant to pair with `backdropFilter`. Light is white glass, dark is a slate pane with a light rim.
41
43
 
42
44
  The `dark` palette overrides the surface/text tokens; `gray*` and brand colors also shift to keep contrast. Read [the palette walkthrough](../guides/utilities.md) for usage patterns.
43
45
 
46
+ ## Brand colors: `registerPalette`
47
+
48
+ A generated app ships a `src/database/themes.js` with its own `lightColors` and
49
+ `darkColors` objects. Assigning onto `colors` from that file changes nothing:
50
+ every widget reads the framework's live `colors`, and the next theme switch
51
+ re-applies a registered palette over whatever you wrote there. The call that
52
+ reaches the page is `registerPalette`:
53
+
54
+ ```javascript
55
+ import { registerPalette } from "flet-box";
56
+ import { lightColors, darkColors } from "./database/themes.js";
57
+
58
+ registerPalette("light", lightColors);
59
+ registerPalette("dark", darkColors);
60
+ ```
61
+
62
+ What it does:
63
+
64
+ - **Merges**, it does not replace. Tokens you leave out keep the framework's
65
+ value, so a palette that only carries `primary` and `surface` stays legal.
66
+ - **Repaints when that palette is on screen.** If the name matches the active
67
+ theme the tokens are applied, the `--color-*` custom properties are rewritten,
68
+ and theme subscribers are notified. Registering the other theme only stores it
69
+ for the next `setTheme`.
70
+ - **Never writes the theme preference.** Supplying your brand is not the user
71
+ choosing light or dark; that is the one difference from `setTheme`.
72
+ - **A token the framework has never heard of is added to `colors`**, so
73
+ `colors.brandSand` resolves in your own code. Widgets will still not use it —
74
+ they read the tokens they know — and because the built-in palettes do not
75
+ carry it, a custom key keeps its registered value across a theme switch unless
76
+ you register it in both palettes.
77
+
78
+ Run it once, at startup, before the first screen renders. The generated app does
79
+ it at the bottom of `src/database/themes.js` — the same file that declares
80
+ `lightColors` and `darkColors` — so a project that edits its brand colors is
81
+ already correct without touching `src/app.js`.
82
+
44
83
  ## Examples
45
84
 
46
85
  ### Everyday example
@@ -83,6 +122,7 @@ runApp(ThemeProvider({ children: ThemedApp() }), "root");
83
122
  ## Notes
84
123
 
85
124
  - The shared palette tokens are updated across all widgets when you switch themes; widgets referencing `colors.*` at build time pick up the active palette.
125
+ - `colors.glass` is genuinely see-through: its contrast depends on whatever is behind it, so use it over photography or gradients with a scrim, and keep body copy off the most colourful part of the backdrop. The dark token is a dark pane, not white glass.
86
126
  - `watchSystemTheme()` and `applySystemTheme()` read `prefers-color-scheme`; both return/need cleanup to release listeners.
87
127
  - `subscribeTheme(callback)` fires with the new palette object — remember to unsubscribe when a feature is destroyed.
88
128
 
@@ -63,6 +63,9 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
63
63
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
64
64
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
65
65
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
66
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
67
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
68
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
66
69
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
67
70
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
68
71
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -31,7 +31,7 @@ const banner = AdMob({
31
31
  | `margin` | `number` | Space outside the widget, between it and its neighbors. |
32
32
  | `interstitialId` | `string` | AdMob interstitial ad unit id. |
33
33
  | `rewardedId` | `string` | AdMob rewarded ad unit id. |
34
- | `autoShow` | `boolean` | Shows the ad automatically when it is ready. |
34
+ | `autoShow` | `boolean` | Shows the banner automatically on mount. false silences only the mount; show() still asks for the ad. |
35
35
  | `autoInitialize` | `boolean` | The `autoInitialize` value for the widget. |
36
36
  | `width` | `Size` | Width of the widget. A number is pixels; a string uses any CSS unit. |
37
37
  | `height` | `Size` | Height of the widget. A number is pixels; a string uses any CSS unit. |
@@ -62,6 +62,9 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
62
62
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
63
63
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
64
64
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
65
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
66
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
67
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
65
68
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
66
69
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
67
70
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -56,6 +56,9 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
56
56
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
57
57
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
58
58
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
59
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
60
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
61
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
59
62
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
60
63
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
61
64
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -50,6 +50,9 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
50
50
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
51
51
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
52
52
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
53
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
54
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
55
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
53
56
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
54
57
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
55
58
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -96,9 +99,9 @@ const toast = AnimatedBox({
96
99
  ## Tips
97
100
 
98
101
  - Each animation is { effect, from, to } where effect is a CSS property like opacity,
99
- - scale, translateY, or backgroundColor.
100
- - Set timing (ease, ease-out, linear) and delay at the widget level; per-step reverse
101
- - cycles the animation back instead of running it once.
102
+ - scale, translateY, or backgroundColor. It runs once and holds `to` at the end.
103
+ - Set timing (ease, ease-out, linear) and delay at the widget level; add reverse: true
104
+ - to cycle back to `from`, together with loop: true for a breathing pulse.
102
105
  - top, right, bottom, and left are forwarded to the child as positioning hints for
103
106
  - layout systems.
104
107
 
@@ -46,6 +46,9 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
46
46
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
47
47
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
48
48
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
49
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
50
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
51
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
49
52
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
50
53
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
51
54
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -53,6 +53,9 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
53
53
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
54
54
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
55
55
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
56
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
57
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
58
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
56
59
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
57
60
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
58
61
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -50,6 +50,9 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
50
50
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
51
51
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
52
52
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
53
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
54
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
55
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
53
56
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
54
57
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
55
58
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -52,6 +52,9 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
52
52
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
53
53
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
54
54
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
55
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
56
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
57
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
55
58
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
56
59
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
57
60
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |
@@ -59,6 +59,9 @@ Every widget also accepts these shared props — see [common props](COMMON_PROPS
59
59
  | `borderRadius` | `number \| string` | Rounds the corners of the widget. |
60
60
  | `elevation` | `number` | Shadow depth. Higher values lift the widget off the page. |
61
61
  | `shadow` | `string` | Raw CSS `box-shadow` value, for a custom shadow. |
62
+ | `filter` | `string` | Raw CSS `filter` value applied to the widget itself, e.g. `blur(4px)`. |
63
+ | `backdropFilter` | `string` | Raw CSS `backdrop-filter` value: what sits behind the widget is blurred through it, which is what makes a translucent card frosted glass. |
64
+ | `maskImage` | `string` | Raw CSS `mask-image` value, used to fade a widget out at its edges instead of cutting it. |
62
65
  | `opacity` | `number` | Opacity from 0 (invisible) to 1 (fully opaque). |
63
66
  | `visible` | `boolean` | Whether the widget is rendered and visible. |
64
67
  | `disabled` | `boolean` | Disables interaction and shows the non-interactive state. |