synthos 0.7.2 → 0.9.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 (380) hide show
  1. package/README.md +215 -65
  2. package/default-pages/application/page.html +42 -0
  3. package/default-pages/application/page.json +10 -0
  4. package/default-pages/elevenlabs_effects_studio/page.html +1363 -0
  5. package/default-pages/elevenlabs_effects_studio/page.json +11 -0
  6. package/default-pages/elevenlabs_voice_studio/page.html +801 -0
  7. package/default-pages/elevenlabs_voice_studio/page.json +11 -0
  8. package/default-pages/{json_tools.html → json_tools/page.html} +13 -11
  9. package/default-pages/json_tools/page.json +10 -0
  10. package/default-pages/my_notes/notes/a1b2c3d4-e5f6-7890-abcd-ef1234567890.json +5 -0
  11. package/default-pages/my_notes/page.html +132 -0
  12. package/default-pages/{my_notes.json → my_notes/page.json} +2 -2
  13. package/default-pages/neon_asteroids/files/Ambient_Space.mp3 +0 -0
  14. package/default-pages/neon_asteroids/files/Ambient_Space2.mp3 +0 -0
  15. package/default-pages/neon_asteroids/files/Ambient_Space3.mp3 +0 -0
  16. package/default-pages/neon_asteroids/files/Asteroid_Explosion.mp3 +0 -0
  17. package/default-pages/neon_asteroids/files/Hyperspace_Jump.mp3 +0 -0
  18. package/default-pages/neon_asteroids/files/Laser_Fire.mp3 +0 -0
  19. package/default-pages/neon_asteroids/files/Menu_Navigate.mp3 +0 -0
  20. package/default-pages/neon_asteroids/files/Power_Up_Collect.mp3 +0 -0
  21. package/default-pages/neon_asteroids/files/Saucer_Alert.mp3 +0 -0
  22. package/default-pages/neon_asteroids/files/Ship_Thrust.mp3 +0 -0
  23. package/default-pages/neon_asteroids/files/effects.json +74 -0
  24. package/default-pages/neon_asteroids/page.html +1822 -0
  25. package/default-pages/{neon_asteroids.json → neon_asteroids/page.json} +3 -3
  26. package/default-pages/oregon_trail/page.html +323 -0
  27. package/default-pages/oregon_trail/page.json +12 -0
  28. package/default-pages/retro_game_starter/page.html +1308 -0
  29. package/default-pages/retro_game_starter/page.json +12 -0
  30. package/default-pages/{sidebar_builder.html → sidebar_page/page.html} +12 -10
  31. package/default-pages/sidebar_page/page.json +10 -0
  32. package/default-pages/{solar_explorer.html → solar_explorer/page.html} +24 -29
  33. package/default-pages/{solar_explorer.json → solar_explorer/page.json} +4 -4
  34. package/default-pages/{solar_tutorial.html → solar_tutorial/page.html} +12 -10
  35. package/default-pages/solar_tutorial/page.json +10 -0
  36. package/default-pages/{two-panel_builder.html → two-panel_page/page.html} +13 -11
  37. package/default-pages/two-panel_page/page.json +10 -0
  38. package/default-pages/us_map/page.html +193 -0
  39. package/default-pages/us_map/page.json +12 -0
  40. package/default-pages/us_map_1850/page.html +326 -0
  41. package/default-pages/us_map_1850/page.json +12 -0
  42. package/default-pages/western_cities_1850/page.html +527 -0
  43. package/default-pages/western_cities_1850/page.json +12 -0
  44. package/default-themes/aurora-dawn.json +19 -0
  45. package/default-themes/aurora-dawn.v3.css +198 -0
  46. package/default-themes/aurora-dusk.json +19 -0
  47. package/default-themes/aurora-dusk.v3.css +200 -0
  48. package/default-themes/cosmos-dawn.json +19 -0
  49. package/default-themes/cosmos-dawn.v3.css +198 -0
  50. package/default-themes/cosmos-dusk.json +19 -0
  51. package/default-themes/cosmos-dusk.v3.css +200 -0
  52. package/default-themes/high-contrast-dark.json +19 -0
  53. package/default-themes/high-contrast-dark.v3.css +200 -0
  54. package/default-themes/high-contrast-light.json +19 -0
  55. package/default-themes/high-contrast-light.v3.css +198 -0
  56. package/default-themes/{nebula-dawn.css → nebula-dawn.v2.css} +134 -0
  57. package/default-themes/nebula-dawn.v3.css +199 -0
  58. package/default-themes/{nebula-dusk.css → nebula-dusk.v2.css} +128 -0
  59. package/default-themes/nebula-dusk.v3.css +201 -0
  60. package/default-themes/solar-flare-dawn.json +19 -0
  61. package/default-themes/solar-flare-dawn.v3.css +198 -0
  62. package/default-themes/solar-flare-dusk.json +19 -0
  63. package/default-themes/solar-flare-dusk.v3.css +200 -0
  64. package/dist/agents/a2a/a2aProvider.d.ts.map +1 -0
  65. package/dist/agents/a2a/a2aProvider.js +126 -0
  66. package/dist/agents/a2a/a2aProvider.js.map +1 -0
  67. package/dist/agents/discovery.d.ts.map +1 -0
  68. package/dist/agents/discovery.js +52 -0
  69. package/dist/agents/discovery.js.map +1 -0
  70. package/dist/agents/index.d.ts +7 -0
  71. package/dist/agents/index.d.ts.map +1 -0
  72. package/dist/agents/index.js +20 -0
  73. package/dist/agents/index.js.map +1 -0
  74. package/dist/agents/openclaw/gatewayManager.d.ts +117 -0
  75. package/dist/agents/openclaw/gatewayManager.d.ts.map +1 -0
  76. package/dist/agents/openclaw/gatewayManager.js +486 -0
  77. package/dist/agents/openclaw/gatewayManager.js.map +1 -0
  78. package/dist/agents/openclaw/openclawProvider.d.ts.map +1 -0
  79. package/dist/agents/openclaw/openclawProvider.js +237 -0
  80. package/dist/agents/openclaw/openclawProvider.js.map +1 -0
  81. package/dist/agents/openclaw/sshTunnelManager.d.ts +25 -0
  82. package/dist/agents/openclaw/sshTunnelManager.d.ts.map +1 -0
  83. package/dist/agents/openclaw/sshTunnelManager.js +359 -0
  84. package/dist/agents/openclaw/sshTunnelManager.js.map +1 -0
  85. package/dist/agents/types.d.ts.map +1 -0
  86. package/dist/agents/types.js +6 -0
  87. package/dist/agents/types.js.map +1 -0
  88. package/dist/builders/anthropic.d.ts +31 -0
  89. package/dist/builders/anthropic.d.ts.map +1 -0
  90. package/dist/builders/anthropic.js +227 -0
  91. package/dist/builders/anthropic.js.map +1 -0
  92. package/dist/builders/fireworksai.d.ts +9 -0
  93. package/dist/builders/fireworksai.d.ts.map +1 -0
  94. package/dist/builders/fireworksai.js +57 -0
  95. package/dist/builders/fireworksai.js.map +1 -0
  96. package/dist/builders/index.d.ts +13 -0
  97. package/dist/builders/index.d.ts.map +1 -0
  98. package/dist/builders/index.js +31 -0
  99. package/dist/builders/index.js.map +1 -0
  100. package/dist/builders/openai.d.ts +8 -0
  101. package/dist/builders/openai.d.ts.map +1 -0
  102. package/dist/builders/openai.js +87 -0
  103. package/dist/builders/openai.js.map +1 -0
  104. package/dist/builders/types.d.ts +54 -0
  105. package/dist/builders/types.d.ts.map +1 -0
  106. package/dist/builders/types.js +211 -0
  107. package/dist/builders/types.js.map +1 -0
  108. package/dist/connectors/index.d.ts.map +1 -1
  109. package/dist/connectors/index.js +3 -2
  110. package/dist/connectors/index.js.map +1 -1
  111. package/dist/connectors/registry.d.ts +2 -1
  112. package/dist/connectors/registry.d.ts.map +1 -1
  113. package/dist/connectors/registry.js +65 -96
  114. package/dist/connectors/registry.js.map +1 -1
  115. package/dist/connectors/types.d.ts.map +1 -1
  116. package/dist/customizer/Customizer.d.ts +57 -0
  117. package/dist/customizer/Customizer.d.ts.map +1 -0
  118. package/dist/customizer/Customizer.js +124 -0
  119. package/dist/customizer/Customizer.js.map +1 -0
  120. package/dist/customizer/index.d.ts.map +1 -0
  121. package/dist/customizer/index.js +9 -0
  122. package/dist/customizer/index.js.map +1 -0
  123. package/dist/files.d.ts +17 -0
  124. package/dist/files.d.ts.map +1 -1
  125. package/dist/files.js +75 -1
  126. package/dist/files.js.map +1 -1
  127. package/dist/index.d.ts.map +1 -1
  128. package/dist/index.js +1 -0
  129. package/dist/index.js.map +1 -1
  130. package/dist/init.d.ts +10 -6
  131. package/dist/init.d.ts.map +1 -1
  132. package/dist/init.js +97 -86
  133. package/dist/init.js.map +1 -1
  134. package/dist/migrations.d.ts.map +1 -1
  135. package/dist/migrations.js +142 -145
  136. package/dist/migrations.js.map +1 -1
  137. package/dist/models/anthropic.d.ts +24 -0
  138. package/dist/models/anthropic.d.ts.map +1 -0
  139. package/dist/models/anthropic.js +103 -0
  140. package/dist/models/anthropic.js.map +1 -0
  141. package/dist/models/chainOfThought.d.ts.map +1 -0
  142. package/dist/models/chainOfThought.js +45 -0
  143. package/dist/models/chainOfThought.js.map +1 -0
  144. package/dist/models/fireworksai.d.ts.map +1 -0
  145. package/dist/models/fireworksai.js +141 -0
  146. package/dist/models/fireworksai.js.map +1 -0
  147. package/dist/models/index.d.ts +7 -1
  148. package/dist/models/index.d.ts.map +1 -1
  149. package/dist/models/index.js +20 -1
  150. package/dist/models/index.js.map +1 -1
  151. package/dist/models/logCompletePrompt.d.ts.map +1 -0
  152. package/dist/models/logCompletePrompt.js +23 -0
  153. package/dist/models/logCompletePrompt.js.map +1 -0
  154. package/dist/models/openai.d.ts +24 -0
  155. package/dist/models/openai.d.ts.map +1 -0
  156. package/dist/models/openai.js +101 -0
  157. package/dist/models/openai.js.map +1 -0
  158. package/dist/models/providers.d.ts.map +1 -1
  159. package/dist/models/providers.js +12 -4
  160. package/dist/models/providers.js.map +1 -1
  161. package/dist/models/types.d.ts +53 -2
  162. package/dist/models/types.d.ts.map +1 -1
  163. package/dist/models/types.js +21 -0
  164. package/dist/models/types.js.map +1 -1
  165. package/dist/models/utils.d.ts.map +1 -0
  166. package/dist/models/utils.js +21 -0
  167. package/dist/models/utils.js.map +1 -0
  168. package/dist/pages.d.ts +30 -7
  169. package/dist/pages.d.ts.map +1 -1
  170. package/dist/pages.js +177 -55
  171. package/dist/pages.js.map +1 -1
  172. package/dist/scripts.d.ts.map +1 -1
  173. package/dist/scripts.js +4 -3
  174. package/dist/scripts.js.map +1 -1
  175. package/dist/service/createCompletePrompt.d.ts.map +1 -1
  176. package/dist/service/createCompletePrompt.js +9 -6
  177. package/dist/service/createCompletePrompt.js.map +1 -1
  178. package/dist/service/generateImage.d.ts.map +1 -1
  179. package/dist/service/generateImage.js +3 -3
  180. package/dist/service/generateImage.js.map +1 -1
  181. package/dist/service/server.d.ts.map +1 -1
  182. package/dist/service/server.js +39 -7
  183. package/dist/service/server.js.map +1 -1
  184. package/dist/service/transformPage.d.ts +47 -18
  185. package/dist/service/transformPage.d.ts.map +1 -1
  186. package/dist/service/transformPage.js +559 -270
  187. package/dist/service/transformPage.js.map +1 -1
  188. package/dist/service/useAgentRoutes.d.ts +5 -0
  189. package/dist/service/useAgentRoutes.d.ts.map +1 -0
  190. package/dist/service/useAgentRoutes.js +392 -0
  191. package/dist/service/useAgentRoutes.js.map +1 -0
  192. package/dist/service/useApiRoutes.d.ts.map +1 -1
  193. package/dist/service/useApiRoutes.js +380 -138
  194. package/dist/service/useApiRoutes.js.map +1 -1
  195. package/dist/service/useConnectorRoutes.d.ts.map +1 -1
  196. package/dist/service/useConnectorRoutes.js +20 -9
  197. package/dist/service/useConnectorRoutes.js.map +1 -1
  198. package/dist/service/useFileRoutes.d.ts +4 -0
  199. package/dist/service/useFileRoutes.d.ts.map +1 -0
  200. package/dist/service/useFileRoutes.js +122 -0
  201. package/dist/service/useFileRoutes.js.map +1 -0
  202. package/dist/service/usePageRoutes.d.ts.map +1 -1
  203. package/dist/service/usePageRoutes.js +660 -68
  204. package/dist/service/usePageRoutes.js.map +1 -1
  205. package/dist/service/useSharedDataRoutes.d.ts +4 -0
  206. package/dist/service/useSharedDataRoutes.d.ts.map +1 -0
  207. package/dist/service/useSharedDataRoutes.js +104 -0
  208. package/dist/service/useSharedDataRoutes.js.map +1 -0
  209. package/dist/service/useSharedFileRoutes.d.ts +4 -0
  210. package/dist/service/useSharedFileRoutes.d.ts.map +1 -0
  211. package/dist/service/useSharedFileRoutes.js +121 -0
  212. package/dist/service/useSharedFileRoutes.js.map +1 -0
  213. package/dist/settings.d.ts +3 -1
  214. package/dist/settings.d.ts.map +1 -1
  215. package/dist/settings.js +5 -8
  216. package/dist/settings.js.map +1 -1
  217. package/dist/synthos-cli.d.ts.map +1 -1
  218. package/dist/synthos-cli.js +4 -3
  219. package/dist/synthos-cli.js.map +1 -1
  220. package/dist/themes.d.ts +15 -0
  221. package/dist/themes.d.ts.map +1 -1
  222. package/dist/themes.js +106 -20
  223. package/dist/themes.js.map +1 -1
  224. package/migration-rules/v1-to-v2.md +193 -0
  225. package/migration-rules/v2-to-v3.md +481 -0
  226. package/package.json +15 -11
  227. package/required-pages/builder/page.html +43 -0
  228. package/required-pages/builder/page.json +10 -0
  229. package/required-pages/pages/page.html +924 -0
  230. package/required-pages/pages/page.json +10 -0
  231. package/required-pages/settings/page.html +1753 -0
  232. package/required-pages/settings/page.json +10 -0
  233. package/required-pages/synthos_apis/page.html +846 -0
  234. package/required-pages/synthos_apis/page.json +10 -0
  235. package/required-pages/{synthos_scripts.html → synthos_scripts/page.html} +13 -11
  236. package/required-pages/synthos_scripts/page.json +10 -0
  237. package/service-connectors/airtable/connector.json +27 -0
  238. package/service-connectors/alpha-vantage/connector.json +26 -0
  239. package/service-connectors/brave-search/connector.json +26 -0
  240. package/service-connectors/cloudinary/connector.json +27 -0
  241. package/service-connectors/deepl/connector.json +28 -0
  242. package/service-connectors/elevenlabs/connector.json +30 -0
  243. package/service-connectors/giphy/connector.json +27 -0
  244. package/service-connectors/github/connector.json +29 -0
  245. package/service-connectors/huggingface/connector.json +27 -0
  246. package/service-connectors/imgur/connector.json +29 -0
  247. package/service-connectors/instagram/connector.json +43 -0
  248. package/service-connectors/jira/connector.json +28 -0
  249. package/service-connectors/mapbox/connector.json +26 -0
  250. package/service-connectors/nasa/connector.json +27 -0
  251. package/service-connectors/newsapi/connector.json +27 -0
  252. package/service-connectors/notion/connector.json +28 -0
  253. package/service-connectors/open-exchange-rates/connector.json +27 -0
  254. package/service-connectors/openweathermap/connector.json +26 -0
  255. package/service-connectors/pexels/connector.json +27 -0
  256. package/service-connectors/resend/connector.json +29 -0
  257. package/service-connectors/rss2json/connector.json +27 -0
  258. package/service-connectors/sendgrid/connector.json +27 -0
  259. package/service-connectors/spoonacular/connector.json +28 -0
  260. package/service-connectors/stability-ai/connector.json +27 -0
  261. package/service-connectors/twilio/connector.json +28 -0
  262. package/service-connectors/unsplash/connector.json +27 -0
  263. package/service-connectors/wolfram-alpha/connector.json +26 -0
  264. package/service-connectors/youtube-data/connector.json +30 -0
  265. package/src/agents/a2a/a2aProvider.ts +110 -0
  266. package/src/agents/discovery.ts +74 -0
  267. package/src/agents/index.ts +6 -0
  268. package/src/agents/openclaw/gatewayManager.ts +570 -0
  269. package/src/agents/openclaw/openclawProvider.ts +259 -0
  270. package/src/agents/openclaw/sshTunnelManager.ts +393 -0
  271. package/src/agents/types.ts +82 -0
  272. package/src/builders/anthropic.ts +283 -0
  273. package/src/builders/fireworksai.ts +59 -0
  274. package/src/builders/index.ts +33 -0
  275. package/src/builders/openai.ts +89 -0
  276. package/src/builders/types.ts +261 -0
  277. package/src/connectors/index.ts +3 -1
  278. package/src/connectors/registry.ts +40 -96
  279. package/src/connectors/types.ts +25 -0
  280. package/src/customizer/Customizer.ts +151 -0
  281. package/src/customizer/index.ts +5 -0
  282. package/src/files.ts +71 -0
  283. package/src/index.ts +2 -1
  284. package/src/init.ts +138 -97
  285. package/src/migrations.ts +148 -145
  286. package/src/models/anthropic.ts +119 -0
  287. package/src/models/chainOfThought.ts +56 -0
  288. package/src/models/fireworksai.ts +143 -0
  289. package/src/models/index.ts +7 -1
  290. package/src/models/logCompletePrompt.ts +25 -0
  291. package/src/models/openai.ts +110 -0
  292. package/src/models/providers.ts +12 -3
  293. package/src/models/types.ts +97 -2
  294. package/src/models/utils.ts +16 -0
  295. package/src/pages.ts +176 -54
  296. package/src/scripts.ts +2 -2
  297. package/src/service/createCompletePrompt.ts +3 -1
  298. package/src/service/generateImage.ts +2 -2
  299. package/src/service/server.ts +39 -8
  300. package/src/service/transformPage.ts +605 -301
  301. package/src/service/useAgentRoutes.ts +428 -0
  302. package/src/service/useApiRoutes.ts +309 -45
  303. package/src/service/useConnectorRoutes.ts +21 -10
  304. package/src/service/useFileRoutes.ts +127 -0
  305. package/src/service/usePageRoutes.ts +736 -75
  306. package/src/service/useSharedDataRoutes.ts +106 -0
  307. package/src/service/useSharedFileRoutes.ts +126 -0
  308. package/src/settings.ts +8 -10
  309. package/src/synthos-cli.ts +4 -3
  310. package/src/themes.ts +103 -20
  311. package/static-files/favicon.svg +12 -0
  312. package/static-files/fluentlm-instructions.llmd +868 -0
  313. package/static-files/fluentlm-instructions.md +1595 -0
  314. package/static-files/fluentlm.css +4844 -0
  315. package/static-files/fluentlm.js +3602 -0
  316. package/static-files/fluentlm.min.css +1 -0
  317. package/static-files/fluentlm.min.js +1 -0
  318. package/static-files/helpers.v3.js +304 -0
  319. package/static-files/page.v3.js +1290 -0
  320. package/static-files/recommended-frameworks.llmd +81 -0
  321. package/static-files/recommended-frameworks.md +137 -0
  322. package/static-files/retro-game.js +877 -0
  323. package/static-files/shell.css +797 -0
  324. package/static-files/theme-dark.css +169 -0
  325. package/static-files/theme-light.css +169 -0
  326. package/tests/anthropic.spec.ts +84 -0
  327. package/tests/builders.spec.ts +139 -0
  328. package/tests/chainOfThought.spec.ts +108 -0
  329. package/tests/ensureScripts.spec.ts +82 -0
  330. package/tests/files.spec.ts +233 -0
  331. package/tests/fireworksai.spec.ts +92 -0
  332. package/tests/logCompletePrompt.spec.ts +74 -0
  333. package/tests/migrations.spec.ts +79 -1
  334. package/tests/openai.spec.ts +71 -0
  335. package/tests/pages.spec.ts +226 -1
  336. package/tests/providers.spec.ts +144 -0
  337. package/tests/scripts.spec.ts +209 -0
  338. package/tests/transformPage.spec.ts +456 -0
  339. package/tests/types.spec.ts +23 -0
  340. package/default-pages/app_builder.html +0 -40
  341. package/default-pages/app_builder.json +0 -1
  342. package/default-pages/json_tools.json +0 -1
  343. package/default-pages/my_notes.html +0 -33
  344. package/default-pages/neon_asteroids.html +0 -77
  345. package/default-pages/sidebar_builder.json +0 -1
  346. package/default-pages/solar_tutorial.json +0 -1
  347. package/default-pages/two-panel_builder.json +0 -1
  348. package/dist/connectors/index.d.ts +0 -3
  349. package/dist/connectors/types.d.ts +0 -61
  350. package/dist/index.d.ts +0 -7
  351. package/dist/migrations.d.ts +0 -11
  352. package/dist/models/providers.d.ts +0 -7
  353. package/dist/scripts.d.ts +0 -14
  354. package/dist/service/createCompletePrompt.d.ts +0 -5
  355. package/dist/service/debugLog.d.ts +0 -11
  356. package/dist/service/generateImage.d.ts +0 -32
  357. package/dist/service/index.d.ts +0 -8
  358. package/dist/service/modelInstructions.d.ts +0 -7
  359. package/dist/service/requiresSettings.d.ts +0 -3
  360. package/dist/service/server.d.ts +0 -4
  361. package/dist/service/useApiRoutes.d.ts +0 -4
  362. package/dist/service/useConnectorRoutes.d.ts +0 -4
  363. package/dist/service/useDataRoutes.d.ts +0 -4
  364. package/dist/service/usePageRoutes.d.ts +0 -5
  365. package/dist/synthos-cli.d.ts +0 -2
  366. package/images/home.png +0 -0
  367. package/images/page-management.png +0 -0
  368. package/images/settings.png +0 -0
  369. package/images/synthos-square.png +0 -0
  370. package/page-scripts/helpers-v2.js +0 -121
  371. package/page-scripts/page-v2.js +0 -615
  372. package/required-pages/builder.html +0 -74
  373. package/required-pages/builder.json +0 -1
  374. package/required-pages/pages.html +0 -196
  375. package/required-pages/pages.json +0 -1
  376. package/required-pages/settings.html +0 -841
  377. package/required-pages/settings.json +0 -1
  378. package/required-pages/synthos_apis.html +0 -272
  379. package/required-pages/synthos_apis.json +0 -1
  380. package/required-pages/synthos_scripts.json +0 -1
@@ -0,0 +1,1595 @@
1
+ # FluentLM — Component Reference
2
+
3
+ Compact reference for LLM-driven HTML generation. Each component shows 1–3 examples followed by its class list.
4
+
5
+ ---
6
+
7
+ ## Global Classes
8
+
9
+ Apply to any element.
10
+
11
+ | Class | Effect |
12
+ |-------|--------|
13
+ | `flm-text--secondary` | Color: `--bodySubtext` |
14
+ | `flm-text--disabled` | Color: `--disabledText` |
15
+ | `flm-text--error` | Color: `--errorText` |
16
+ | `flm-text--success` | Color: `--successText` |
17
+ | `flm-text--nowrap` | Truncate with ellipsis |
18
+ | `flm-text--block` | `display: block` |
19
+ | `flm-text--semibold` | Weight 600 |
20
+ | `flm-text--bold` | Weight 700 |
21
+ | `flm-sr-only` | Visually hidden, screen-reader accessible |
22
+
23
+ ---
24
+
25
+ ## Global Implementation Notes
26
+
27
+ **Auto-wired JS handlers** — The Nav, Pivot, Dialog, Panel, Modal, Callout, Dropdown, ComboBox, SpinButton, SwatchColorPicker, GroupedList, MessageBar, Toggle, Rating, SearchBox, TagPicker, DatePicker, TimePicker, Coachmark, and TeachingBubble components implement their own click/interaction handlers via `fluentlm.js`. Do not duplicate them in page scripts.
28
+
29
+ **Theme switching** — Use `FluentLM.setTheme('dark')` / `FluentLM.setTheme('light')`, or toggle the `fluent-dark` class on `<html>`. Do not use `data-theme` attributes.
30
+
31
+ **CSS variables** — Use only the FluentLM semantic tokens documented in the CSS Custom Properties section below (e.g. `--bodyText`, `--bodyBackground`). Do not use Fluent UI v2 variable names (e.g. `--colorNeutralForeground1`). **Important:** For any custom styles (hover states, backgrounds, borders, text colors), always use the **Semantic Colors** variables (e.g. `--bodyBackground`, `--defaultStateBackground`, `--bodySubtext`) instead of the **Palette Colors** variables (e.g. `--neutralLighter`, `--neutralLight`). Palette colors are fixed values that do not change between light and dark themes, so using them will produce incorrect colors in one theme or the other.
32
+
33
+ **CSS load order** — The base CSS file must always be included before any theme files.
34
+
35
+ **Icons** — Any element with a `data-icon="Name"` attribute gets an inline SVG injected by JS. Works on `.flm-icon` elements, empty `<i>` / `<span>` tags, buttons, and links.
36
+
37
+ ---
38
+
39
+ ## Button
40
+
41
+ ```html
42
+ <button class="flm-button">Default</button>
43
+ <button class="flm-button flm-button--primary" data-icon="Save">Save</button>
44
+ <button class="flm-button flm-button--icon" data-icon="Settings" aria-label="Settings"></button>
45
+ ```
46
+
47
+ | Class | Effect |
48
+ |-------|--------|
49
+ | `flm-button` | Base button |
50
+ | `flm-button--primary` | Brand-colored fill |
51
+ | `flm-button--compound` | Two-line button (needs `.flm-button-label` + `.flm-button-description` children) |
52
+ | `flm-button--icon` | Icon-only, square (requires `aria-label`) |
53
+ | `flm-button--subtle` | No border, transparent background |
54
+
55
+ | Attribute | Effect |
56
+ |-----------|--------|
57
+ | `data-icon="Name"` | JS injects icon before label |
58
+ | `data-split` | JS adds dropdown caret |
59
+ | `disabled` | Native disabled state |
60
+
61
+ | Child class | Where |
62
+ |-------------|-------|
63
+ | `flm-button-label` | Primary text in compound button |
64
+ | `flm-button-description` | Secondary text in compound button |
65
+
66
+ ---
67
+
68
+ ## Text
69
+
70
+ ```html
71
+ <span class="flm-text">Default (medium)</span>
72
+ <span class="flm-text flm-text--xLarge">Heading</span>
73
+ <p class="flm-text flm-text--small flm-text--secondary flm-text--block">Caption paragraph.</p>
74
+ ```
75
+
76
+ | Class | Size |
77
+ |-------|------|
78
+ | `flm-text--tiny` | 10px |
79
+ | `flm-text--xSmall` | 10px |
80
+ | `flm-text--small` | 12px |
81
+ | `flm-text--smallPlus` | 12px |
82
+ | `flm-text--medium` | 14px (default) |
83
+ | `flm-text--mediumPlus` | 16px |
84
+ | `flm-text--large` | 18px |
85
+ | `flm-text--xLarge` | 20px / semibold |
86
+ | `flm-text--xxLarge` | 28px / semibold |
87
+ | `flm-text--superLarge` | 42px / semibold |
88
+ | `flm-text--mega` | 68px / semibold |
89
+
90
+ ---
91
+
92
+ ## Label
93
+
94
+ ```html
95
+ <label class="flm-label" for="f1">Name</label>
96
+ <label class="flm-label flm-label--required" for="f2">Email</label>
97
+ ```
98
+
99
+ | Class | Effect |
100
+ |-------|--------|
101
+ | `flm-label` | Base label |
102
+ | `flm-label--required` | Adds red asterisk |
103
+ | `flm-label--disabled` | Dimmed text |
104
+
105
+ ---
106
+
107
+ ## Link
108
+
109
+ ```html
110
+ <a class="flm-link" href="/page">Go to page</a>
111
+ ```
112
+
113
+ | Class | Effect |
114
+ |-------|--------|
115
+ | `flm-link` | Base link |
116
+ | `flm-link--disabled` | Dimmed, no pointer events |
117
+
118
+ ---
119
+
120
+ ## Icon
121
+
122
+ ```html
123
+ <i class="flm-icon" data-icon="Mail"></i>
124
+ <i class="flm-icon flm-icon--large" data-icon="ChevronDown"></i>
125
+ ```
126
+
127
+ | Class | Size |
128
+ |-------|------|
129
+ | `flm-icon--small` | 12px |
130
+ | (default) | 16px |
131
+ | `flm-icon--large` | 20px |
132
+
133
+ | Attribute | Effect |
134
+ |-----------|--------|
135
+ | `data-icon="Name"` | JS resolves to SVG/glyph |
136
+
137
+ ---
138
+
139
+ ## TextField
140
+
141
+ ```html
142
+ <div class="flm-textfield">
143
+ <label class="flm-label" for="f1">Name</label>
144
+ <input class="flm-textfield-input" id="f1" placeholder="Enter name">
145
+ </div>
146
+
147
+ <div class="flm-textfield flm-textfield--error">
148
+ <label class="flm-label" for="f2">Age</label>
149
+ <input class="flm-textfield-input" id="f2" value="-1">
150
+ <span class="flm-textfield-error">Must be positive</span>
151
+ </div>
152
+
153
+ <div class="flm-textfield">
154
+ <label class="flm-label" for="f3">Notes</label>
155
+ <textarea class="flm-textfield-input" id="f3" rows="4"></textarea>
156
+ </div>
157
+ ```
158
+
159
+ | Class | Effect |
160
+ |-------|--------|
161
+ | `flm-textfield` | Base wrapper |
162
+ | `flm-textfield--required` | Required field styling |
163
+ | `flm-textfield--error` | Error border + enables `.flm-textfield-error` |
164
+ | `flm-textfield--disabled` | Dimmed, pair with `disabled` on input |
165
+ | `flm-textfield--underlined` | Bottom border only |
166
+ | `flm-textfield--borderless` | No border |
167
+
168
+ | Child class | Element |
169
+ |-------------|---------|
170
+ | `flm-textfield-input` | `<input>` or `<textarea>` |
171
+ | `flm-textfield-error` | `<span>` error message |
172
+ | `flm-textfield-wrapper` | `<div>` wraps input when using prefix/suffix |
173
+ | `flm-textfield-prefix` | `<span>` before input |
174
+ | `flm-textfield-suffix` | `<span>` after input |
175
+
176
+ ---
177
+
178
+ ## Checkbox
179
+
180
+ ```html
181
+ <label class="flm-checkbox">
182
+ <input type="checkbox" class="flm-checkbox-input">
183
+ <span class="flm-checkbox-mark"></span>
184
+ <span class="flm-checkbox-label">Accept terms</span>
185
+ </label>
186
+ ```
187
+
188
+ | Class | Effect |
189
+ |-------|--------|
190
+ | `flm-checkbox` | Base wrapper (is a `<label>`) |
191
+ | `flm-checkbox--disabled` | Dimmed, pair with `disabled` on input |
192
+
193
+ | Child class | Element |
194
+ |-------------|---------|
195
+ | `flm-checkbox-input` | Hidden native `<input type="checkbox">` |
196
+ | `flm-checkbox-mark` | Visual checkmark box |
197
+ | `flm-checkbox-label` | Text label |
198
+
199
+ Native: `checked`, `disabled`, `indeterminate` (via JS).
200
+
201
+ ---
202
+
203
+ ## Toggle
204
+
205
+ ```html
206
+ <label class="flm-toggle">
207
+ <span class="flm-toggle-label">Notifications</span>
208
+ <input type="checkbox" class="flm-toggle-input">
209
+ <span class="flm-toggle-track"><span class="flm-toggle-thumb"></span></span>
210
+ <span class="flm-toggle-state" data-on="On" data-off="Off"></span>
211
+ </label>
212
+ ```
213
+
214
+ | Class | Effect |
215
+ |-------|--------|
216
+ | `flm-toggle` | Base wrapper (is a `<label>`) |
217
+ | `flm-toggle--disabled` | Dimmed, pair with `disabled` on input |
218
+ | `flm-toggle--inline` | Label and track on same line |
219
+
220
+ | Child class | Element |
221
+ |-------------|---------|
222
+ | `flm-toggle-input` | Hidden native `<input type="checkbox">` |
223
+ | `flm-toggle-label` | Text label |
224
+ | `flm-toggle-track` | Sliding rail |
225
+ | `flm-toggle-thumb` | Circle knob inside track |
226
+ | `flm-toggle-state` | Shows `data-on`/`data-off` text based on state |
227
+
228
+ ---
229
+
230
+ ## Dropdown
231
+
232
+ ```html
233
+ <div class="flm-dropdown">
234
+ <label class="flm-label">Country</label>
235
+ <button class="flm-dropdown-trigger">
236
+ <span class="flm-dropdown-title flm-dropdown-title--placeholder">Select…</span>
237
+ <span class="flm-dropdown-caret" data-icon="ChevronDown"></span>
238
+ </button>
239
+ <div class="flm-dropdown-listbox">
240
+ <div class="flm-dropdown-option" data-value="us">United States</div>
241
+ <div class="flm-dropdown-option" data-value="gb">United Kingdom</div>
242
+ </div>
243
+ </div>
244
+ ```
245
+
246
+ | Class | Effect |
247
+ |-------|--------|
248
+ | `flm-dropdown` | Container |
249
+ | `flm-dropdown--disabled` | Disabled state |
250
+ | `flm-dropdown--error` | Error border |
251
+
252
+ | Attribute | Effect |
253
+ |-----------|--------|
254
+ | `data-value="val"` | On `.flm-dropdown-option` — option value. Auto-set on root when selected |
255
+
256
+ | Child class | Element |
257
+ |-------------|---------|
258
+ | `flm-dropdown-trigger` | Clickable button (styled like ComboBox wrapper) |
259
+ | `flm-dropdown-title` | Selected text display |
260
+ | `flm-dropdown-title--placeholder` | Placeholder color |
261
+ | `flm-dropdown-caret` | Chevron icon |
262
+ | `flm-dropdown-listbox` | Options popup |
263
+ | `flm-dropdown-option` | Individual option |
264
+ | `flm-dropdown-option--selected` | Selected option |
265
+ | `flm-dropdown-option--disabled` | Disabled option |
266
+ | `flm-dropdown-value` | Hidden `<input>` for form submission (optional) |
267
+ | `flm-dropdown-error` | `<span>` error message |
268
+
269
+ JS: keyboard nav (ArrowUp/Down/Enter/Space/Escape), click-outside dismiss, flip-above.
270
+
271
+ ---
272
+
273
+ ## Stack
274
+
275
+ ```html
276
+ <div class="flm-stack" style="gap: var(--spacingS1)">
277
+ <div>Row 1</div>
278
+ <div>Row 2</div>
279
+ </div>
280
+
281
+ <div class="flm-stack flm-stack--horizontal" style="gap: var(--spacingM)">
282
+ <div class="flm-stack-item flm-stack-item--grow">Fills space</div>
283
+ <div>Fixed</div>
284
+ </div>
285
+ ```
286
+
287
+ | Class | Effect |
288
+ |-------|--------|
289
+ | `flm-stack` | Vertical flexbox (default) |
290
+ | `flm-stack--horizontal` | Row direction |
291
+ | `flm-stack--center` | Center both axes |
292
+ | `flm-stack--end` | Align to end |
293
+ | `flm-stack--space-between` | Space between items |
294
+ | `flm-stack--wrap` | Allow wrapping |
295
+
296
+ | Child class | Effect |
297
+ |-------------|--------|
298
+ | `flm-stack-item--grow` | `flex-grow: 1` |
299
+ | `flm-stack-item--shrink` | `flex-shrink: 1` |
300
+ | `flm-stack-item--align-end` | Self-align to end |
301
+ | `flm-stack-item--align-center` | Self-align to center |
302
+
303
+ Inline `style="gap: var(--spacingS1)"` sets spacing per instance.
304
+
305
+ ---
306
+
307
+ ## Separator
308
+
309
+ ```html
310
+ <hr class="flm-separator">
311
+ <hr class="flm-separator flm-separator--vertical">
312
+ ```
313
+
314
+ | Class | Effect |
315
+ |-------|--------|
316
+ | `flm-separator` | Horizontal line |
317
+ | `flm-separator--vertical` | Vertical line (use in horizontal stacks) |
318
+
319
+ ---
320
+
321
+ ## Spinner
322
+
323
+ ```html
324
+ <div class="flm-spinner"><div class="flm-spinner-circle"></div></div>
325
+ <div class="flm-spinner flm-spinner--large">
326
+ <div class="flm-spinner-circle"></div>
327
+ <span class="flm-spinner-label">Loading…</span>
328
+ </div>
329
+ ```
330
+
331
+ | Class | Size |
332
+ |-------|------|
333
+ | `flm-spinner--xSmall` | 12px |
334
+ | `flm-spinner--small` | 16px |
335
+ | (default) | 20px |
336
+ | `flm-spinner--large` | 28px |
337
+
338
+ | Child class | Element |
339
+ |-------------|---------|
340
+ | `flm-spinner-circle` | Animated ring |
341
+ | `flm-spinner-label` | Optional text label |
342
+
343
+ ---
344
+
345
+ ## MessageBar
346
+
347
+ ```html
348
+ <div class="flm-messagebar flm-messagebar--success">Operation completed.</div>
349
+ <div class="flm-messagebar flm-messagebar--error">Something went wrong.</div>
350
+ ```
351
+
352
+ | Class | Type |
353
+ |-------|------|
354
+ | `flm-messagebar--info` | Neutral info (default) |
355
+ | `flm-messagebar--success` | Green success |
356
+ | `flm-messagebar--warning` | Yellow warning |
357
+ | `flm-messagebar--severeWarning` | Orange severe warning |
358
+ | `flm-messagebar--error` | Red error |
359
+ | `flm-messagebar--blocked` | Red blocked |
360
+
361
+ | Child class | Element |
362
+ |-------------|---------|
363
+ | `flm-messagebar-icon` | Leading icon (auto-injected by JS if absent) |
364
+ | `flm-messagebar-text` | Message content |
365
+ | `flm-messagebar-actions` | Action buttons container |
366
+ | `flm-messagebar-dismiss` | Dismiss/close button |
367
+
368
+ ---
369
+
370
+ ## Dialog
371
+
372
+ ```html
373
+ <div class="flm-dialog-overlay" id="dlg1" data-light-dismiss>
374
+ <div class="flm-dialog">
375
+ <div class="flm-dialog-header">
376
+ <h2 class="flm-dialog-title">Confirm</h2>
377
+ <button class="flm-dialog-close" data-icon="Cancel" aria-label="Close"></button>
378
+ </div>
379
+ <div class="flm-dialog-body">Are you sure?</div>
380
+ <div class="flm-dialog-footer">
381
+ <button class="flm-button" data-dialog-close>Cancel</button>
382
+ <button class="flm-button flm-button--primary" data-dialog-close>OK</button>
383
+ </div>
384
+ </div>
385
+ </div>
386
+ <button class="flm-button" data-dialog-open="dlg1">Open Dialog</button>
387
+ ```
388
+
389
+ | Class | Effect |
390
+ |-------|--------|
391
+ | `flm-dialog-overlay` | Full-screen overlay container (give it an `id`) |
392
+ | `flm-dialog` | The dialog box |
393
+ | `flm-dialog--large-header` | Larger title font |
394
+
395
+ | Attribute | Effect |
396
+ |-----------|--------|
397
+ | `data-dialog-open="id"` | On trigger button — opens dialog |
398
+ | `data-dialog-close` | On any button — closes containing dialog |
399
+ | `data-light-dismiss` | On overlay — click outside to close |
400
+
401
+ | Child class | Element |
402
+ |-------------|---------|
403
+ | `flm-dialog-header` | Header row |
404
+ | `flm-dialog-title` | `<h2>` title |
405
+ | `flm-dialog-close` | Close X button |
406
+ | `flm-dialog-body` | Content area |
407
+ | `flm-dialog-footer` | Action buttons row |
408
+
409
+ **Implementation note:** When embedding a Dropdown, ComboBox, or other popup-based component inside a Dialog, Modal, or Panel, add `overflow: visible` to both the dialog/modal container (`.flm-dialog`, `.flm-modal`) and the body (`.flm-dialog-body`, `.flm-panel-body`) so the dropdown listbox is not clipped.
410
+
411
+ ---
412
+
413
+ ## Panel
414
+
415
+ ```html
416
+ <div class="flm-panel-overlay"></div>
417
+ <div class="flm-panel" id="panel1">
418
+ <div class="flm-panel-header">
419
+ <h2 class="flm-panel-title">Settings</h2>
420
+ <button class="flm-panel-close" data-icon="Cancel" aria-label="Close"></button>
421
+ </div>
422
+ <div class="flm-panel-body">Panel content here.</div>
423
+ <div class="flm-panel-footer">
424
+ <button class="flm-button flm-button--primary" data-panel-close>Save</button>
425
+ </div>
426
+ </div>
427
+ <button class="flm-button" data-panel-open="panel1">Open Panel</button>
428
+ ```
429
+
430
+ | Class | Effect |
431
+ |-------|--------|
432
+ | `flm-panel` | Slide-in container (give it an `id`) |
433
+ | `flm-panel--small` | 272px width |
434
+ | `flm-panel--medium` | 592px width |
435
+ | `flm-panel--large` | 940px width |
436
+ | `flm-panel--extraLarge` | 1200px width |
437
+ | `flm-panel--fluid` | 100% width |
438
+ | `flm-panel--left` | Slides from left instead of right |
439
+
440
+ | Attribute | Effect |
441
+ |-----------|--------|
442
+ | `data-panel-open="id"` | On trigger — opens panel |
443
+ | `data-panel-close` | On button — closes containing panel |
444
+
445
+ | Child class | Element |
446
+ |-------------|---------|
447
+ | `flm-panel-header` | Header row |
448
+ | `flm-panel-title` | `<h2>` title |
449
+ | `flm-panel-close` | Close X button |
450
+ | `flm-panel-body` | Scrollable content |
451
+ | `flm-panel-footer` | Actions row (sticky bottom) |
452
+
453
+ ---
454
+
455
+ ## Modal
456
+
457
+ ```html
458
+ <div class="flm-modal-overlay" id="modal1" data-light-dismiss>
459
+ <div class="flm-modal" style="width: 480px; padding: var(--spacingL1);">
460
+ Content here
461
+ <button class="flm-button" data-modal-close>Close</button>
462
+ </div>
463
+ </div>
464
+ <button class="flm-button" data-modal-open="modal1">Open Modal</button>
465
+ ```
466
+
467
+ | Class | Effect |
468
+ |-------|--------|
469
+ | `flm-modal-overlay` | Full-screen overlay (give it an `id`) |
470
+ | `flm-modal` | Centered content box |
471
+
472
+ | Attribute | Effect |
473
+ |-----------|--------|
474
+ | `data-modal-open="id"` | Opens modal |
475
+ | `data-modal-close` | Closes containing modal |
476
+ | `data-light-dismiss` | On overlay — click outside to close |
477
+ | `data-blocking` | On overlay — prevents Escape/click dismiss |
478
+
479
+ ---
480
+
481
+ ## Callout
482
+
483
+ ```html
484
+ <button class="flm-button" data-callout-toggle="co1">Show Info</button>
485
+ <div class="flm-callout" id="co1">
486
+ <div class="flm-callout-beak"></div>
487
+ <div class="flm-callout-body">Callout content here.</div>
488
+ </div>
489
+ ```
490
+
491
+ | Class | Effect |
492
+ |-------|--------|
493
+ | `flm-callout` | Positioned popup (give it an `id`) |
494
+
495
+ | Attribute | Effect |
496
+ |-----------|--------|
497
+ | `data-callout-toggle="id"` | Toggle callout visibility |
498
+
499
+ | Child class | Element |
500
+ |-------------|---------|
501
+ | `flm-callout-beak` | Arrow pointing to target |
502
+ | `flm-callout-body` | Content area |
503
+
504
+ ---
505
+
506
+ ## CommandBar
507
+
508
+ ```html
509
+ <div class="flm-commandbar">
510
+ <div class="flm-commandbar-items">
511
+ <button class="flm-commandbar-item" data-icon="Add">New</button>
512
+ <button class="flm-commandbar-item" data-icon="Edit">Edit</button>
513
+ <span class="flm-commandbar-divider"></span>
514
+ <button class="flm-commandbar-item" data-icon="Delete">Delete</button>
515
+ </div>
516
+ <div class="flm-commandbar-far">
517
+ <button class="flm-commandbar-item" data-icon="Filter">Filter</button>
518
+ </div>
519
+ </div>
520
+ ```
521
+
522
+ | Class | Element |
523
+ |-------|---------|
524
+ | `flm-commandbar` | Toolbar container |
525
+ | `flm-commandbar-items` | Left-side items |
526
+ | `flm-commandbar-far` | Right-side items |
527
+ | `flm-commandbar-item` | Individual command button |
528
+ | `flm-commandbar-divider` | Vertical separator |
529
+ | `flm-commandbar-overflow` | Overflow "..." button |
530
+
531
+ | Attribute | Effect |
532
+ |-----------|--------|
533
+ | `data-icon="Name"` | Icon before label |
534
+ | `disabled` | Disabled state |
535
+
536
+ **Implementation note:** When embedding a Dropdown or other popup-based component inside a CommandBar, add `overflow: visible` to `.flm-commandbar` and `.flm-commandbar-items` so the dropdown listbox is not clipped.
537
+
538
+ ---
539
+
540
+ ## Nav
541
+
542
+ ```html
543
+ <nav class="flm-nav">
544
+ <!-- Expanded group -->
545
+ <div class="flm-nav-group">
546
+ <button class="flm-nav-group-header">
547
+ <i class="flm-nav-chevron flm-nav-chevron--expanded" data-icon="ChevronRight"></i>
548
+ Section
549
+ </button>
550
+ <div class="flm-nav-group-items">
551
+ <a class="flm-nav-link flm-nav-link--active" href="#">Home</a>
552
+ <a class="flm-nav-link" href="#">Settings</a>
553
+ <a class="flm-nav-link flm-nav-link--disabled">Disabled</a>
554
+ </div>
555
+ </div>
556
+ <!-- Collapsed group: put --collapsed on flm-nav-group-items, omit --expanded on chevron -->
557
+ <div class="flm-nav-group">
558
+ <button class="flm-nav-group-header">
559
+ <i class="flm-nav-chevron" data-icon="ChevronRight"></i>
560
+ Collapsed Section
561
+ </button>
562
+ <div class="flm-nav-group-items flm-nav-group-items--collapsed">
563
+ <a class="flm-nav-link" href="#">Hidden Link</a>
564
+ </div>
565
+ </div>
566
+ </nav>
567
+ ```
568
+
569
+ | Class | Effect |
570
+ |-------|--------|
571
+ | `flm-nav` | Nav container |
572
+ | `flm-nav-group` | Section group |
573
+ | `flm-nav-group-header` | Collapsible group title |
574
+ | `flm-nav-group-items` | Links container |
575
+ | `flm-nav-group-items--collapsed` | Hidden (toggled by JS). Apply to `.flm-nav-group-items`, NOT the parent group |
576
+ | `flm-nav-link` | Navigation link |
577
+ | `flm-nav-link--active` | Active/selected link |
578
+ | `flm-nav-link--disabled` | Disabled link |
579
+ | `flm-nav-link--nested` | Extra indentation |
580
+ | `flm-nav-chevron` | Expand/collapse icon |
581
+ | `flm-nav-chevron--expanded` | Rotated 90deg |
582
+
583
+ ---
584
+
585
+ ## Breadcrumb
586
+
587
+ ```html
588
+ <ol class="flm-breadcrumb">
589
+ <li class="flm-breadcrumb-item"><a class="flm-breadcrumb-link" href="#">Home</a></li>
590
+ <li class="flm-breadcrumb-item"><a class="flm-breadcrumb-link" href="#">Library</a></li>
591
+ <li class="flm-breadcrumb-item"><a class="flm-breadcrumb-link">Current Page</a></li>
592
+ </ol>
593
+ ```
594
+
595
+ | Class | Effect |
596
+ |-------|--------|
597
+ | `flm-breadcrumb` | `<ol>` container |
598
+ | `flm-breadcrumb--small` | Smaller font |
599
+ | `flm-breadcrumb--large` | Larger font + semibold |
600
+ | `flm-breadcrumb-item` | `<li>` wrapper |
601
+ | `flm-breadcrumb-link` | Clickable text |
602
+ | `flm-breadcrumb-overflow` | "..." overflow button |
603
+
604
+ ---
605
+
606
+ ## Pivot
607
+
608
+ ```html
609
+ <div class="flm-pivot">
610
+ <div class="flm-pivot-tabs" role="tablist">
611
+ <button class="flm-pivot-tab flm-pivot-tab--active" data-panel="p1" role="tab">Tab 1</button>
612
+ <button class="flm-pivot-tab" data-panel="p2" role="tab">Tab 2</button>
613
+ <button class="flm-pivot-tab flm-pivot-tab--disabled" role="tab">Disabled</button>
614
+ </div>
615
+ <div class="flm-pivot-panel flm-pivot-panel--active" id="p1" role="tabpanel">Content 1</div>
616
+ <div class="flm-pivot-panel" id="p2" role="tabpanel">Content 2</div>
617
+ </div>
618
+ ```
619
+
620
+ | Class | Effect |
621
+ |-------|--------|
622
+ | `flm-pivot` | Container |
623
+ | `flm-pivot--links` | Link-style tabs (wider padding) |
624
+ | `flm-pivot--tabs` | Filled tab style |
625
+ | `flm-pivot-tabs` | Tab bar |
626
+ | `flm-pivot-tab` | Individual tab button |
627
+ | `flm-pivot-tab--active` | Selected tab |
628
+ | `flm-pivot-tab--disabled` | Disabled tab |
629
+ | `flm-pivot-panel` | Content panel |
630
+ | `flm-pivot-panel--active` | Visible panel |
631
+
632
+ | Attribute | Effect |
633
+ |-----------|--------|
634
+ | `data-panel="id"` | Links tab to panel by id |
635
+
636
+ ---
637
+
638
+ ## DetailsList
639
+
640
+ ```html
641
+ <div class="flm-detailslist">
642
+ <div class="flm-detailslist-header">
643
+ <div class="flm-detailslist-check"><label class="flm-checkbox"><input type="checkbox" class="flm-checkbox-input"><span class="flm-checkbox-mark"></span></label></div>
644
+ <div class="flm-detailslist-header-cell" style="width: 200px;">Name</div>
645
+ <div class="flm-detailslist-header-cell" style="width: 120px;">Status</div>
646
+ <div class="flm-detailslist-header-cell" style="flex: 1;">Date</div>
647
+ </div>
648
+ <div class="flm-detailslist-row">
649
+ <div class="flm-detailslist-check"><label class="flm-checkbox"><input type="checkbox" class="flm-checkbox-input"><span class="flm-checkbox-mark"></span></label></div>
650
+ <div class="flm-detailslist-cell" style="width: 200px;">Document.pdf</div>
651
+ <div class="flm-detailslist-cell" style="width: 120px;">Active</div>
652
+ <div class="flm-detailslist-cell" style="flex: 1;">Feb 20, 2026</div>
653
+ </div>
654
+ </div>
655
+ ```
656
+
657
+ | Class | Effect |
658
+ |-------|--------|
659
+ | `flm-detailslist` | Table container |
660
+ | `flm-detailslist--compact` | Reduced row height (32px) |
661
+ | `flm-detailslist-header` | Header row |
662
+ | `flm-detailslist-header-cell` | Column header |
663
+ | `flm-detailslist-row` | Data row |
664
+ | `flm-detailslist-row--selected` | Selected row highlight |
665
+ | `flm-detailslist-cell` | Data cell |
666
+ | `flm-detailslist-check` | Row checkbox column |
667
+ | `flm-detailslist-empty` | Empty state message |
668
+
669
+ Set column widths via inline `style="width: 200px"` or `style="flex: 1"`.
670
+
671
+ ---
672
+
673
+ ## SearchBox
674
+
675
+ ```html
676
+ <div class="flm-searchbox">
677
+ <input class="flm-searchbox-input" type="text" placeholder="Search…">
678
+ </div>
679
+ ```
680
+
681
+ | Class | Effect |
682
+ |-------|--------|
683
+ | `flm-searchbox` | Container (JS injects icon + clear btn) |
684
+ | `flm-searchbox--underlined` | Bottom border only |
685
+ | `flm-searchbox--disabled` | Disabled state |
686
+
687
+ | Child class | Element |
688
+ |-------------|---------|
689
+ | `flm-searchbox-input` | `<input type="text">` |
690
+ | `flm-searchbox-icon` | Search icon (auto-injected) |
691
+ | `flm-searchbox-clear` | Clear button (auto-injected) |
692
+
693
+ ---
694
+
695
+ ## ContextualMenu
696
+
697
+ ```html
698
+ <button class="flm-button" data-contextmenu-toggle="menu1">Menu</button>
699
+ <div class="flm-contextmenu" id="menu1">
700
+ <div class="flm-contextmenu-header">Actions</div>
701
+ <button class="flm-contextmenu-item"><span class="flm-contextmenu-item-text">Edit</span></button>
702
+ <button class="flm-contextmenu-item"><span class="flm-contextmenu-item-text">Copy</span></button>
703
+ <div class="flm-contextmenu-divider"></div>
704
+ <button class="flm-contextmenu-item" disabled><span class="flm-contextmenu-item-text">Delete</span></button>
705
+ </div>
706
+ ```
707
+
708
+ | Class | Effect |
709
+ |-------|--------|
710
+ | `flm-contextmenu` | Menu container (give it an `id`) |
711
+ | `flm-contextmenu-item` | Menu item button |
712
+ | `flm-contextmenu-item--checked` | Shows checkmark |
713
+ | `flm-contextmenu-divider` | Horizontal rule |
714
+ | `flm-contextmenu-header` | Section header |
715
+
716
+ | Attribute | Effect |
717
+ |-----------|--------|
718
+ | `data-contextmenu-toggle="id"` | Click trigger |
719
+ | `data-contextmenu="id"` | Right-click trigger |
720
+ | `disabled` | Disabled item |
721
+
722
+ | Child class | Element |
723
+ |-------------|---------|
724
+ | `flm-contextmenu-item-icon` | Leading icon |
725
+ | `flm-contextmenu-item-text` | Item label |
726
+ | `flm-contextmenu-item-submenu` | Submenu chevron |
727
+
728
+ ---
729
+
730
+ ## ProgressIndicator
731
+
732
+ ```html
733
+ <div class="flm-progress">
734
+ <span class="flm-progress-label">Uploading…</span>
735
+ <div class="flm-progress-track"><div class="flm-progress-bar" style="width: 60%"></div></div>
736
+ <span class="flm-progress-description">60% complete</span>
737
+ </div>
738
+
739
+ <div class="flm-progress flm-progress--indeterminate">
740
+ <div class="flm-progress-track"><div class="flm-progress-bar"></div></div>
741
+ </div>
742
+ ```
743
+
744
+ | Class | Effect |
745
+ |-------|--------|
746
+ | `flm-progress` | Container |
747
+ | `flm-progress--indeterminate` | Animated looping bar |
748
+
749
+ | Child class | Element |
750
+ |-------------|---------|
751
+ | `flm-progress-label` | Title text |
752
+ | `flm-progress-track` | Background rail |
753
+ | `flm-progress-bar` | Filled portion (set `width` via style) |
754
+ | `flm-progress-description` | Subtitle text |
755
+
756
+ ---
757
+
758
+ ## Tooltip
759
+
760
+ ```html
761
+ <span data-tooltip="Helpful info">Hover me</span>
762
+ ```
763
+
764
+ | Class | Effect |
765
+ |-------|--------|
766
+ | `flm-tooltip-host` | Explicit wrapper (optional — `data-tooltip` on any element works) |
767
+ | `flm-tooltip` | Tooltip box (for pre-defined rich tooltips) |
768
+
769
+ | Attribute | Effect |
770
+ |-----------|--------|
771
+ | `data-tooltip="text"` | Simple text tooltip (auto-created by JS) |
772
+ | `data-tooltip-id="id"` | References a pre-defined `.flm-tooltip` element |
773
+
774
+ ---
775
+
776
+ ## Persona
777
+
778
+ ```html
779
+ <div class="flm-persona flm-persona--size40">
780
+ <div class="flm-persona-coin flm-persona-presence flm-persona-presence--available">JD</div>
781
+ <div class="flm-persona-details">
782
+ <span class="flm-persona-name">Jane Doe</span>
783
+ <span class="flm-persona-secondary">Software Engineer</span>
784
+ </div>
785
+ </div>
786
+ ```
787
+
788
+ | Class | Size |
789
+ |-------|------|
790
+ | `flm-persona--size24` | 24px (default) |
791
+ | `flm-persona--size32` | 32px |
792
+ | `flm-persona--size40` | 40px |
793
+ | `flm-persona--size48` | 48px |
794
+ | `flm-persona--size56` | 56px |
795
+ | `flm-persona--size72` | 72px |
796
+ | `flm-persona--size100` | 100px |
797
+ | `flm-persona--size120` | 120px |
798
+
799
+ | Presence class | Status |
800
+ |----------------|--------|
801
+ | `flm-persona-presence--available` | Green |
802
+ | `flm-persona-presence--away` | Yellow |
803
+ | `flm-persona-presence--busy` | Red |
804
+ | `flm-persona-presence--dnd` | Red |
805
+ | `flm-persona-presence--offline` | Gray |
806
+
807
+ | Child class | Element |
808
+ |-------------|---------|
809
+ | `flm-persona-coin` | Avatar circle (initials or `<img>`) |
810
+ | `flm-persona-details` | Text wrapper |
811
+ | `flm-persona-name` | Primary name |
812
+ | `flm-persona-secondary` | Title / role |
813
+ | `flm-persona-tertiary` | Additional info |
814
+
815
+ ---
816
+
817
+ ## Image
818
+
819
+ ```html
820
+ <img class="flm-image" src="photo.jpg" alt="Description">
821
+ <img class="flm-image flm-image--cover flm-image--round" src="avatar.jpg" alt="User" style="width:48px;height:48px">
822
+ ```
823
+
824
+ | Class | Effect |
825
+ |-------|--------|
826
+ | `flm-image` | Base image |
827
+ | `flm-image--cover` | `object-fit: cover` |
828
+ | `flm-image--contain` | `object-fit: contain` |
829
+ | `flm-image--center` | Centered, no scaling |
830
+ | `flm-image--border` | Border + rounded corners |
831
+ | `flm-image--round` | Circular |
832
+ | `flm-image--maximize` | Fill parent 100% |
833
+
834
+ ---
835
+
836
+ ## ChoiceGroup
837
+
838
+ ```html
839
+ <div class="flm-choicegroup">
840
+ <label class="flm-choicegroup-option">
841
+ <input type="radio" class="flm-choicegroup-input" name="g1" value="a" checked>
842
+ <span class="flm-choicegroup-mark"></span>
843
+ <span class="flm-choicegroup-label">Option A</span>
844
+ </label>
845
+ <label class="flm-choicegroup-option">
846
+ <input type="radio" class="flm-choicegroup-input" name="g1" value="b">
847
+ <span class="flm-choicegroup-mark"></span>
848
+ <span class="flm-choicegroup-label">Option B</span>
849
+ </label>
850
+ </div>
851
+ ```
852
+
853
+ | Class | Effect |
854
+ |-------|--------|
855
+ | `flm-choicegroup` | Radio group container |
856
+ | `flm-choicegroup--horizontal` | Row layout |
857
+ | `flm-choicegroup-option` | Individual radio (is a `<label>`) |
858
+ | `flm-choicegroup-option--disabled` | Dimmed, pair with `disabled` on input |
859
+
860
+ | Child class | Element |
861
+ |-------------|---------|
862
+ | `flm-choicegroup-input` | Hidden native `<input type="radio">` |
863
+ | `flm-choicegroup-mark` | Visual radio circle |
864
+ | `flm-choicegroup-label` | Text label |
865
+
866
+ Native: `checked`, `disabled`.
867
+
868
+ ---
869
+
870
+ ## Shimmer
871
+
872
+ ```html
873
+ <div class="flm-shimmer">
874
+ <div class="flm-shimmer-line"></div>
875
+ <div class="flm-shimmer-line flm-shimmer-line--medium"></div>
876
+ <div class="flm-shimmer-line flm-shimmer-line--short"></div>
877
+ </div>
878
+
879
+ <div class="flm-shimmer flm-shimmer--row">
880
+ <div class="flm-shimmer-circle"></div>
881
+ <div class="flm-shimmer" style="flex:1">
882
+ <div class="flm-shimmer-line"></div>
883
+ <div class="flm-shimmer-line flm-shimmer-line--medium"></div>
884
+ </div>
885
+ </div>
886
+ ```
887
+
888
+ | Class | Effect |
889
+ |-------|--------|
890
+ | `flm-shimmer` | Container (vertical) |
891
+ | `flm-shimmer--row` | Horizontal composition |
892
+
893
+ | Element class | Shape |
894
+ |---------------|-------|
895
+ | `flm-shimmer-line` | 16px bar (full width) |
896
+ | `flm-shimmer-line--short` | 40% width |
897
+ | `flm-shimmer-line--medium` | 70% width |
898
+ | `flm-shimmer-circle` | 40px circle |
899
+ | `flm-shimmer-circle--small` | 24px circle |
900
+ | `flm-shimmer-circle--large` | 56px circle |
901
+ | `flm-shimmer-rect` | 120×120px block |
902
+ | `flm-shimmer-rect--wide` | 200px wide |
903
+ | `flm-shimmer-rect--tall` | 200px tall |
904
+
905
+ ---
906
+
907
+ ## List
908
+
909
+ ```html
910
+ <div class="flm-list flm-list--bordered flm-list--scrollable">
911
+ <div class="flm-list-item flm-list-item--selected">Selected</div>
912
+ <div class="flm-list-item">
913
+ <div class="flm-list-item-content">
914
+ <span class="flm-list-item-primary">Title</span>
915
+ <span class="flm-list-item-secondary">Subtitle</span>
916
+ </div>
917
+ </div>
918
+ <div class="flm-list-item flm-list-item--disabled">Disabled</div>
919
+ </div>
920
+ ```
921
+
922
+ | Class | Effect |
923
+ |-------|--------|
924
+ | `flm-list` | List container |
925
+ | `flm-list--bordered` | Border + dividers |
926
+ | `flm-list--scrollable` | Scrollable (300px max-height) |
927
+ | `flm-list--compact` | Reduced row height |
928
+ | `flm-list-item` | Row (36px min-height) |
929
+ | `flm-list-item--selected` | Checked background |
930
+ | `flm-list-item--disabled` | Dimmed, no pointer events |
931
+
932
+ | Child class | Element |
933
+ |-------------|---------|
934
+ | `flm-list-item-icon` | Leading icon |
935
+ | `flm-list-item-content` | Wrapper for two-line layout |
936
+ | `flm-list-item-primary` | Primary text |
937
+ | `flm-list-item-secondary` | Secondary text |
938
+
939
+ ---
940
+
941
+ ## GroupedList
942
+
943
+ ```html
944
+ <div class="flm-groupedlist">
945
+ <div class="flm-groupedlist-group">
946
+ <button class="flm-groupedlist-header">
947
+ <i class="flm-groupedlist-chevron flm-groupedlist-chevron--expanded" data-icon="ChevronRight"></i>
948
+ Group Name <span class="flm-groupedlist-count">(3)</span>
949
+ </button>
950
+ <div class="flm-groupedlist-items">
951
+ <div class="flm-groupedlist-item">Item 1</div>
952
+ <div class="flm-groupedlist-item">Item 2</div>
953
+ </div>
954
+ </div>
955
+ </div>
956
+ ```
957
+
958
+ | Class | Effect |
959
+ |-------|--------|
960
+ | `flm-groupedlist` | Container |
961
+ | `flm-groupedlist-group` | Section group |
962
+ | `flm-groupedlist-header` | Collapsible group title |
963
+ | `flm-groupedlist-items` | Items container |
964
+ | `flm-groupedlist-items--collapsed` | Hidden (toggled by JS) |
965
+ | `flm-groupedlist-item` | Individual item |
966
+ | `flm-groupedlist-item--selected` | Selected item |
967
+ | `flm-groupedlist-item--disabled` | Disabled item |
968
+ | `flm-groupedlist-chevron` | Expand/collapse icon |
969
+ | `flm-groupedlist-chevron--expanded` | Rotated 90deg |
970
+ | `flm-groupedlist-count` | Item count badge |
971
+
972
+ ---
973
+
974
+ ## Rating
975
+
976
+ ```html
977
+ <div class="flm-rating">
978
+ <input type="radio" class="flm-rating-input" name="r" value="5"><label class="flm-rating-star"></label>
979
+ <input type="radio" class="flm-rating-input" name="r" value="4"><label class="flm-rating-star"></label>
980
+ <input type="radio" class="flm-rating-input" name="r" value="3" checked><label class="flm-rating-star"></label>
981
+ <input type="radio" class="flm-rating-input" name="r" value="2"><label class="flm-rating-star"></label>
982
+ <input type="radio" class="flm-rating-input" name="r" value="1"><label class="flm-rating-star"></label>
983
+ </div>
984
+ ```
985
+
986
+ | Class | Effect |
987
+ |-------|--------|
988
+ | `flm-rating` | Container (radio inputs ordered 5→1) |
989
+ | `flm-rating--readonly` | Non-interactive, use `--filled`/`--empty` on stars |
990
+ | `flm-rating--disabled` | Dimmed, no interaction |
991
+ | `flm-rating--large` | Larger stars (32px) |
992
+
993
+ | Child class | Element |
994
+ |-------------|---------|
995
+ | `flm-rating-input` | Hidden `<input type="radio">` |
996
+ | `flm-rating-star` | Star label (clip-path shape) |
997
+ | `flm-rating-star--filled` | Filled star (readonly mode) |
998
+ | `flm-rating-star--empty` | Empty star (readonly mode) |
999
+
1000
+ JS stores `data-rating-value` on root.
1001
+
1002
+ ---
1003
+
1004
+ ## Facepile
1005
+
1006
+ ```html
1007
+ <div class="flm-facepile" data-max="3">
1008
+ <span class="flm-facepile-member"><span class="flm-persona-coin">JD</span></span>
1009
+ <span class="flm-facepile-member"><span class="flm-persona-coin">AB</span></span>
1010
+ <span class="flm-facepile-member"><span class="flm-persona-coin">MK</span></span>
1011
+ <span class="flm-facepile-member"><span class="flm-persona-coin">TW</span></span>
1012
+ </div>
1013
+ ```
1014
+
1015
+ | Class | Effect |
1016
+ |-------|--------|
1017
+ | `flm-facepile` | Container |
1018
+ | `flm-facepile-member` | Overlapping coin wrapper |
1019
+ | `flm-facepile-overflow` | +N chip (auto-injected by JS) |
1020
+ | `flm-facepile-add` | Add person button |
1021
+
1022
+ | Attribute | Effect |
1023
+ |-----------|--------|
1024
+ | `data-max="N"` | JS hides excess members, shows +N overflow |
1025
+
1026
+ ---
1027
+
1028
+ ## SwatchColorPicker
1029
+
1030
+ ```html
1031
+ <div class="flm-swatchcolorpicker">
1032
+ <button class="flm-swatchcolorpicker-cell" style="background-color: #ff1744;" data-color="#ff1744"></button>
1033
+ <button class="flm-swatchcolorpicker-cell flm-swatchcolorpicker-cell--selected" style="background-color: #2979ff;" data-color="#2979ff"></button>
1034
+ </div>
1035
+ ```
1036
+
1037
+ | Class | Effect |
1038
+ |-------|--------|
1039
+ | `flm-swatchcolorpicker` | Grid container |
1040
+ | `flm-swatchcolorpicker--circle` | Circular swatches |
1041
+ | `flm-swatchcolorpicker--large` | 32px swatches |
1042
+ | `flm-swatchcolorpicker-cell` | Color button (set `background-color` inline) |
1043
+ | `flm-swatchcolorpicker-cell--selected` | Selection ring |
1044
+ | `flm-swatchcolorpicker-cell--disabled` | Dimmed |
1045
+
1046
+ | Attribute | Effect |
1047
+ |-----------|--------|
1048
+ | `data-color="hex"` | Color value for JS selection tracking |
1049
+
1050
+ JS sets `data-selected` and `data-selected-color` on root.
1051
+
1052
+ ---
1053
+
1054
+ ## DocumentCard
1055
+
1056
+ ```html
1057
+ <div class="flm-documentcard">
1058
+ <div class="flm-documentcard-preview">
1059
+ <div class="flm-documentcard-preview-icon"><i class="flm-icon flm-icon--large" data-icon="Document"></i></div>
1060
+ </div>
1061
+ <div class="flm-documentcard-details">
1062
+ <span class="flm-documentcard-title">Report.docx</span>
1063
+ </div>
1064
+ <div class="flm-documentcard-activity">
1065
+ <span class="flm-persona-coin" style="width:24px;height:24px;font-size:10px;">JD</span>
1066
+ <div>
1067
+ <span class="flm-documentcard-activity-name">Jane Doe</span>
1068
+ <span class="flm-documentcard-activity-date">Feb 20</span>
1069
+ </div>
1070
+ </div>
1071
+ </div>
1072
+ ```
1073
+
1074
+ | Class | Effect |
1075
+ |-------|--------|
1076
+ | `flm-documentcard` | Card container (212px) |
1077
+ | `flm-documentcard--compact` | Horizontal layout |
1078
+
1079
+ | Child class | Element |
1080
+ |-------------|---------|
1081
+ | `flm-documentcard-preview` | Image/icon area |
1082
+ | `flm-documentcard-preview-icon` | Centered icon |
1083
+ | `flm-documentcard-details` | Title/text area |
1084
+ | `flm-documentcard-title` | Document name |
1085
+ | `flm-documentcard-activity` | Persona + timestamp row |
1086
+ | `flm-documentcard-activity-name` | Author name |
1087
+ | `flm-documentcard-activity-date` | Timestamp |
1088
+ | `flm-documentcard-actions` | Action buttons row |
1089
+
1090
+ ---
1091
+
1092
+ ## SpinButton
1093
+
1094
+ ```html
1095
+ <div class="flm-spinbutton-wrapper">
1096
+ <label class="flm-label" for="sb1">Quantity</label>
1097
+ <div class="flm-spinbutton">
1098
+ <button class="flm-spinbutton-btn flm-spinbutton-btn--decrement" data-icon="ChevronDown" aria-label="Decrease"></button>
1099
+ <input class="flm-spinbutton-input" id="sb1" type="number" value="5" min="0" max="100" step="1">
1100
+ <button class="flm-spinbutton-btn flm-spinbutton-btn--increment" data-icon="ChevronUp" aria-label="Increase"></button>
1101
+ </div>
1102
+ </div>
1103
+ ```
1104
+
1105
+ | Class | Effect |
1106
+ |-------|--------|
1107
+ | `flm-spinbutton` | Input + buttons container |
1108
+ | `flm-spinbutton--disabled` | Disabled state |
1109
+ | `flm-spinbutton-wrapper` | Outer wrapper with label |
1110
+
1111
+ | Child class | Element |
1112
+ |-------------|---------|
1113
+ | `flm-spinbutton-input` | `<input type="number">` (native spinners hidden) |
1114
+ | `flm-spinbutton-btn` | Inc/dec button |
1115
+ | `flm-spinbutton-btn--decrement` | Decrement button |
1116
+ | `flm-spinbutton-btn--increment` | Increment button |
1117
+
1118
+ JS wires buttons to `stepUp()`/`stepDown()`.
1119
+
1120
+ ---
1121
+
1122
+ ## Slider
1123
+
1124
+ ```html
1125
+ <div class="flm-slider">
1126
+ <div class="flm-slider-label">
1127
+ <label class="flm-label" for="sl1">Volume</label>
1128
+ </div>
1129
+ <div class="flm-slider-container">
1130
+ <input class="flm-slider-input" id="sl1" type="range" min="0" max="100" value="60">
1131
+ <span class="flm-slider-value">60</span>
1132
+ </div>
1133
+ </div>
1134
+ ```
1135
+
1136
+ | Class | Effect |
1137
+ |-------|--------|
1138
+ | `flm-slider` | Container |
1139
+ | `flm-slider--disabled` | Disabled state |
1140
+ | `flm-slider--vertical` | Vertical orientation |
1141
+
1142
+ | Child class | Element |
1143
+ |-------------|---------|
1144
+ | `flm-slider-container` | Flex wrapper for input + value |
1145
+ | `flm-slider-input` | `<input type="range">` |
1146
+ | `flm-slider-value` | Live value display |
1147
+ | `flm-slider-label` | Label row |
1148
+
1149
+ JS sets `--flm-slider-fill` CSS var for track gradient.
1150
+
1151
+ ---
1152
+
1153
+ ## ComboBox
1154
+
1155
+ ```html
1156
+ <div class="flm-combobox">
1157
+ <label class="flm-label">Fruit</label>
1158
+ <div class="flm-combobox-wrapper">
1159
+ <input class="flm-combobox-input" placeholder="Select…">
1160
+ <button class="flm-combobox-caret" data-icon="ChevronDown" aria-label="Toggle"></button>
1161
+ </div>
1162
+ <div class="flm-combobox-listbox">
1163
+ <div class="flm-combobox-option" data-value="apple">Apple</div>
1164
+ <div class="flm-combobox-option" data-value="banana">Banana</div>
1165
+ </div>
1166
+ </div>
1167
+ ```
1168
+
1169
+ | Class | Effect |
1170
+ |-------|--------|
1171
+ | `flm-combobox` | Container |
1172
+ | `flm-combobox--disabled` | Disabled state |
1173
+ | `flm-combobox--error` | Error border |
1174
+
1175
+ | Attribute | Effect |
1176
+ |-----------|--------|
1177
+ | `data-multiselect` | On `.flm-combobox` — enables multi-select mode |
1178
+ | `data-value="val"` | On `.flm-combobox-option` — option value |
1179
+
1180
+ | Child class | Element |
1181
+ |-------------|---------|
1182
+ | `flm-combobox-wrapper` | Input + caret row |
1183
+ | `flm-combobox-input` | Text input |
1184
+ | `flm-combobox-caret` | Dropdown toggle button |
1185
+ | `flm-combobox-listbox` | Options dropdown |
1186
+ | `flm-combobox-option` | Individual option |
1187
+ | `flm-combobox-option--selected` | Selected option |
1188
+ | `flm-combobox-option--disabled` | Disabled option |
1189
+ | `flm-combobox-option-check` | Checkbox (multi-select mode) |
1190
+ | `flm-combobox-error` | Error message |
1191
+
1192
+ JS: filtering, keyboard nav (ArrowUp/Down/Enter/Escape), click-outside dismiss, flip-above.
1193
+
1194
+ ---
1195
+
1196
+ ## TeachingBubble
1197
+
1198
+ ```html
1199
+ <button data-teachingbubble-toggle="tb1">Learn more</button>
1200
+ <div class="flm-teachingbubble" id="tb1">
1201
+ <div class="flm-teachingbubble-beak"></div>
1202
+ <div class="flm-teachingbubble-header">
1203
+ <h3 class="flm-teachingbubble-headline">Welcome!</h3>
1204
+ <button class="flm-teachingbubble-close" data-icon="Cancel" aria-label="Close"></button>
1205
+ </div>
1206
+ <div class="flm-teachingbubble-body">Guidance text here.</div>
1207
+ <div class="flm-teachingbubble-footer">
1208
+ <button class="flm-button flm-button--primary">Got it!</button>
1209
+ </div>
1210
+ </div>
1211
+ ```
1212
+
1213
+ | Class | Effect |
1214
+ |-------|--------|
1215
+ | `flm-teachingbubble` | Inverted-color callout (themePrimary bg) |
1216
+
1217
+ | Attribute | Effect |
1218
+ |-----------|--------|
1219
+ | `data-teachingbubble-toggle="id"` | Toggle trigger |
1220
+
1221
+ | Child class | Element |
1222
+ |-------------|---------|
1223
+ | `flm-teachingbubble-beak` | Arrow pointing to target |
1224
+ | `flm-teachingbubble-header` | Header row |
1225
+ | `flm-teachingbubble-headline` | Title |
1226
+ | `flm-teachingbubble-close` | Close button |
1227
+ | `flm-teachingbubble-body` | Content text |
1228
+ | `flm-teachingbubble-footer` | Action buttons |
1229
+
1230
+ Button colors automatically inverted inside `.flm-teachingbubble`.
1231
+
1232
+ ---
1233
+
1234
+ ## HoverCard
1235
+
1236
+ ```html
1237
+ <span data-hovercard-id="hc1" style="cursor:pointer">Hover me</span>
1238
+ <div class="flm-hovercard" id="hc1">
1239
+ <div class="flm-hovercard-compact">
1240
+ <div class="flm-hovercard-title">Jane Doe</div>
1241
+ <div class="flm-hovercard-subtitle">Engineer</div>
1242
+ </div>
1243
+ <div class="flm-hovercard-expanded">
1244
+ <div class="flm-hovercard-body">Extended details…</div>
1245
+ </div>
1246
+ </div>
1247
+ ```
1248
+
1249
+ | Class | Effect |
1250
+ |-------|--------|
1251
+ | `flm-hovercard` | Positioned card |
1252
+
1253
+ | Attribute | Effect |
1254
+ |-----------|--------|
1255
+ | `data-hovercard-id="id"` | On host — links to hovercard |
1256
+
1257
+ | Child class | Element |
1258
+ |-------------|---------|
1259
+ | `flm-hovercard-compact` | First phase (shows after 500ms) |
1260
+ | `flm-hovercard-expanded` | Second phase (shows after 1500ms total) |
1261
+ | `flm-hovercard-title` | Title |
1262
+ | `flm-hovercard-subtitle` | Subtitle |
1263
+ | `flm-hovercard-body` | Body text |
1264
+
1265
+ Card stays open while mouse is over it.
1266
+
1267
+ ---
1268
+
1269
+ ## Coachmark
1270
+
1271
+ ```html
1272
+ <div class="flm-coachmark" data-teachingbubble-toggle="tb1">
1273
+ <div class="flm-coachmark-dot"></div>
1274
+ <div class="flm-coachmark-ring"></div>
1275
+ </div>
1276
+ <div class="flm-teachingbubble" id="tb1">…</div>
1277
+ ```
1278
+
1279
+ | Class | Effect |
1280
+ |-------|--------|
1281
+ | `flm-coachmark` | Pulsing beacon |
1282
+ | `flm-coachmark--hidden` | Hidden (auto-set when bubble dismissed) |
1283
+ | `flm-coachmark--dark` | Dark theme variant |
1284
+
1285
+ | Attribute | Effect |
1286
+ |-----------|--------|
1287
+ | `data-teachingbubble-toggle="id"` | Click opens linked TeachingBubble |
1288
+
1289
+ | Child class | Element |
1290
+ |-------------|---------|
1291
+ | `flm-coachmark-dot` | Central dot |
1292
+ | `flm-coachmark-ring` | Pulsing ring animation |
1293
+
1294
+ JS uses MutationObserver to auto-hide beacon when bubble is dismissed.
1295
+
1296
+ ---
1297
+
1298
+ ## DatePicker
1299
+
1300
+ ```html
1301
+ <div class="flm-datepicker" data-min-date="01/01/2026" data-max-date="12/31/2026">
1302
+ <label class="flm-label" for="dp1">Date</label>
1303
+ <div class="flm-datepicker-wrapper">
1304
+ <input class="flm-datepicker-input" id="dp1" placeholder="MM/DD/YYYY">
1305
+ <button class="flm-datepicker-icon" data-icon="Calendar" aria-label="Open calendar"></button>
1306
+ </div>
1307
+ </div>
1308
+ ```
1309
+
1310
+ | Class | Effect |
1311
+ |-------|--------|
1312
+ | `flm-datepicker` | Container |
1313
+ | `flm-datepicker--disabled` | Disabled state |
1314
+ | `flm-datepicker--error` | Error border |
1315
+
1316
+ | Attribute | Effect |
1317
+ |-----------|--------|
1318
+ | `data-min-date="MM/DD/YYYY"` | Minimum selectable date |
1319
+ | `data-max-date="MM/DD/YYYY"` | Maximum selectable date |
1320
+
1321
+ | Child class | Element |
1322
+ |-------------|---------|
1323
+ | `flm-datepicker-wrapper` | Input + icon row |
1324
+ | `flm-datepicker-input` | Text input |
1325
+ | `flm-datepicker-icon` | Calendar toggle button |
1326
+ | `flm-datepicker-error` | Error message |
1327
+
1328
+ JS generates 42-cell calendar grid on open. Month nav via prev/next buttons. Day click formats as MM/DD/YYYY.
1329
+
1330
+ ---
1331
+
1332
+ ## TagPicker
1333
+
1334
+ ```html
1335
+ <div class="flm-tagpicker">
1336
+ <label class="flm-label">Tags</label>
1337
+ <div class="flm-tagpicker-well">
1338
+ <input class="flm-tagpicker-input" placeholder="Add tags…">
1339
+ </div>
1340
+ <div class="flm-tagpicker-listbox">
1341
+ <div class="flm-tagpicker-option" data-value="react">React</div>
1342
+ <div class="flm-tagpicker-option" data-value="vue">Vue</div>
1343
+ </div>
1344
+ </div>
1345
+ ```
1346
+
1347
+ PeoplePicker variant:
1348
+
1349
+ ```html
1350
+ <div class="flm-tagpicker flm-tagpicker--people">
1351
+ <label class="flm-label">People</label>
1352
+ <div class="flm-tagpicker-well">
1353
+ <input class="flm-tagpicker-input" placeholder="Search people…">
1354
+ </div>
1355
+ <div class="flm-tagpicker-listbox">
1356
+ <div class="flm-tagpicker-option" data-value="jane" data-initials="JD" data-secondary="Engineer">
1357
+ <span class="flm-tagpicker-option-coin">JD</span>
1358
+ <span class="flm-tagpicker-option-details">
1359
+ <span class="flm-tagpicker-option-name">Jane Doe</span>
1360
+ <span class="flm-tagpicker-option-secondary">Engineer</span>
1361
+ </span>
1362
+ </div>
1363
+ </div>
1364
+ </div>
1365
+ ```
1366
+
1367
+ | Class | Effect |
1368
+ |-------|--------|
1369
+ | `flm-tagpicker` | Container |
1370
+ | `flm-tagpicker--people` | PeoplePicker variant (shows persona coins) |
1371
+ | `flm-tagpicker--disabled` | Disabled state |
1372
+ | `flm-tagpicker--error` | Error border |
1373
+
1374
+ | Attribute | Effect |
1375
+ |-----------|--------|
1376
+ | `data-max-tags="N"` | Limits number of selected tags |
1377
+ | `data-value="val"` | On `.flm-tagpicker-option` — option value |
1378
+ | `data-initials="XX"` | On option — initials for persona coin (people variant) |
1379
+ | `data-secondary="text"` | On option — secondary text (people variant) |
1380
+ | `data-selected-values` | Auto-maintained CSV of selected values on root |
1381
+
1382
+ | Child class | Element |
1383
+ |-------------|---------|
1384
+ | `flm-tagpicker-well` | Input area holding chips + input |
1385
+ | `flm-tagpicker-input` | Text input |
1386
+ | `flm-tagpicker-chip` | Selected tag pill |
1387
+ | `flm-tagpicker-chip-text` | Chip label text |
1388
+ | `flm-tagpicker-chip-remove` | Chip remove (X) button |
1389
+ | `flm-tagpicker-chip-coin` | Small persona coin in chip (people variant) |
1390
+ | `flm-tagpicker-listbox` | Options dropdown |
1391
+ | `flm-tagpicker-option` | Individual option |
1392
+ | `flm-tagpicker-option--selected` | Already-picked option (grayed out) |
1393
+ | `flm-tagpicker-option-coin` | Persona coin in option (people variant) |
1394
+ | `flm-tagpicker-option-details` | Name + secondary text wrapper |
1395
+ | `flm-tagpicker-option-name` | Primary name |
1396
+ | `flm-tagpicker-option-secondary` | Secondary text |
1397
+ | `flm-tagpicker-error` | Error message |
1398
+
1399
+ JS: type-to-filter, keyboard nav (ArrowUp/Down/Enter/Escape), Backspace removes last chip, click X removes chip, click-outside dismiss, flip-above.
1400
+
1401
+ ---
1402
+
1403
+ ## OverflowSet
1404
+
1405
+ ```html
1406
+ <div class="flm-overflowset">
1407
+ <div class="flm-overflowset-items">
1408
+ <button class="flm-overflowset-item" data-label="New" data-icon="Add">New</button>
1409
+ <button class="flm-overflowset-item" data-label="Edit" data-icon="Edit">Edit</button>
1410
+ </div>
1411
+ <button class="flm-overflowset-overflow" aria-label="More items">...</button>
1412
+ <div class="flm-overflowset-far">
1413
+ <button class="flm-overflowset-item">Settings</button>
1414
+ </div>
1415
+ </div>
1416
+ ```
1417
+
1418
+ | Class | Effect |
1419
+ |-------|--------|
1420
+ | `flm-overflowset` | Container (flex row, overflow hidden) |
1421
+ | `flm-overflowset--has-overflow` | Auto-set when items overflow (shows "..." button) |
1422
+ | `flm-overflowset-items` | Flex row holding the items |
1423
+ | `flm-overflowset-item` | Individual item (`flex-shrink: 0`) |
1424
+ | `flm-overflowset-item--hidden` | Hidden by JS (overflowed) |
1425
+ | `flm-overflowset-overflow` | "..." overflow button |
1426
+ | `flm-overflowset-far` | Right-side items (never overflow, `margin-left: auto`) |
1427
+
1428
+ | Attribute | Effect |
1429
+ |-----------|--------|
1430
+ | `data-overflow-order="N"` | Higher N overflows first (priority control) |
1431
+ | `data-label="text"` | Label shown in overflow menu |
1432
+ | `data-icon="Name"` | Icon shown in overflow menu |
1433
+
1434
+ JS: ResizeObserver measures available width, hides items that don't fit, builds a ContextMenu for hidden items. Clicking a menu item proxies the original item's click.
1435
+
1436
+ ---
1437
+
1438
+ ## TimePicker
1439
+
1440
+ ```html
1441
+ <div class="flm-timepicker" data-increment="30" data-use-12h data-min-time="09:00" data-max-time="17:00">
1442
+ <label class="flm-label" for="tp1">Time</label>
1443
+ <div class="flm-timepicker-wrapper">
1444
+ <input class="flm-timepicker-input" id="tp1" placeholder="Select a time…">
1445
+ <button class="flm-timepicker-icon" data-icon="Clock" aria-label="Open time picker"></button>
1446
+ </div>
1447
+ </div>
1448
+ ```
1449
+
1450
+ | Class | Effect |
1451
+ |-------|--------|
1452
+ | `flm-timepicker` | Container |
1453
+ | `flm-timepicker--disabled` | Disabled state |
1454
+ | `flm-timepicker--error` | Error border |
1455
+
1456
+ | Attribute | Effect |
1457
+ |-----------|--------|
1458
+ | `data-increment="30"` | Minute increment (default 30) |
1459
+ | `data-use-12h` | 12-hour format with AM/PM (default 24h) |
1460
+ | `data-min-time="HH:MM"` | Earliest available time (24h format) |
1461
+ | `data-max-time="HH:MM"` | Latest available time (24h format) |
1462
+
1463
+ | Child class | Element |
1464
+ |-------------|---------|
1465
+ | `flm-timepicker-wrapper` | Input + icon row |
1466
+ | `flm-timepicker-input` | Text input (typeable, filters options) |
1467
+ | `flm-timepicker-icon` | Clock toggle button |
1468
+ | `flm-timepicker-error` | Error message |
1469
+
1470
+ JS generates time-slot options at the configured increment. Input text filters the list. Arrow keys navigate, Enter selects, Escape closes. Auto-scrolls to selected or nearest-to-current-time option on open.
1471
+
1472
+ ---
1473
+
1474
+ ## CSS Custom Properties
1475
+
1476
+ Use these variables in inline `style` attributes or demo-specific `<style>` blocks. They automatically adapt to light/dark theme. **Do not use Fluent UI v2 variable names** (e.g. `--colorNeutralForeground1`) — they are not defined in this library.
1477
+
1478
+ ### Semantic Colors (theme-aware)
1479
+
1480
+ Use these for page layout, custom containers, and demo styling:
1481
+
1482
+ | Variable | Purpose |
1483
+ |----------|---------|
1484
+ | `--bodyBackground` | Page / container background |
1485
+ | `--bodyStandoutBackground` | Slightly offset background (sidebars, cards) |
1486
+ | `--bodyFrameBackground` | Frame / shell background |
1487
+ | `--bodyFrameDivider` | Border between frame sections |
1488
+ | `--bodyDivider` | General divider lines |
1489
+ | `--bodyText` | Primary text color |
1490
+ | `--bodyTextChecked` | Text on checked/selected background |
1491
+ | `--bodySubtext` | Secondary / caption text |
1492
+ | `--disabledText` | Disabled text |
1493
+ | `--errorText` | Error text |
1494
+ | `--successText` | Success text |
1495
+ | `--link` | Link color |
1496
+ | `--linkHovered` | Link hover color |
1497
+ | `--overlayBackground` | Semi-transparent backdrop |
1498
+ | `--defaultStateBackground` | Default surface background |
1499
+ | `--focusBorder` | Focus outline color |
1500
+
1501
+ ### Palette Colors
1502
+
1503
+ Raw color values — **not** theme-aware (same in light and dark):
1504
+
1505
+ | Variable | Value |
1506
+ |----------|-------|
1507
+ | `--themePrimary` | `#0078d4` (brand blue) |
1508
+ | `--themeDark` | `#005a9e` |
1509
+ | `--themeDarkAlt` | `#106ebe` |
1510
+ | `--themeDarker` | `#004578` |
1511
+ | `--themeSecondary` | `#2b88d8` |
1512
+ | `--themeTertiary` | `#71afe5` |
1513
+ | `--themeLight` | `#c7e0f4` |
1514
+ | `--themeLighter` | `#deecf9` |
1515
+ | `--themeLighterAlt` | `#eff6fc` |
1516
+ | `--black` | `#000000` |
1517
+ | `--white` | `#ffffff` |
1518
+ | `--neutralPrimary` | `#323130` |
1519
+ | `--neutralSecondary` | `#605e5c` |
1520
+ | `--neutralTertiary` | `#a19f9d` |
1521
+ | `--neutralLight` | `#edebe9` |
1522
+ | `--neutralLighter` | `#f3f2f1` |
1523
+ | `--neutralLighterAlt` | `#faf9f8` |
1524
+ | `--red` | `#e81123` |
1525
+ | `--redDark` | `#a4262c` |
1526
+ | `--orange` | `#d83b01` |
1527
+ | `--yellow` | `#ffb900` |
1528
+ | `--green` | `#107c10` |
1529
+ | `--teal` | `#008272` |
1530
+ | `--blue` | `#0078d4` |
1531
+ | `--purple` | `#5c2d91` |
1532
+
1533
+ ### Status Backgrounds (theme-aware)
1534
+
1535
+ | Variable | Purpose |
1536
+ |----------|---------|
1537
+ | `--infoBackground` | Info message bar / banner |
1538
+ | `--errorBackground` | Error state |
1539
+ | `--warningBackground` | Warning state |
1540
+ | `--severeWarningBackground` | Severe warning state |
1541
+ | `--successBackground` | Success state |
1542
+ | `--blockingBackground` | Blocking state |
1543
+
1544
+ ### Typography
1545
+
1546
+ | Variable | Value |
1547
+ |----------|-------|
1548
+ | `--fontFamily` | Segoe UI system stack |
1549
+ | `--fontFamilyMonospace` | Cascadia Code / Consolas |
1550
+ | `--fontSizeTiny` | `10px` |
1551
+ | `--fontSizeSmall` | `12px` |
1552
+ | `--fontSizeMedium` | `14px` |
1553
+ | `--fontSizeMediumPlus` | `16px` |
1554
+ | `--fontSizeLarge` | `18px` |
1555
+ | `--fontSizeXLarge` | `20px` |
1556
+ | `--fontSizeXXLarge` | `28px` |
1557
+ | `--fontSizeSuperLarge` | `42px` |
1558
+ | `--fontSizeMega` | `68px` |
1559
+ | `--fontWeightRegular` | `400` |
1560
+ | `--fontWeightSemibold` | `600` |
1561
+ | `--fontWeightBold` | `700` |
1562
+
1563
+ ### Spacing
1564
+
1565
+ | Variable | Value |
1566
+ |----------|-------|
1567
+ | `--spacingS2` | `4px` |
1568
+ | `--spacingS1` | `8px` |
1569
+ | `--spacingM` | `16px` |
1570
+ | `--spacingL1` | `20px` |
1571
+ | `--spacingL2` | `32px` |
1572
+
1573
+ ### Effects
1574
+
1575
+ | Variable | Purpose |
1576
+ |----------|---------|
1577
+ | `--elevation4` | Subtle shadow (cards) |
1578
+ | `--elevation8` | Medium shadow (dropdowns, callouts) |
1579
+ | `--elevation16` | Prominent shadow (dialogs, panels) |
1580
+ | `--elevation64` | Dramatic shadow |
1581
+ | `--roundedCorner2` | `2px` border radius |
1582
+ | `--roundedCorner4` | `4px` border radius |
1583
+ | `--roundedCorner6` | `6px` border radius |
1584
+
1585
+ ### Motion
1586
+
1587
+ | Variable | Value |
1588
+ |----------|-------|
1589
+ | `--duration1` | `100ms` |
1590
+ | `--duration2` | `200ms` |
1591
+ | `--duration3` | `300ms` |
1592
+ | `--duration4` | `400ms` |
1593
+ | `--easeAccelerate` | `cubic-bezier(0.9, 0.1, 1, 0.2)` |
1594
+ | `--easeDecelerate` | `cubic-bezier(0.1, 0.9, 0.2, 1)` |
1595
+ | `--easeStandard` | `cubic-bezier(0.8, 0, 0.2, 1)` |