@cavulsqa/create 2.9.3 → 2.10.0

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 (199) hide show
  1. package/README.md +12 -1
  2. package/bin/create.mjs +18 -25
  3. package/lib/templates.mjs +56 -0
  4. package/package.json +13 -5
  5. package/templates/f7-app/auto-imports.d.ts +9 -0
  6. package/templates/f7-app/package.json +6 -3
  7. package/templates/f7-app/src/env.d.ts +1 -0
  8. package/templates/f7-app/src/main.ts +3 -0
  9. package/templates/f7-app/src/plugins/bootstrapError.ts +2 -0
  10. package/templates/f7-app/src/plugins/recorder.plugin.ts +155 -0
  11. package/templates/f7-app/src/shared/recorder/capacitorSink.ts +124 -0
  12. package/templates/f7-app/vite.config.ts +1 -0
  13. package/templates/m3e-app/.claude/rules/data-fetching.md +68 -0
  14. package/templates/m3e-app/.claude/rules/database.md +106 -0
  15. package/templates/m3e-app/.claude/rules/m3e-ui.md +48 -0
  16. package/templates/m3e-app/.claude/rules/modules.md +43 -0
  17. package/templates/m3e-app/.claude/rules/native.md +60 -0
  18. package/templates/m3e-app/.claude/skills/m3-expressive/SKILL.md +68 -0
  19. package/templates/m3e-app/.claude/skills/m3-expressive/color.md +44 -0
  20. package/templates/m3e-app/.claude/skills/m3-expressive/components.md +325 -0
  21. package/templates/m3e-app/.claude/skills/m3-expressive/layout.md +42 -0
  22. package/templates/m3e-app/.claude/skills/m3-expressive/motion.md +51 -0
  23. package/templates/m3e-app/.claude/skills/m3-expressive/shapes-type.md +48 -0
  24. package/templates/m3e-app/.claude/skills/m3-expressive/sources.md +53 -0
  25. package/templates/m3e-app/.claude/skills/module-architecture/SKILL.md +65 -0
  26. package/templates/m3e-app/.claude/skills/module-architecture/file-templates.md +178 -0
  27. package/templates/m3e-app/.claude/skills/reactive-data/SKILL.md +90 -0
  28. package/templates/m3e-app/.claude/skills/reactive-data/testing.md +55 -0
  29. package/templates/m3e-app/.env.example +32 -0
  30. package/templates/m3e-app/CLAUDE.md +93 -0
  31. package/templates/m3e-app/auto-imports.d.ts +851 -0
  32. package/templates/m3e-app/capacitor.config.ts +44 -0
  33. package/templates/m3e-app/components.d.ts +252 -0
  34. package/templates/m3e-app/index.html +16 -0
  35. package/templates/m3e-app/package.json +107 -0
  36. package/templates/m3e-app/src/App.vue +129 -0
  37. package/templates/m3e-app/src/app/pragmas.config.ts +35 -0
  38. package/templates/m3e-app/src/app/scroll.config.ts +20 -0
  39. package/templates/m3e-app/src/app/storage.config.ts +65 -0
  40. package/templates/m3e-app/src/app/tabs.ts +33 -0
  41. package/templates/m3e-app/src/app/theme.config.ts +51 -0
  42. package/templates/m3e-app/src/assets/css/app.css +18 -0
  43. package/templates/m3e-app/src/assets/css/base.css +53 -0
  44. package/templates/m3e-app/src/assets/css/layout/container-transform.css +113 -0
  45. package/templates/m3e-app/src/assets/css/layout/shell.css +69 -0
  46. package/templates/m3e-app/src/assets/css/layout/transitions.css +121 -0
  47. package/templates/m3e-app/src/assets/css/m3e.css +6 -0
  48. package/templates/m3e-app/src/assets/css/theme/framework7.css +18 -0
  49. package/templates/m3e-app/src/assets/css/theme/tailwind.css +365 -0
  50. package/templates/m3e-app/src/domains/benchmark/benchmark.dataset.ts +209 -0
  51. package/templates/m3e-app/src/domains/benchmark/benchmark.suite.ts +662 -0
  52. package/templates/m3e-app/src/domains/sales/sales.repository.ts +458 -0
  53. package/templates/m3e-app/src/env.d.ts +40 -0
  54. package/templates/m3e-app/src/locales/ar.json +1260 -0
  55. package/templates/m3e-app/src/locales/en.json +1260 -0
  56. package/templates/m3e-app/src/locales/fr.json +1260 -0
  57. package/templates/m3e-app/src/main.ts +41 -0
  58. package/templates/m3e-app/src/modules/demo/components/DemoBenchmark.vue +119 -0
  59. package/templates/m3e-app/src/modules/demo/components/DemoBusLog.vue +63 -0
  60. package/templates/m3e-app/src/modules/demo/components/DemoCreateOrderSheet.vue +203 -0
  61. package/templates/m3e-app/src/modules/demo/components/DemoMetricsSheet.vue +75 -0
  62. package/templates/m3e-app/src/modules/demo/components/DemoOrderList.vue +75 -0
  63. package/templates/m3e-app/src/modules/demo/components/DemoPipelineBenchmark.vue +65 -0
  64. package/templates/m3e-app/src/modules/demo/components/DemoStatCards.vue +71 -0
  65. package/templates/m3e-app/src/modules/demo/composables/useBenchmark.ts +139 -0
  66. package/templates/m3e-app/src/modules/demo/composables/useOrderStatus.ts +64 -0
  67. package/templates/m3e-app/src/modules/demo/composables/useReactiveDemo.ts +171 -0
  68. package/templates/m3e-app/src/modules/demo/router/routes/demo.routes.ts +22 -0
  69. package/templates/m3e-app/src/modules/demo/views/DemoView.vue +210 -0
  70. package/templates/m3e-app/src/modules/demo/views/OrderDetailView.vue +136 -0
  71. package/templates/m3e-app/src/modules/demo/views/OrderSearchView.vue +74 -0
  72. package/templates/m3e-app/src/modules/gallery/components/GalleryBlock.vue +16 -0
  73. package/templates/m3e-app/src/modules/gallery/components/GalleryCarouselTile.vue +71 -0
  74. package/templates/m3e-app/src/modules/gallery/components/GalleryCustomerForm.vue +76 -0
  75. package/templates/m3e-app/src/modules/gallery/components/GalleryProofOfDelivery.vue +69 -0
  76. package/templates/m3e-app/src/modules/gallery/components/agenda/AgendaDay.vue +106 -0
  77. package/templates/m3e-app/src/modules/gallery/components/agenda/AgendaMonth.vue +40 -0
  78. package/templates/m3e-app/src/modules/gallery/components/agenda/AgendaVisitList.vue +45 -0
  79. package/templates/m3e-app/src/modules/gallery/components/chat/ChatAttachSheet.vue +106 -0
  80. package/templates/m3e-app/src/modules/gallery/components/chat/ChatContactPicker.vue +85 -0
  81. package/templates/m3e-app/src/modules/gallery/components/chat/ChatInviteComposer.vue +131 -0
  82. package/templates/m3e-app/src/modules/gallery/components/chat/ChatPollComposer.vue +148 -0
  83. package/templates/m3e-app/src/modules/gallery/components/chat/ChatRecentPhotos.vue +62 -0
  84. package/templates/m3e-app/src/modules/gallery/components/inputs/InputsAccount.vue +79 -0
  85. package/templates/m3e-app/src/modules/gallery/components/inputs/InputsTags.vue +53 -0
  86. package/templates/m3e-app/src/modules/gallery/components/inputs/InputsVerification.vue +73 -0
  87. package/templates/m3e-app/src/modules/gallery/components/inputs/PasswordStrength.vue +37 -0
  88. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryButtons.vue +128 -0
  89. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryCarousels.vue +236 -0
  90. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryCharts.vue +84 -0
  91. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryFabs.vue +70 -0
  92. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryInputs.vue +219 -0
  93. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryNavigation.vue +141 -0
  94. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryOverlays.vue +368 -0
  95. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryPickers.vue +175 -0
  96. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryProgress.vue +118 -0
  97. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryScale.vue +103 -0
  98. package/templates/m3e-app/src/modules/gallery/components/sections/GallerySelection.vue +219 -0
  99. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryShapes.vue +48 -0
  100. package/templates/m3e-app/src/modules/gallery/components/sections/GallerySurfaces.vue +213 -0
  101. package/templates/m3e-app/src/modules/gallery/components/sections/GalleryTables.vue +185 -0
  102. package/templates/m3e-app/src/modules/gallery/components/surfaces/SurfacesContainerTransform.vue +46 -0
  103. package/templates/m3e-app/src/modules/gallery/composables/chatTeam.ts +18 -0
  104. package/templates/m3e-app/src/modules/gallery/composables/composeKind.ts +2 -0
  105. package/templates/m3e-app/src/modules/gallery/composables/currentPosition.ts +35 -0
  106. package/templates/m3e-app/src/modules/gallery/composables/demoOrders.ts +29 -0
  107. package/templates/m3e-app/src/modules/gallery/composables/featuredStories.ts +73 -0
  108. package/templates/m3e-app/src/modules/gallery/composables/fieldFormats.ts +36 -0
  109. package/templates/m3e-app/src/modules/gallery/composables/openExternal.ts +11 -0
  110. package/templates/m3e-app/src/modules/gallery/composables/routePlan.ts +90 -0
  111. package/templates/m3e-app/src/modules/gallery/composables/useAgenda.ts +61 -0
  112. package/templates/m3e-app/src/modules/gallery/composables/useChatCustomers.ts +31 -0
  113. package/templates/m3e-app/src/modules/gallery/composables/useChatDemo.ts +299 -0
  114. package/templates/m3e-app/src/modules/gallery/composables/useGallerySections.ts +230 -0
  115. package/templates/m3e-app/src/modules/gallery/composables/useLocalAttachments.ts +71 -0
  116. package/templates/m3e-app/src/modules/gallery/composables/useLocationShare.ts +38 -0
  117. package/templates/m3e-app/src/modules/gallery/composables/usePhotoScenes.ts +82 -0
  118. package/templates/m3e-app/src/modules/gallery/composables/useTreeDemo.ts +67 -0
  119. package/templates/m3e-app/src/modules/gallery/composables/wilayas.ts +67 -0
  120. package/templates/m3e-app/src/modules/gallery/router/routes/gallery.routes.ts +52 -0
  121. package/templates/m3e-app/src/modules/gallery/views/GalleryAgendaView.vue +117 -0
  122. package/templates/m3e-app/src/modules/gallery/views/GalleryChatView.vue +292 -0
  123. package/templates/m3e-app/src/modules/gallery/views/GalleryContactsView.vue +77 -0
  124. package/templates/m3e-app/src/modules/gallery/views/GalleryFeaturedView.vue +60 -0
  125. package/templates/m3e-app/src/modules/gallery/views/GalleryLoginView.vue +135 -0
  126. package/templates/m3e-app/src/modules/gallery/views/GalleryOnboardingView.vue +116 -0
  127. package/templates/m3e-app/src/modules/gallery/views/GallerySectionView.vue +27 -0
  128. package/templates/m3e-app/src/modules/gallery/views/GalleryTabsView.vue +135 -0
  129. package/templates/m3e-app/src/modules/gallery/views/GalleryView.vue +50 -0
  130. package/templates/m3e-app/src/modules/home/components/HomeHero.vue +57 -0
  131. package/templates/m3e-app/src/modules/home/composables/useHomeFeatures.ts +128 -0
  132. package/templates/m3e-app/src/modules/home/composables/useOpenFeature.ts +22 -0
  133. package/templates/m3e-app/src/modules/home/router/routes/home.routes.ts +21 -0
  134. package/templates/m3e-app/src/modules/home/views/FeatureDetailView.vue +66 -0
  135. package/templates/m3e-app/src/modules/home/views/HomeView.vue +47 -0
  136. package/templates/m3e-app/src/modules/settings/components/RolePalette.vue +38 -0
  137. package/templates/m3e-app/src/modules/settings/components/SeedSwatches.vue +41 -0
  138. package/templates/m3e-app/src/modules/settings/components/SettingsChoice.vue +43 -0
  139. package/templates/m3e-app/src/modules/settings/components/StudioPreview.vue +52 -0
  140. package/templates/m3e-app/src/modules/settings/router/routes/settings.routes.ts +17 -0
  141. package/templates/m3e-app/src/modules/settings/types.ts +7 -0
  142. package/templates/m3e-app/src/modules/settings/views/ColorStudioView.vue +166 -0
  143. package/templates/m3e-app/src/modules/settings/views/SettingsView.vue +157 -0
  144. package/templates/m3e-app/src/plugins/bootstrapError.ts +62 -0
  145. package/templates/m3e-app/src/plugins/capacitor/index.ts +14 -0
  146. package/templates/m3e-app/src/plugins/capacitor/useAndroidBackButton.ts +36 -0
  147. package/templates/m3e-app/src/plugins/capacitor/useKeyboard.ts +48 -0
  148. package/templates/m3e-app/src/plugins/capacitor/useSplashScreen.ts +43 -0
  149. package/templates/m3e-app/src/plugins/capacitor/useStatusBar.ts +16 -0
  150. package/templates/m3e-app/src/plugins/framework7.plugin.ts +36 -0
  151. package/templates/m3e-app/src/plugins/i18n.plugin.ts +87 -0
  152. package/templates/m3e-app/src/plugins/m3e.plugin.ts +22 -0
  153. package/templates/m3e-app/src/plugins/seed.plugin.ts +7 -0
  154. package/templates/m3e-app/src/plugins/sqlite.plugin.ts +32 -0
  155. package/templates/m3e-app/src/router/global/global.routes.ts +12 -0
  156. package/templates/m3e-app/src/router/index.ts +20 -0
  157. package/templates/m3e-app/src/shared/components/error/404.vue +13 -0
  158. package/templates/m3e-app/src/shared/components/layout/EmptyState.vue +30 -0
  159. package/templates/m3e-app/src/shared/components/layout/SectionHeader.vue +10 -0
  160. package/templates/m3e-app/src/shared/components/page/AppPage.vue +104 -0
  161. package/templates/m3e-app/src/shared/composables/navigation/useActiveTab.ts +39 -0
  162. package/templates/m3e-app/src/shared/composables/navigation/useContainerTransform.ts +117 -0
  163. package/templates/m3e-app/src/shared/composables/navigation/useNavigationGuard.ts +48 -0
  164. package/templates/m3e-app/src/shared/composables/navigation/useNavigationVisibility.ts +64 -0
  165. package/templates/m3e-app/src/shared/composables/navigation/useViewRouter.ts +25 -0
  166. package/templates/m3e-app/src/shared/composables/navigation/useWindowClass.ts +22 -0
  167. package/templates/m3e-app/src/shared/composables/theme/useThemeSettings.ts +155 -0
  168. package/templates/m3e-app/src/shared/database/candidates/capacitorSqlite.ts +36 -0
  169. package/templates/m3e-app/src/shared/database/candidates/index.ts +4 -0
  170. package/templates/m3e-app/src/shared/database/candidates/opfsSahPool.ts +25 -0
  171. package/templates/m3e-app/src/shared/database/candidates/types.ts +56 -0
  172. package/templates/m3e-app/src/shared/database/candidates/waSqlite.ts +56 -0
  173. package/templates/m3e-app/src/shared/database/database.ts +219 -0
  174. package/templates/m3e-app/src/shared/database/index.ts +3 -0
  175. package/templates/m3e-app/src/shared/database/migrations.ts +223 -0
  176. package/templates/m3e-app/src/shared/database/opfs.worker.ts +5 -0
  177. package/templates/m3e-app/src/shared/database/queries.ts +26 -0
  178. package/templates/m3e-app/src/shared/database/schema.ts +153 -0
  179. package/templates/m3e-app/src/shared/database/storage.ts +64 -0
  180. package/templates/m3e-app/src/shared/database/wa.worker.ts +5 -0
  181. package/templates/m3e-app/src/shared/utils/lazyRoute.ts +41 -0
  182. package/templates/m3e-app/src/shared/utils/resolvers/resolvers.ts +42 -0
  183. package/templates/m3e-app/src/shared/utils/textDirection.ts +22 -0
  184. package/templates/m3e-app/src/shared/utils/theme/themeSettings.ts +59 -0
  185. package/templates/m3e-app/src/shared/utils/tone.ts +8 -0
  186. package/templates/m3e-app/tests/benchmark.suite.test.ts +104 -0
  187. package/templates/m3e-app/tests/containerTransform.test.ts +58 -0
  188. package/templates/m3e-app/tests/fieldFormats.test.ts +25 -0
  189. package/templates/m3e-app/tests/lazyRoute.test.ts +30 -0
  190. package/templates/m3e-app/tests/locales.test.ts +73 -0
  191. package/templates/m3e-app/tests/migrations.test.ts +74 -0
  192. package/templates/m3e-app/tests/navigationGuard.test.ts +82 -0
  193. package/templates/m3e-app/tests/openDatabase.test.ts +54 -0
  194. package/templates/m3e-app/tests/sales.repository.test.ts +329 -0
  195. package/templates/m3e-app/tests/storage.test.ts +117 -0
  196. package/templates/m3e-app/tests/textDirection.test.ts +11 -0
  197. package/templates/m3e-app/tooling/linkedPackages.ts +112 -0
  198. package/templates/m3e-app/tsconfig.json +21 -0
  199. package/templates/m3e-app/vite.config.ts +144 -0
@@ -0,0 +1,325 @@
1
+ # Component catalogue
2
+
3
+ Every component is auto-imported by `M3eResolver`; write the tag, never an import. Composables
4
+ (`useSnackbar`, `useDialog`, `useActionSheet`, `useHaptics`, `useReducedMotion`) are auto-imported
5
+ too. Each section names the spec page to read when a detail is not covered here.
6
+
7
+ ## Actions
8
+
9
+ **`M3Button`** - `variant` filled | tonal | outlined | elevated | text, `size` xs | s | m | l | xl,
10
+ `shape` round | square, `toggle` + `v-model:selected`, slots `#icon` (receives `selected`), `#trailing`.
11
+ Hierarchy: one filled action per screen region; tonal for secondary; outlined/text below that. Size
12
+ `s` is the default for in-content actions, `m` for a screen's primary action and sheet footers, `l`/`xl`
13
+ for hero moments only. → buttons/specs
14
+
15
+ **`M3IconButton`** - `label` required, `variant` standard | filled | tonal | outlined, `width` narrow |
16
+ default | wide, `size`, `shape`, `toggle`. App-bar actions are `standard`; a toolbar's emphasised
17
+ action is `filled`. → icon-buttons/specs
18
+
19
+ **`M3ButtonGroup`** - `variant` standard (pressed button widens 15%, neighbours give way) or
20
+ connected (2dp gaps, replaces segmented buttons; use toggle buttons inside for single select), `size`.
21
+ → button-groups/specs
22
+
23
+ **`M3SplitButton`** - primary action + `#menu`; pair with `M3Menu` anchored inside the menu slot.
24
+ → split-button/specs
25
+
26
+ **`M3Fab`** - `label` required, `size` small | default | medium | large, `color` *-container (default)
27
+ or solid, `extended` (undefined = plain; true/false = extended FAB shown/collapsed - collapse on scroll
28
+ down). One FAB per screen, for its single most important constructive action, in `AppPage`'s `#fab`.
29
+ → floating-action-button/specs, extended-fab/specs
30
+
31
+ **`M3FabMenu` + `M3FabMenuItem`** - when the main action has 2-6 variants. Items take `index`
32
+ (0 nearest the FAB). → fab-menu/specs
33
+
34
+ **`M3FabMorph`** - Framework7's FAB morph as a container transform: the FAB grows into a floating
35
+ toolbar of icon buttons (`variant="toolbar"`) or a panel (`panel`, with a scrim) and shrinks back.
36
+ `v-model:open`, `label`, `#icon`, default slot with `{ close }`. Use it when the FAB opens a set of
37
+ peer actions on one screen; variants of one action are a FAB menu.
38
+
39
+ ## Navigation
40
+
41
+ **Scroll behaviour** - `src/app/scroll.config.ts` sets it for the whole app: `topAppBar:
42
+ "enterAlways"` slides a small top app bar away with the content and back on the way up (the status
43
+ strip stays covered, `#bottom` and sticky `M3ListGroup` titles move with it); `navigationBar:
44
+ "hideOnScroll"` slides the navigation bar off while scrolling down. `AppPage` wires both; a page
45
+ passes `scrollBehavior` to override the top bar. Outside `AppPage`, `M3TopAppBar`'s
46
+ `scrollBehavior` and `useHideOnScroll(scroller)` give the same behaviour.
47
+
48
+ **`M3Breadcrumbs`** - `items` (`{ label, href? }`), `@select`, `max` (the middle collapses into a
49
+ menu past it), `label`. The last item is the current page. Fades the edge it overflows past.
50
+
51
+ **`M3NavigationBar` / `M3NavigationRail` + `M3NavigationItem`** - the shell already renders these from
52
+ `src/app/tabs.ts`; add a destination there. Items take `#icon="{ selected }"` (outlined → filled),
53
+ `badge` (number or `true`). `@reselect` fires on tapping the current destination.
54
+ → navigation-bar/specs, navigation-rail/specs
55
+
56
+ **`M3Tabs` + `M3Tab`** - `variant` primary (content-width indicator, optional `#icon`) for peer views
57
+ of one subject; secondary for subdivisions inside a primary tab. `scrollable` beyond ~4 tabs.
58
+ Arrow keys move. Swipeable pages: put the tabs in `AppPage`'s `#bottom` slot (pinned under the
59
+ bar), the pages in `M3TabPanels` + `M3TabPanel value`, bind one `v-model` to both and pass both
60
+ the same `createTabPager()` so the indicator follows the swipe. Give `M3TabPanels` a height; each
61
+ page scrolls on its own. A carousel or swipe row inside a page keeps its own sideways drag.
62
+ → tabs/specs
63
+
64
+ **`M3TopAppBar`** - rendered by `AppPage`. `small` for pushed pages, `medium`/`large` flexible for
65
+ roots and long titles. Tapping the bar outside its buttons scrolls the page to the top (Android's
66
+ status bar keeps taps for its shade); nav-bar reselect does the same. → app-bars/specs
67
+
68
+ **`M3FloatingToolbar`** - page actions over content: `variant` standard | vibrant, `#fab`,
69
+ `hideOnScroll`. Compose gives it no shadow (1dp with a FAB) - do not add one. **`M3DockedToolbar`** - a detail screen's persistent actions at the bottom edge.
70
+ → toolbars/specs
71
+
72
+ ## Containment
73
+
74
+ **`M3List` + `M3ListItem`** - `variant` segmented (default; each row its own surface, 2dp apart) or
75
+ standard. Items: `headline`, `supporting`, `overline`, `trailingText`, `multiline`, `clickable` or
76
+ `href`, `selected`, `tone="destructive"`; slots `#leading` (icon, `M3Shape` avatar 40dp), `#trailing`
77
+ (decoration), `#action` (a control with its own target). Swipe actions: `M3SwipeAction` buttons
78
+ (`label`, `tone`, `@click`) in `#swipe-start` / `#swipe-end`; `swipe-full="end"` arms the outermost
79
+ action past half the row (deletes, archives - pair with an undo snackbar), `v-model:swiped` reads
80
+ the open side. One row open at a time; a tap outside closes it. Expandable items: put the hidden
81
+ content in `#details` (`v-model:expanded`); `M3List accordion` keeps one open, as Framework7's
82
+ accordion list does - FAQs, settings groups, order lines. `M3List sortable` is Framework7's
83
+ sortable list: a drag handle on every item plus long-press-and-drag on the row; handle
84
+ `@sort="(from, to) => (rows = moveItem(rows, from, to))"` and persist the order yourself. Not for
85
+ `M3VirtualList`. → lists/specs
86
+
87
+ **`M3Carousel`** - Compose's carousel, keyline for keyline: `items`, `label`, `variant`
88
+ multi-browse (default; browsing many items - photos, products) | hero (one featured item at a time;
89
+ a fling moves one) | uncontained (fixed `item-width`, coasts without snapping), `item-width`
90
+ (preferred large width, 186), `item-spacing` 8, `content-padding` 16, `height`, `v-model:item`.
91
+ Items are laid out full size and masked, so put a full-bleed picture in the slot and let it
92
+ parallax; fade labels with `--m3-carousel-item-progress` and slide them with
93
+ `--m3-carousel-mask-start`. The slot's `scrollTo` brings a tapped item forward. → carousel/specs
94
+
95
+ **`M3Tree`** - Framework7's treeview from data: `items` (`{ id, label, supporting?, children?,
96
+ lazy? }`), `label`, `mode` select (`v-model:selected`) | check (`v-model:checked` leaf ids,
97
+ tri-state branches), `v-model:expanded`, `load` for lazy children, `#icon="{ node, expanded }"`,
98
+ `#trailing`. Categories, charts of accounts, permission sets.
99
+
100
+ **`M3DataTable`** - Framework7's data table: `rows`, `columns` (`{ key, label, value?, format?,
101
+ numeric?, sortable?, width? }`), `row-key`, `label`, `v-model:sort` (sorts locally unless
102
+ `:sort-locally="false"` - then sort in SQL from the model), `selectable` + `v-model:selected`,
103
+ `max-height` + `sticky-first-column` for wide tables, `dense`, `#cell`, `#footer` (totals), `#empty`.
104
+ For phones prefer a list with the key fields; use the table where rows are compared across columns.
105
+
106
+ **`M3Card`** - `variant` elevated | filled | outlined; `clickable` makes the whole card one target -
107
+ then put no other buttons inside. → cards/specs
108
+
109
+ **`M3Divider`** - only where whitespace and surfaces do not already separate. → divider/specs
110
+
111
+ ## Overlays
112
+
113
+ **`M3BottomSheet`** - `v-model:open`, `title`, `dismissible`, slots `#header`, default (scrolls),
114
+ `#footer` (fixed actions). Spring-driven; drag from handle or top-scrolled content. Prefer it to a
115
+ dialog for anything with more than one choice or any form. → bottom-sheets/specs
116
+
117
+ **`M3StandardBottomSheet`** - the non-modal sheet beside the content (a map, a route, a player):
118
+ `v-model:detent` peek | half | expanded (| hidden with `hideable`), `label`, `title`, `peekHeight`
119
+ (56 by default - raise it to show the title), `half`. Drags anywhere until expanded, then the content
120
+ scrolls; pulling down from the content's top brings it back. Fixed to the window: set
121
+ `--m3-standard-sheet-inset-bottom` above a navigation bar and pad the page by the peek.
122
+
123
+ **Action sheet** - `await useActionSheet().open({ title, supporting, quickActions, groups })` resolves
124
+ the chosen id or null. Options with icons in segmented groups; `selected` shows a check, `tone:
125
+ "destructive"` paints error. Icons are components wrapped in `markRaw`.
126
+
127
+ **`M3Dialog` / `useDialog().confirm({...})`** - only for a decision that must interrupt: destructive
128
+ confirmations, required choices. `destructive` paints the confirm action; `icon` centres the headline.
129
+ → dialogs/specs
130
+
131
+ **`M3FullScreenDialog`** - Framework7's popup, M3's full-screen dialog: `v-model:open`, `title`,
132
+ `confirm-label` (+ `confirm-disabled`), `#actions`, `@confirm`, `@close`. For a task that needs the
133
+ whole phone screen - a new order, an intake form; from 600dp it becomes a basic dialog. While the
134
+ form is dirty pass `:dismissible="false"` and ask in `@close` before discarding (`useDialog`
135
+ confirmations draw above it).
136
+
137
+ **`M3Menu` + `M3MenuItem` + `M3MenuGroup`** - anchored to an element ref (`:anchor`), `variant`
138
+ standard | vibrant; groups give the expressive segmented look. `checkable` for single/multi select.
139
+ A `#submenu` slot of items makes a cascading item (trailing arrow; opens beside it on tap, hover or
140
+ the arrow key); choosing inside closes the whole chain, Back closes the submenu alone. Keep it one
141
+ level deep on phones. → menus/specs
142
+
143
+ **Snackbar** - `await useSnackbar().show({ message, action, duration })` resolves `action` |
144
+ `dismissed` | `timeout`. One action max, never for errors that need a decision. Undo is the classic.
145
+ → snackbar/specs
146
+
147
+ **In-app notification** - `await useNotification().show({ title, text, source, meta, icon, duration })`
148
+ resolves `opened` | `dismissed` | `timeout` | `replaced`. Framework7's notification: a banner from the
149
+ top for something that happened elsewhere (a new order, a finished sync) that the person may want
150
+ to open; a snackbar is for feedback on what they just did. One at a time - a new one replaces it.
151
+
152
+ **`M3SideSheet`** - `v-model:open`, `side` start | end, `title`; filters and secondary detail beside
153
+ the content. **`M3ModalNavigationRail`** - the expressive replacement for the navigation drawer;
154
+ closes itself once a destination is chosen. → side-sheets/specs, navigation-rail/specs
155
+
156
+ **`M3Popover`** - Framework7's popover: any content anchored to an element. `anchor` (element),
157
+ `v-model:open`, `label`, `side` bottom | top, `align` start | center | end, `modal` (scrim + focus
158
+ trap); default slot gets `{ close }`. Flips and stays on screen, grows out of the anchor, closes on a
159
+ tap outside, Escape or back, and focus returns to the anchor. For a few controls or an explanation
160
+ tied to one element; a list of actions is `M3Menu`.
161
+
162
+ **`M3Tooltip`** - plain (long-press, hover, focus; labels an icon button) or rich (`title`, text,
163
+ actions; explains, never holds the only path to a task). Placed so it never leaves the screen.
164
+ → tooltips/specs
165
+
166
+ ## Date and time
167
+
168
+ Values are strings end to end - `IsoDate` (`YYYY-MM-DD`) and `IsoTime` (`HH:mm`, 24-hour) - so no
169
+ timezone or DST shift can move a picked day. Utilities (`formatIso`, `parseLocalDate`,
170
+ `formatIsoTime`, `uses12Hour`...) are exported beside the components.
171
+
172
+ **`M3DatePicker`** - `v-model`, `v-model:open`, `presentation` dialog (Material's modal, default) |
173
+ sheet (Framework7's, one-handed). `modes` defaults to calendar + typed input in a dialog, calendar +
174
+ wheel in a sheet. Edits a draft; only OK commits. `min`, `max`, `isDisabled`, `locale`, every label
175
+ a prop. **`M3Calendar`** - the grid alone, inline or docked in a card: `v-model:value`, or
176
+ `mode="range"` with `v-model:start` / `v-model:end`. → date-pickers/specs
177
+
178
+ **`M3TimePicker`** - `v-model` `HH:mm`, `presentation` dialog | sheet, `modes` dial + keyboard
179
+ (dialog) or dial + wheel (sheet), `hour12` (else the locale decides), `minuteStep`. The dial is
180
+ **`M3ClockDial`**: 24-hour faces put 00 and 13-23 on the inner ring. → time-pickers/specs
181
+
182
+ **`M3WeekStrip`** - the head of an agenda: `v-model` `IsoDate`, `label`, `marks` (`{ [IsoDate]:
183
+ count }` for the dots), `markLabel`, `locale`, `firstDay`. Swipes week to week endlessly; pin it
184
+ under the app bar through `AppPage`'s `#bottom`, the day's items in a list below. Inset with
185
+ `--m3-week-strip-inset`, never padding.
186
+
187
+ **`M3WheelPicker`** - Framework7's picker: drums over one band, `columns` of `{ key, label,
188
+ options, flex, align, loop }`, `v-model` keyed by column; `loop` rolls a drum over at its ends. Built like Framework7's: native scroll-snap, flat rows, gradient fades in `--m3-wheel-surface`
189
+ (the colour behind it) - no per-row 3D or masks, which made it lag on phones - and a
190
+ tick per detent. **`M3DateWheel`** / **`M3TimeWheel`** are the ready date and time drums; put them in
191
+ an `M3BottomSheet` with a draft when the choice needs confirming. No M3 spec - it is the F7 parity
192
+ piece.
193
+
194
+ ## Photos
195
+
196
+ **`M3PhotoBrowser`** - Framework7's photo browser: `photos` (`{ src, alt, caption?, width?, height? }`),
197
+ `v-model:open`, `v-model:index`, `label`, `#actions` for the bar (share, delete). Swipe between,
198
+ pinch or double-tap to zoom, pan when zoomed, swipe up or down to close; only neighbours load. Give
199
+ `width`/`height` when known. It is drawn on black - call `useDarkStatusBar(() => open.value)` so the
200
+ status bar icons turn light while it shows.
201
+
202
+ **`M3Image`** - lazy image: `src`, `alt` (`""` when decorative), `width` + `height` or `ratio` to
203
+ reserve its space, `placeholder` (a colour or a tiny image, drawn blurred), `fit`, `eager` for the
204
+ first screen, `#error`. Fades in once decoded; cached pictures appear at once.
205
+
206
+ **`M3Pager`** + **`M3PagerPage`** - Framework7's swiper as a pager on native scroll-snap: one page per
207
+ swipe, `v-model:page`, `label`; dots underneath, or `#footer` with `{ page, count, progress, go,
208
+ next, previous }` for Skip / Next. **`M3PageIndicator`** (`count`, `progress`, `@select`) is the
209
+ dots alone; its pill follows the finger. Onboarding, a product's photos, a feature tour.
210
+
211
+ ## Lists at scale
212
+
213
+ **`M3ListGroup` + `M3ListIndex`** - Framework7's contacts list and list index: groups whose titles
214
+ stick under the app bar (`title`, `indexKey`; `groupKey(label)` folds accents and buckets digits
215
+ under `#`), and an A–Z rail (`keys`, `label`) in `AppPage`'s `#fixed` slot that jumps as the finger
216
+ drags. Pad the content ~24px at the end edge so rows clear the rail.
217
+
218
+ **`M3InfiniteScroll`** - after a list: `:load` returns a promise and resolves `false` when there is
219
+ no more; failures wait for the user's retry; `endText` closes the list; expose `reset()` after a new
220
+ filter. Feed it from a repository with `LIMIT/OFFSET` (or a keyset) - never load everything to
221
+ slice it in memory. **`M3Timeline` + `M3TimelineItem`** - an order's journey, a patient's visits:
222
+ `title`, `time`, `supporting`, `state` done | current | upcoming, `#icon` for the current step,
223
+ `stateLabel` so the state is read out.
224
+
225
+ **`M3VirtualList`** - thousands of rows against the page's own scroller (the app bar still
226
+ collapses): `items`, `itemSize` (number or function: 56 / 72 / 88 + 2 for the segment gap),
227
+ `itemKey`, `inset`. Rows are recycled - row components must render from props alone; `recycle=false`
228
+ keys by `itemKey` for rows with local state. **`M3PullToRefresh`** - `:refresh` returns a promise;
229
+ the loading indicator fills with the pull and loops until it settles.
230
+
231
+ ## Progress
232
+
233
+ **`M3Skeleton` + `M3SkeletonBlock` + `M3SkeletonText`** - Framework7's skeleton: placeholders in
234
+ the shape of the content on its way, for loads you expect to take more than a moment (a list from
235
+ the database, a detail screen). Mirror the real layout exactly - same rows, same type scales via
236
+ `M3SkeletonText typescale` - so nothing jumps when it lands. `effect` wave (default) | pulse | none;
237
+ set `--m3-skeleton-surface` to the colour behind the group. Use `M3LoadingIndicator` instead when
238
+ there is no layout to predict.
239
+
240
+ **`M3LoadingIndicator`** - waits up to a few seconds, or `progress` 0-1 for determinate. `contained`
241
+ over content. Replaces every spinner. → loading-indicator/specs
242
+
243
+ **`M3LinearProgress` / `M3CircularProgress`** - `value` 0-1 or omitted (indeterminate), `wavy` (default
244
+ on), `thickness`; circular takes `gauge` and a centred slot. Linear sits 4dp in from the edges.
245
+ → progress-indicators/specs
246
+
247
+ ## Selection and input
248
+
249
+ **`M3Switch`** (`icons`, `bothIcons`) for an instant on/off; **`M3Checkbox`** for items in a list
250
+ or a form submitted later; **`M3Radio`** (`v-model` + `value`) for one of few visible options - more
251
+ than ~5, use an action sheet. **`M3Slider`** - `size` xs..xl, `step`, `ticks`, `#icon` from m, `format`
252
+ for the value bubble. **`M3RangeSlider`** - `v-model:start` / `v-model:end`, `startLabel` /
253
+ `endLabel` (each handle is its own slider), `minDistance` keeps them apart. **`M3Stepper`** - Framework7's stepper for small counts (cart quantity, guests, a dose):
254
+ `v-model`, `label`, `min`/`max`/`step` (decimals stay clean), `variant` outlined | tonal, `size` s | m,
255
+ `editable` (type the value; a decimal comma is read), `format` for units. Holding a button repeats
256
+ and speeds up across wide ranges. Use a slider when the exact value matters less than its position.
257
+ **`M3Chip`** - `kind` assist | filter (`v-model:selected`) | input
258
+ (`removable`) | suggestion. **`M3TextField`** - `variant` filled (default) | outlined, `supporting`,
259
+ `error`, `maxlength` counter, `prefix`/`suffix`, `multiline`, `#leading`/`#trailing`; native
260
+ attributes pass through. **`M3ExposedDropdown`** - Compose's exposed dropdown menu: `options`
261
+ (`{ value, label, supporting?, disabled? }`), `v-model`, `label`; read-only it is a select (arrow
262
+ keys, type-ahead), `editable` makes it Framework7's autocomplete (accent- and case-insensitive
263
+ filter, bolded match, `limit`). For a remote source, `:filter="false"` + `v-model:query` +
264
+ `loading`. Use it over radios past ~5 options, and over an action sheet when the field sits in a
265
+ form. **`M3SmartSelect`** - Framework7's smart select, a list row that opens a sheet of options:
266
+ `options`, `v-model` (an array with `multiple`), `label`, `placeholder`; search appears past
267
+ `searchFrom` (10). Prefer it to the exposed dropdown for multi-choice and inside settings lists.
268
+ **`M3SearchBar`** - `v-model`, `@search`, `#leading`/`#trailing`, for
269
+ filtering what is already on screen. **`M3SearchView`** - the bar that opens into a full-screen
270
+ view (`v-model`, `v-model:expanded`, `placeholder`; results in the default slot with `{ query }`,
271
+ recent searches when the query is empty); use it for searching a whole data set.
272
+ → switch, checkbox, radio-button, sliders, chips, text-fields, search /specs
273
+
274
+ ## Charts
275
+
276
+ `M3LineChart` (`area` for filled), `M3BarChart` (`stacked`) and `M3DonutChart` - plain SVG, no
277
+ library: `labels` + `series` (`{ label, values, color? }`, `null` breaks a line) or `segments`
278
+ (`{ label, value }`), `label` (the accessible name), `format` for numbers (use
279
+ `Intl.NumberFormat` compact). Colours come from the theme's roles; touching reads values;
280
+ screen readers get a hidden table. Lines for change over time, bars to compare categories, a
281
+ donut for parts of one whole (at most ~6 segments). Feed them aggregates from SQL, never raw rows.
282
+
283
+ ## Forms
284
+
285
+ **`M3TextEditor`** - Framework7's text editor: `v-model` HTML, `label`, `placeholder`, `toolbar`
286
+ (commands and `"|"`), `labels` for i18n. Bold, italic, underline, strikethrough, lists, links
287
+ (through a popover), clear formatting. Its HTML is sanitised in and out (`sanitizeHtml` is exported
288
+
289
+ - run it again wherever stored HTML is rendered with `v-html`). Use a plain multiline `M3TextField`
290
+ unless formatting is the point.
291
+
292
+ **`M3SignaturePad`** - proof of delivery: `v-model:strokes` (fractions of the pad, so a draft or a
293
+ rotation redraws it sharp), `height`, `label`, `placeholder`; ref methods `undo()`, `clear()`,
294
+ `toDataURL(type, background)` for the upload, `toSvg()`. Always pair it with a typed name - signing
295
+ has no keyboard path.
296
+
297
+ **`M3ColorPicker`** - `v-model` `#rrggbb`, hue / chroma / tone sliders in HCT with previewing tracks,
298
+ a hex field, optional `swatches`. Put it in a sheet with a draft and apply on confirm when the
299
+ colour drives something expensive, such as the app theme.
300
+
301
+ **`useFormDraft(key, state, options)`** - keeps what is typed into a form as a draft (debounced,
302
+ written at once when the app goes to the background) and restores it when the form opens again.
303
+ Returns `{ restored, savedAt, error, clear, flush }`; call `clear()` on submit or discard. `storage`
304
+ takes any async store (default `localStorage`), `version` drops drafts from an older form, `maxAge`
305
+ expires them. Never draft passwords or card numbers - give it only the fields worth keeping.
306
+
307
+ ## Messages
308
+
309
+ **`M3Messages`** - a conversation: `messages` (`{ id, sent, at, text?, author?, avatar?, status?,
310
+ image? }`, oldest first), `label`, `locale`, `authors` for a group (names and avatars), `typing`
311
+ (`true` or `{ author }`), label props for i18n. It scrolls with the page: opens at the newest,
312
+ follows new ones while the reader is there, keeps their place otherwise and counts what arrived.
313
+ Older history goes in `#before` as `<M3InfiniteScroll edge="start">` - page it, never pass
314
+ thousands. `@hold` (long-press) for a message menu via `useActionSheet`, `@press` for an image,
315
+ `@retry` for a failed send. Give images `width`/`height` so nothing jumps as they load.
316
+ **`M3MessageBar`** - the composer, in `AppPage`'s `#fixed`: `v-model`, `label`, `@send` (trimmed
317
+ text; it clears itself), `#leading` (attach), `#trailing` (emoji), `#idle` (stands in for send
318
+ while empty), `enterSends` for hardware keyboards. It publishes its height for `M3Messages`; zero
319
+ the page's own bottom padding (`.page-content { padding-bottom: 0 }`) on a chat page.
320
+
321
+ ## Shape and decoration
322
+
323
+ **`M3Shape`** - masks its content to one of the 35 shapes (square box). **`M3ShapeMorph`** - an SVG
324
+ shape that springs into the next when `shape` changes; fills with `currentColor`. **`M3Badge`** -
325
+ dot or count on its slot. Details: [shapes-type.md](shapes-type.md).
@@ -0,0 +1,42 @@
1
+ # Layout
2
+
3
+ ## The shell
4
+
5
+ - Window classes from `useWindowClass()`: compact < 600dp, medium < 840, expanded < 1200, large.
6
+ Key layout on these, never on device type - a phone in landscape is medium.
7
+ - Compact: `M3NavigationBar` floats at the bottom; the shell writes `--app-nav-offset` (64px while
8
+ visible) and `--app-bottom-inset` (offset + gesture area). Anything floating above content uses
9
+ them; nothing measures the bar.
10
+ - Medium and up: `M3NavigationRail` beside the views, expandable from its menu button.
11
+ - Pushed pages hide the bar (`AppPage back`), the rail stays.
12
+
13
+ ## Page anatomy (`AppPage`)
14
+
15
+ ```vue
16
+ <AppPage :title="t('feature.title')" name="feature"> <!-- large flexible bar -->
17
+ <template #actions><M3IconButton :label="…"><i-ms-search-rounded /></M3IconButton></template>
18
+ <SectionHeader :title="t('feature.section')" />
19
+ <M3List variant="segmented" inset>…</M3List>
20
+ <template #fab><M3Fab :label="…"><i-ms-add-rounded /></M3Fab></template>
21
+ <template #fixed><MyFeatureSheet v-model:open="open" /></template>
22
+ </AppPage>
23
+ ```
24
+
25
+ A pushed page: `<AppPage :title back>` (small bar, back button, bar hidden); `variant="medium"` for a
26
+ long title. Sheets and toolbars that must not scroll go in `#fixed`.
27
+
28
+ ## Spacing and rhythm
29
+
30
+ - Content gutters 16dp (`px-4`, `mx-4`, `inset` on lists); section labels 24dp (`px-6`).
31
+ - Between blocks 12-24dp; inside a block 8-16dp. Segments 2dp apart.
32
+ - Touch targets ≥ 48dp - the components extend small visuals with an invisible target.
33
+ - At most ~840dp of reading width on large windows: wrap long content in `max-w-[52rem] mx-auto`.
34
+
35
+ ## Placement
36
+
37
+ - One FAB, bottom-end, in `#fab`. With a floating toolbar, the FAB goes in the toolbar's `#fab`.
38
+ - Destructive actions go behind a menu or the end of an action sheet, never next to the main action.
39
+ - A detail screen's state changes go in `M3DockedToolbar` (connected button group).
40
+ - Forms of more than two fields open in an `M3BottomSheet` with the submit button in `#footer`.
41
+
42
+ See [sources.md](sources.md) → Layout.
@@ -0,0 +1,51 @@
1
+ # Motion
2
+
3
+ M3 Expressive motion is physics: springs with a damping ratio and a stiffness. **Spatial** springs
4
+ move position, size, rotation and shape and may overshoot; **effects** springs change colour and
5
+ opacity and never do. Speed follows the size of what moves: **fast** for small components, **default**
6
+ for partial-screen surfaces (sheets, menus), **slow** for full-screen moves.
7
+
8
+ ## The tokens
9
+
10
+ | Token | Expressive ζ / k | CSS easing var | Duration var |
11
+ | ----------------------------- | --------------------------- | ------------------------------------- | ------------------------------- |
12
+ | fast spatial | 0.6 / 800 (≈9.5% overshoot) | `--md-sys-motion-spring-fast-spatial` | `…-fast-spatial-duration` 350ms |
13
+ | default spatial | 0.8 / 380 | `…-default-spatial` | 500ms |
14
+ | slow spatial | 0.8 / 200 | `…-slow-spatial` | 650ms |
15
+ | fast / default / slow effects | 1.0 / 3800, 1600, 800 | `…-fast-effects` etc. | 150 / 200 / 300ms |
16
+
17
+ Spatial easings are generated `linear()` curves that keep the overshoot; effects are the official
18
+ beziers. Tailwind: `ease-fast-spatial`, `ease-default-effects`… with `duration-spring-fast`,
19
+ `duration-spring-default`, `duration-spring-slow`. Legacy tokens (`--md-sys-motion-easing-emphasized-
20
+ decelerate`, `--md-sys-motion-duration-medium2`…) remain for transitions that are not physical moves:
21
+ dialogs entering, fades.
22
+
23
+ ## Choosing the mechanism
24
+
25
+ - **CSS transition on a token** - state changes nobody interrupts: a toggle, a selected tab indicator,
26
+ a chip check, a list row rounding off.
27
+ - **`animateSpring`** (`@cavulsqa/m3e`) - anything a gesture drives or that can reverse mid-flight:
28
+ sheets, drags, interrupted opens. It carries velocity into the new target; a CSS transition restarts
29
+ from zero and stutters.
30
+ - **`useFrame`** (`@cavulsqa/m3e-vue`) - continuous drawing (progress, loaders). One shared rAF loop;
31
+ pause when off screen with `useInView`.
32
+ - **Vue `<Transition>` / `<TransitionGroup>`** - enter/leave of elements, with the tokens above.
33
+
34
+ ## Patterns already in the app
35
+
36
+ - Page change: `m3e-axis` shared-axis X (`assets/css/layout/transitions.css`) - slide 64px on slow
37
+ spatial, fade-through. Do not set per-route transitions.
38
+ - Press: shapes tighten on default effects (no bounce); selection reshapes on spatial.
39
+ - Enter from a FAB or anchor: scale/translate from that corner, stagger 15-30ms per item.
40
+ - Exit is always shorter than enter and accelerates.
41
+
42
+ ## Rules
43
+
44
+ - Animate `transform` and `opacity`. A layout property may animate only on a small element (a button's
45
+ padding in a group); never on a page-sized surface.
46
+ - Under reduced motion spatial durations are 1 ms (not 0 - `transitionend` must still fire); keep
47
+ fades and morphs, drop rotation, bounce and travel. JS motion passes `instant: reduced.value`.
48
+ - Haptics accompany a confirmed state change (`useHaptics().tick()` on a toggle, `confirm()` on a
49
+ completed action), never scrolling or hovering.
50
+
51
+ See [sources.md](sources.md) → Motion.
@@ -0,0 +1,48 @@
1
+ # Shape and type
2
+
3
+ ## Corner scale
4
+
5
+ | Tailwind | Token | dp | Typical use |
6
+ | ---------------------- | --------------------- | ---- | ------------------------------------------------- |
7
+ | `rounded-xs` | extra-small | 4 | inner corners of segmented lists, menus, snackbar |
8
+ | `rounded-sm` | small | 8 | chips, small thumbnails |
9
+ | `rounded-md` | medium | 12 | cards, inner panels |
10
+ | `rounded-lg` | large | 16 | outer corners of segments, grouped blocks |
11
+ | `rounded-lg-increased` | large-increased | 20 | medium FAB |
12
+ | `rounded-xl` | extra-large | 28 | sheets, dialogs, hero blocks |
13
+ | `rounded-xl-increased` | extra-large-increased | 32 | large hero surfaces |
14
+ | `rounded-2xl` | extra-extra-large | 48 | full-bleed media corners |
15
+ | `rounded-full` | full | pill | buttons, chips at rest, indicators |
16
+
17
+ Nested corners stay concentric: inner radius = outer radius − padding.
18
+
19
+ ## The shape library
20
+
21
+ 35 shapes (`MATERIAL_SHAPES`): circle, square, slanted, arch, fan, arrow, semiCircle, oval, pill,
22
+ triangle, diamond, clamShell, pentagon, gem, sunny, verySunny, cookie4Sided, cookie6Sided,
23
+ cookie7Sided, cookie9Sided, cookie12Sided, ghostish, clover4Leaf, clover8Leaf, burst, softBurst,
24
+ boom, softBoom, flower, puffy, puffyDiamond, pixelCircle, pixelTriangle, bun, heart. All visible in
25
+ Gallery → Shapes.
26
+
27
+ - **Use shapes for identity and emphasis, not for controls**: avatars and leading icons in lists
28
+ (`M3Shape` 40dp with `TONE_CLASSES`), hero art, empty states, status marks, selected swatches.
29
+ - **Morph to mark a change of state**: `M3ShapeMorph` springs between two shapes - selection, a step
30
+ completing, a status advancing.
31
+ - **Rounded shapes for calm, spiky (burst, boom) for celebration or alerts** - sparingly.
32
+ - A shape needs a square box; a photo cut to a shape uses `M3Shape` around the `<img>`.
33
+
34
+ ## Type
35
+
36
+ Google Sans Flex (self-hosted, `rond.css` - weight + roundness axes) for every style. Utilities:
37
+ `type-<style>` and `type-<style>-emphasized`, styles display/headline/title/body/label ×
38
+ large/medium/small. Sizes are in rem, so the user's font scale applies.
39
+
40
+ - Titles of screens: the app bar owns them. In content, `type-title-medium` for card titles,
41
+ `type-title-small-emphasized` (primary) for section labels, `type-body-large` for list headlines,
42
+ `type-body-medium` for supporting text, `type-label-large` for button-like labels.
43
+ - **Emphasized** styles are for the one thing on a surface that should land first: a total, a hero
44
+ headline, a selected value - not for every heading.
45
+ - `font-rounded` (ROND 100) belongs to display and headline moments in heroes and totals, never body.
46
+ - Numbers that change in place get `tabular-nums`.
47
+
48
+ See [sources.md](sources.md) → Shape, Typography.
@@ -0,0 +1,53 @@
1
+ # Official sources
2
+
3
+ m3.material.io renders in the browser only (fetching returns an empty shell): open it in a browser
4
+ tool. When the spec page and androidx source disagree, the androidx token files win - they are
5
+ generated from the same design-token database and are newer.
6
+
7
+ ## Foundations
8
+
9
+ - Overview and blog: https://m3.material.io/blog/building-with-m3-expressive
10
+ - Motion theming: https://m3.material.io/blog/m3-expressive-motion-theming
11
+ - State layers: https://m3.material.io/foundations/interaction/states/state-layers
12
+ - Accessibility: https://m3.material.io/foundations/accessible-design/overview
13
+ - Layout and window size classes: https://m3.material.io/foundations/layout/applying-layout ·
14
+ https://developer.android.com/develop/ui/compose/layouts/adaptive/use-window-size-classes
15
+
16
+ ## Styles
17
+
18
+ - Motion: https://m3.material.io/styles/motion/overview/how-it-works ·
19
+ specs and web curves: https://m3.material.io/styles/motion/overview/specs ·
20
+ transitions: https://m3.material.io/styles/motion/transitions/transition-patterns
21
+ - Colour: https://m3.material.io/styles/color/roles ·
22
+ https://m3.material.io/styles/color/choosing-a-scheme ·
23
+ https://m3.material.io/styles/color/dynamic-color/overview ·
24
+ custom colours: https://m3.material.io/styles/color/advanced/define-new-colors
25
+ - Shape: https://m3.material.io/styles/shape/corner-radius-scale ·
26
+ https://m3.material.io/styles/shape/shape-morph
27
+ - Typography: https://m3.material.io/styles/typography/type-scale-tokens ·
28
+ https://m3.material.io/styles/typography/fonts
29
+ - Elevation: https://m3.material.io/styles/elevation/tokens
30
+
31
+ ## Components (append `/specs` or `/guidelines`)
32
+
33
+ `https://m3.material.io/components/<name>/specs` for: buttons, icon-buttons, button-groups,
34
+ split-button, floating-action-button, extended-fab, fab-menu, loading-indicator,
35
+ progress-indicators, toolbars, navigation-bar, navigation-rail, app-bars, search, bottom-sheets,
36
+ side-sheets, dialogs, menus, lists, carousel, chips, sliders, switch, tabs, snackbar, cards,
37
+ text-fields, checkbox, radio-button, badges, divider, tooltips, date-pickers, time-pickers.
38
+
39
+ ## Source of the numbers
40
+
41
+ - Compose token files:
42
+ https://github.com/androidx/androidx/tree/androidx-main/compose/material3/material3/src/commonMain/kotlin/androidx/compose/material3/tokens
43
+ - Shapes: …/material3/MaterialShapes.kt · loader: …/LoadingIndicator.kt · wavy: …/WavyProgressIndicator.kt
44
+ (same folder as above, without `/tokens`)
45
+ - Colour library: https://github.com/material-foundation/material-color-utilities/tree/main/typescript
46
+ - MDC-Android component docs (before/after numbers):
47
+ https://github.com/material-components/material-components-android/tree/master/docs/components
48
+
49
+ ## Where a spec lands in this repo
50
+
51
+ `packages/m3e` holds the tokens and geometry (each file's JSDoc links its source);
52
+ `packages/m3e-vue` the components (each SFC's JSDoc links its spec page). Extend those, then use the
53
+ result here.
@@ -0,0 +1,65 @@
1
+ ---
2
+ name: module-architecture
3
+ description: Where code goes in this app and how to add a feature end to end. Use when creating a new screen, module, route, domain, repository, composable, or when deciding whether something belongs in modules, domains or shared. Covers the dependency direction, the file layout of a module, and the checklist for wiring a feature into the shell.
4
+ ---
5
+
6
+ # Module architecture
7
+
8
+ ```
9
+ src/
10
+ ├── app/tabs.ts the navigation destinations, as data
11
+ ├── router/index.ts aggregates module routes, catch-all last
12
+ ├── domains/<domain>/<x>.repository.ts SQL only
13
+ ├── modules/<feature>/
14
+ │ ├── router/routes/<feature>.routes.ts
15
+ │ ├── views/<Name>View.vue
16
+ │ ├── components/*.vue
17
+ │ └── composables/use*.ts
18
+ └── shared/ what two modules genuinely both need
19
+ ```
20
+
21
+ ## The seam
22
+
23
+ | Layer | Owns | Never contains |
24
+ | ---------- | --------------------------------------- | -------------------------------------------- |
25
+ | View | Wiring a composable to components | Business logic, SQL |
26
+ | Composable | State, queries, actions for one feature | Markup |
27
+ | Repository | Plain functions over Kysely | `ref`, lifecycle, Framework7, module imports |
28
+ | Component | Props in, emits out | Database access |
29
+
30
+ Dependencies run **modules → domains → shared → packages**, never backwards. A repository importing
31
+ from a module, or `shared` importing from `modules`, means something is in the wrong place.
32
+
33
+ ## Adding a feature
34
+
35
+ 1. `modules/<feature>/` with the four folders. Templates: [file-templates.md](file-templates.md).
36
+ 2. SQL in `domains/<domain>/<domain>.repository.ts`, taking the database as its first parameter.
37
+ 3. Routes in `modules/<feature>/router/routes/<feature>.routes.ts`, default-exported, registered in
38
+ `src/router/index.ts` **before** the global catch-all.
39
+ 4. A tab in `src/app/tabs.ts` only if it is a top-level section — with both `iconIos` and `iconMd`.
40
+ Otherwise it is a pushed page, and pushed pages are an `AppPage` with `back`, which hides the navigation bar.
41
+ 5. Strings in **both** `locales/en.json` and `locales/fr.json`. A missing key renders as the key.
42
+ Remember `@` and `|` are message syntax.
43
+ 6. A test in `tests/` for anything with SQL.
44
+ 7. `vp check`, `vp test`, `pnpm type-check`.
45
+
46
+ ## shared/ is not a junk drawer
47
+
48
+ Something moves to `shared/` when a second module imports it **today**. The test: name the second
49
+ caller. If you cannot, it lives in the module that uses it.
50
+
51
+ ## Auto-imports
52
+
53
+ `ref`, `computed`, `watch`, lifecycle hooks, `useI18n`, `@vueuse/core`, `f7`, `f7ready` and
54
+ everything under `shared/composables`, `shared/utils`, `plugins` and `modules/**/composables` are
55
+ auto-imported — no import line. Components under `shared/components` and `modules/**/{views,components}`
56
+ resolve the same way.
57
+
58
+ Two things are **not** auto-imported and must be declared:
59
+
60
+ - `f7route` / `f7router` — Framework7 passes them to a route component as props.
61
+ - Repositories and anything under `domains/` — imported explicitly, because a domain is a boundary
62
+ you should see being crossed.
63
+
64
+ `auto-imports.d.ts` and `components.d.ts` are generated. Never hand-edit them; if the editor
65
+ disagrees with the build, run the dev server once to regenerate.