@mhmo91/schmancy 0.10.34 → 0.10.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/custom-elements.json +1144 -1101
- package/dist/SchmancyElement-BBzRWB1w.cjs +2 -0
- package/dist/SchmancyElement-BBzRWB1w.cjs.map +1 -0
- package/dist/SchmancyElement-C3CpdNsi.js +284 -0
- package/dist/SchmancyElement-C3CpdNsi.js.map +1 -0
- package/dist/agent/schmancy.agent.js +3414 -3263
- package/dist/agent/schmancy.agent.js.map +1 -1
- package/dist/agent/schmancy.manifest.json +335 -276
- package/dist/{area-DviXdbDx.js → area-BA96mwFY.js} +2 -2
- package/dist/{area-DviXdbDx.js.map → area-BA96mwFY.js.map} +1 -1
- package/dist/{area-CTSTgjlx.cjs → area-DtyQDdOF.cjs} +1 -1
- package/dist/{area-CTSTgjlx.cjs.map → area-DtyQDdOF.cjs.map} +1 -1
- package/dist/area.cjs +1 -1
- package/dist/area.js +1 -1
- package/dist/{audio-Q9oB_cQR.cjs → audio-B_jT9Xr7.cjs} +1 -1
- package/dist/{audio-Q9oB_cQR.cjs.map → audio-B_jT9Xr7.cjs.map} +1 -1
- package/dist/{audio-DFYoaw0M.js → audio-D52h1jAT.js} +1 -1
- package/dist/{audio-DFYoaw0M.js.map → audio-D52h1jAT.js.map} +1 -1
- package/dist/audio.cjs +1 -1
- package/dist/audio.js +2 -2
- package/dist/{autocomplete-DmLXJr7C.cjs → autocomplete-Bts5Jwwr.cjs} +1 -1
- package/dist/{autocomplete-DmLXJr7C.cjs.map → autocomplete-Bts5Jwwr.cjs.map} +1 -1
- package/dist/{autocomplete-BDvuma6D.js → autocomplete-CI4QJXAN.js} +3 -3
- package/dist/{autocomplete-BDvuma6D.js.map → autocomplete-CI4QJXAN.js.map} +1 -1
- package/dist/autocomplete.cjs +1 -1
- package/dist/autocomplete.js +1 -1
- package/dist/avatar.cjs +1 -1
- package/dist/avatar.js +3 -3
- package/dist/badge.cjs +1 -1
- package/dist/badge.js +1 -1
- package/dist/boat-I4B1UNMc.cjs +34 -0
- package/dist/boat-I4B1UNMc.cjs.map +1 -0
- package/dist/boat-_N1x5U_3.js +191 -0
- package/dist/boat-_N1x5U_3.js.map +1 -0
- package/dist/boat.cjs +1 -1
- package/dist/boat.js +1 -1
- package/dist/breadcrumb.cjs +1 -1
- package/dist/breadcrumb.js +2 -2
- package/dist/{busy-CgzZbGfx.cjs → busy-BIUonyPk.cjs} +1 -1
- package/dist/{busy-CgzZbGfx.cjs.map → busy-BIUonyPk.cjs.map} +1 -1
- package/dist/{busy-DgQ4ux5N.js → busy-CCB3qKnh.js} +2 -2
- package/dist/{busy-DgQ4ux5N.js.map → busy-CCB3qKnh.js.map} +1 -1
- package/dist/busy.cjs +1 -1
- package/dist/busy.js +1 -1
- package/dist/{button-qbN1muQ0.js → button-C89bPnHt.js} +2 -2
- package/dist/{button-qbN1muQ0.js.map → button-C89bPnHt.js.map} +1 -1
- package/dist/{button-DFvR1iXX.cjs → button-CkwQH-g3.cjs} +1 -1
- package/dist/{button-DFvR1iXX.cjs.map → button-CkwQH-g3.cjs.map} +1 -1
- package/dist/button.cjs +4 -4
- package/dist/button.cjs.map +1 -1
- package/dist/button.js +16 -22
- package/dist/button.js.map +1 -1
- package/dist/{card-D_GlwZ5q.cjs → card-BO93_oxQ.cjs} +1 -1
- package/dist/{card-D_GlwZ5q.cjs.map → card-BO93_oxQ.cjs.map} +1 -1
- package/dist/{card-DAbr-7Vy.js → card-CFsCgJKZ.js} +2 -2
- package/dist/{card-DAbr-7Vy.js.map → card-CFsCgJKZ.js.map} +1 -1
- package/dist/card.cjs +1 -1
- package/dist/card.js +1 -1
- package/dist/{checkbox-BNORaxMF.js → checkbox-Bh7q0djq.js} +2 -2
- package/dist/{checkbox-BNORaxMF.js.map → checkbox-Bh7q0djq.js.map} +1 -1
- package/dist/{checkbox-BUY_uc_r.cjs → checkbox-CFUBUFtW.cjs} +1 -1
- package/dist/{checkbox-BUY_uc_r.cjs.map → checkbox-CFUBUFtW.cjs.map} +1 -1
- package/dist/checkbox.cjs +1 -1
- package/dist/checkbox.js +1 -1
- package/dist/{chips-Dg6Lk6BT.js → chips-6YaoRmeG.js} +145 -122
- package/dist/chips-6YaoRmeG.js.map +1 -0
- package/dist/{chips-CXZ4dJCK.cjs → chips-BfzpsyV1.cjs} +44 -33
- package/dist/chips-BfzpsyV1.cjs.map +1 -0
- package/dist/chips.cjs +1 -1
- package/dist/chips.js +2 -2
- package/dist/connectivity.cjs +1 -1
- package/dist/connectivity.js +3 -3
- package/dist/content-drawer.cjs +1 -1
- package/dist/content-drawer.js +1 -1
- package/dist/{date-range-BU6WX7d5.js → date-range-CEo_Kjqw.js} +129 -137
- package/dist/date-range-CEo_Kjqw.js.map +1 -0
- package/dist/{date-range-C-_be3_E.cjs → date-range-N-A249O9.cjs} +25 -19
- package/dist/date-range-N-A249O9.cjs.map +1 -0
- package/dist/{date-range-inline-7o7xtVIu.js → date-range-inline-BwialV9j.js} +2 -2
- package/dist/{date-range-inline-7o7xtVIu.js.map → date-range-inline-BwialV9j.js.map} +1 -1
- package/dist/{date-range-inline-DJtUmHKF.cjs → date-range-inline-DFopysWF.cjs} +1 -1
- package/dist/{date-range-inline-DJtUmHKF.cjs.map → date-range-inline-DFopysWF.cjs.map} +1 -1
- package/dist/date-range-inline.cjs +1 -1
- package/dist/date-range-inline.js +1 -1
- package/dist/date-range.cjs +1 -1
- package/dist/date-range.js +1 -1
- package/dist/delay.cjs +1 -1
- package/dist/delay.js +2 -2
- package/dist/{details-Bs0MyyvF.cjs → details-BLRPV8sY.cjs} +1 -1
- package/dist/{details-Bs0MyyvF.cjs.map → details-BLRPV8sY.cjs.map} +1 -1
- package/dist/{details-EfbDPVEo.js → details-GtpfI2hA.js} +2 -2
- package/dist/{details-EfbDPVEo.js.map → details-GtpfI2hA.js.map} +1 -1
- package/dist/details.cjs +1 -1
- package/dist/details.js +1 -1
- package/dist/{directives-zi1Mm2er.js → directives-C2dXgpCY.js} +13 -6
- package/dist/directives-C2dXgpCY.js.map +1 -0
- package/dist/{directives-fLwDj6b0.cjs → directives-CvYGSW_a.cjs} +2 -2
- package/dist/directives-CvYGSW_a.cjs.map +1 -0
- package/dist/directives.cjs +1 -1
- package/dist/directives.js +2 -2
- package/dist/{divider-CEPfrIwe.js → divider-D0pGX2VB.js} +2 -2
- package/dist/{divider-CEPfrIwe.js.map → divider-D0pGX2VB.js.map} +1 -1
- package/dist/{divider-CdIsWZrM.cjs → divider-rNsWCvMi.cjs} +1 -1
- package/dist/{divider-CdIsWZrM.cjs.map → divider-rNsWCvMi.cjs.map} +1 -1
- package/dist/divider.cjs +1 -1
- package/dist/divider.js +1 -1
- package/dist/dropdown.cjs +1 -1
- package/dist/dropdown.js +2 -2
- package/dist/{expand-g1vqqUp1.js → expand-FcKAzJta.js} +3 -3
- package/dist/{expand-g1vqqUp1.js.map → expand-FcKAzJta.js.map} +1 -1
- package/dist/{expand--at1k3qo.cjs → expand-tffQHGbZ.cjs} +1 -1
- package/dist/{expand--at1k3qo.cjs.map → expand-tffQHGbZ.cjs.map} +1 -1
- package/dist/expand.cjs +1 -1
- package/dist/expand.js +1 -1
- package/dist/fab.cjs +77 -0
- package/dist/fab.cjs.map +1 -0
- package/dist/fab.js +151 -0
- package/dist/fab.js.map +1 -0
- package/dist/{float-P9HukAm-.cjs → float-CDjgxWyy.cjs} +1 -1
- package/dist/{float-P9HukAm-.cjs.map → float-CDjgxWyy.cjs.map} +1 -1
- package/dist/{float-DxVzgI9o.js → float-CQ1WEp3M.js} +2 -2
- package/dist/{float-DxVzgI9o.js.map → float-CQ1WEp3M.js.map} +1 -1
- package/dist/float.cjs +1 -1
- package/dist/float.js +1 -1
- package/dist/{form-CqLaozHp.js → form-H24puioV.js} +3 -3
- package/dist/{form-CqLaozHp.js.map → form-H24puioV.js.map} +1 -1
- package/dist/{form-ByYhXe1p.cjs → form-VYhbbir3.cjs} +1 -1
- package/dist/{form-ByYhXe1p.cjs.map → form-VYhbbir3.cjs.map} +1 -1
- package/dist/form.cjs +6 -6
- package/dist/form.cjs.map +1 -1
- package/dist/form.js +25 -23
- package/dist/form.js.map +1 -1
- package/dist/handover/agent-runtime-followups.md +1 -1
- package/dist/handover/agent-runtime-v1.md +3 -3
- package/dist/{icons-DYtiRU5V.cjs → icons-B_a1HStW.cjs} +1 -1
- package/dist/{icons-DYtiRU5V.cjs.map → icons-B_a1HStW.cjs.map} +1 -1
- package/dist/{icons-CkphcMp6.js → icons-DBxfN91B.js} +2 -2
- package/dist/{icons-CkphcMp6.js.map → icons-DBxfN91B.js.map} +1 -1
- package/dist/icons.cjs +1 -1
- package/dist/icons.js +1 -1
- package/dist/{iframe-CjqJksl8.js → iframe-BDVElN8z.js} +2 -2
- package/dist/{iframe-CjqJksl8.js.map → iframe-BDVElN8z.js.map} +1 -1
- package/dist/{iframe-C3trkP8q.cjs → iframe-CG-z9qev.cjs} +1 -1
- package/dist/{iframe-C3trkP8q.cjs.map → iframe-CG-z9qev.cjs.map} +1 -1
- package/dist/iframe.cjs +1 -1
- package/dist/iframe.js +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +57 -56
- package/dist/{input-DuavpwNL.cjs → input-B14Nn6xD.cjs} +1 -1
- package/dist/{input-DuavpwNL.cjs.map → input-B14Nn6xD.cjs.map} +1 -1
- package/dist/{input-CG51zDVh.js → input-Bt_o4sYo.js} +2 -2
- package/dist/{input-CG51zDVh.js.map → input-Bt_o4sYo.js.map} +1 -1
- package/dist/{input-chip-C6Lq1927.js → input-chip-DEqO0DXc.js} +2 -2
- package/dist/input-chip-DEqO0DXc.js.map +1 -0
- package/dist/{input-chip-57tgNXKT.cjs → input-chip-ugYu9Fn9.cjs} +1 -1
- package/dist/input-chip-ugYu9Fn9.cjs.map +1 -0
- package/dist/input.cjs +1 -1
- package/dist/input.js +1 -1
- package/dist/json.cjs +1 -1
- package/dist/json.js +3 -3
- package/dist/kbd.cjs +1 -1
- package/dist/kbd.js +2 -2
- package/dist/{layout-D4IOwx7p.js → layout-BJ_43VrH.js} +1 -1
- package/dist/{layout-D4IOwx7p.js.map → layout-BJ_43VrH.js.map} +1 -1
- package/dist/{layout-6ipbiWTl.cjs → layout-DF9ZaQ-b.cjs} +1 -1
- package/dist/{layout-6ipbiWTl.cjs.map → layout-DF9ZaQ-b.cjs.map} +1 -1
- package/dist/layout.cjs +1 -1
- package/dist/layout.js +2 -2
- package/dist/{lightbox-H8pVWGMX.cjs → lightbox-B47Zoqv-.cjs} +1 -1
- package/dist/{lightbox-H8pVWGMX.cjs.map → lightbox-B47Zoqv-.cjs.map} +1 -1
- package/dist/{lightbox-CsyO2XSr.js → lightbox-ZmuoBBFT.js} +2 -2
- package/dist/{lightbox-CsyO2XSr.js.map → lightbox-ZmuoBBFT.js.map} +1 -1
- package/dist/lightbox.cjs +1 -1
- package/dist/lightbox.js +1 -1
- package/dist/{list-BAwH0pQW.js → list-C47xzld_.js} +2 -2
- package/dist/{list-BAwH0pQW.js.map → list-C47xzld_.js.map} +1 -1
- package/dist/{list-Bs9m8kw7.cjs → list-CaSWrlG2.cjs} +1 -1
- package/dist/{list-Bs9m8kw7.cjs.map → list-CaSWrlG2.cjs.map} +1 -1
- package/dist/list.cjs +1 -1
- package/dist/list.js +1 -1
- package/dist/{menu-tQVARVaC.js → menu-8RObM6Ie.js} +3 -3
- package/dist/{menu-tQVARVaC.js.map → menu-8RObM6Ie.js.map} +1 -1
- package/dist/{menu-BMcGzj1h.cjs → menu-Jpsy85SX.cjs} +1 -1
- package/dist/{menu-BMcGzj1h.cjs.map → menu-Jpsy85SX.cjs.map} +1 -1
- package/dist/menu.cjs +1 -1
- package/dist/menu.js +1 -1
- package/dist/{mixins-CGXSzZc7.cjs → mixins-DPdzC9ZH.cjs} +1 -1
- package/dist/{mixins-CGXSzZc7.cjs.map → mixins-DPdzC9ZH.cjs.map} +1 -1
- package/dist/{mixins-Bp0wIHg2.js → mixins-DTzfFVyv.js} +1 -1
- package/dist/{mixins-Bp0wIHg2.js.map → mixins-DTzfFVyv.js.map} +1 -1
- package/dist/mixins.cjs +1 -1
- package/dist/mixins.js +2 -2
- package/dist/nav-drawer.cjs +1 -1
- package/dist/nav-drawer.js +1 -1
- package/dist/navigation-bar.cjs +1 -1
- package/dist/navigation-bar.js +1 -1
- package/dist/navigation-rail.cjs +1 -1
- package/dist/navigation-rail.js +2 -2
- package/dist/{notification-D1tX2nx5.js → notification-Ccktcj9H.js} +4 -4
- package/dist/{notification-D1tX2nx5.js.map → notification-Ccktcj9H.js.map} +1 -1
- package/dist/{notification-Bz00zdpV.cjs → notification-DSkB-sn0.cjs} +1 -1
- package/dist/{notification-Bz00zdpV.cjs.map → notification-DSkB-sn0.cjs.map} +1 -1
- package/dist/notification.cjs +1 -1
- package/dist/notification.js +1 -1
- package/dist/{option-BnybLEDO.cjs → option-0aNiVB3Q.cjs} +1 -1
- package/dist/{option-BnybLEDO.cjs.map → option-0aNiVB3Q.cjs.map} +1 -1
- package/dist/{option-BpGV8Apj.js → option-CkMxwBqU.js} +2 -2
- package/dist/{option-BpGV8Apj.js.map → option-CkMxwBqU.js.map} +1 -1
- package/dist/option.cjs +1 -1
- package/dist/option.js +1 -1
- package/dist/{overlay-UQR2Dy3u.cjs → overlay-BS-ta-zq.cjs} +5 -5
- package/dist/overlay-BS-ta-zq.cjs.map +1 -0
- package/dist/{overlay-BpNhd74N.js → overlay-H3Wt_dgQ.js} +108 -108
- package/dist/overlay-H3Wt_dgQ.js.map +1 -0
- package/dist/overlay.cjs +1 -1
- package/dist/{overlay.confirm-body-CVDtVk5X.cjs → overlay.confirm-body-CR9xaqOE.cjs} +1 -1
- package/dist/{overlay.confirm-body-CVDtVk5X.cjs.map → overlay.confirm-body-CR9xaqOE.cjs.map} +1 -1
- package/dist/{overlay.confirm-body-BHcXu5Wk.js → overlay.confirm-body-Dxn_wNm3.js} +6 -6
- package/dist/{overlay.confirm-body-BHcXu5Wk.js.map → overlay.confirm-body-Dxn_wNm3.js.map} +1 -1
- package/dist/overlay.js +3 -3
- package/dist/{overlay.service-DTE6NwIM.js → overlay.service-C46kOtUi.js} +2 -2
- package/dist/{overlay.service-DTE6NwIM.js.map → overlay.service-C46kOtUi.js.map} +1 -1
- package/dist/{overlay.service-C8RsQzgM.cjs → overlay.service-DEj3rfRr.cjs} +1 -1
- package/dist/{overlay.service-C8RsQzgM.cjs.map → overlay.service-DEj3rfRr.cjs.map} +1 -1
- package/dist/{progress-CAKsxp29.js → progress-BK7gSq8j.js} +2 -2
- package/dist/{progress-CAKsxp29.js.map → progress-BK7gSq8j.js.map} +1 -1
- package/dist/{progress-gbIALDRs.cjs → progress-zs18GR6C.cjs} +1 -1
- package/dist/{progress-gbIALDRs.cjs.map → progress-zs18GR6C.cjs.map} +1 -1
- package/dist/progress.cjs +1 -1
- package/dist/progress.js +1 -1
- package/dist/{radio-group-otyvZvUk.js → radio-group-1HCpzRUB.js} +2 -2
- package/dist/{radio-group-otyvZvUk.js.map → radio-group-1HCpzRUB.js.map} +1 -1
- package/dist/{radio-group-CfJ5DtI4.cjs → radio-group-DbYlyPc-.cjs} +1 -1
- package/dist/{radio-group-CfJ5DtI4.cjs.map → radio-group-DbYlyPc-.cjs.map} +1 -1
- package/dist/radio-group.cjs +1 -1
- package/dist/radio-group.js +1 -1
- package/dist/range.cjs +1 -1
- package/dist/range.js +2 -2
- package/dist/{select-81jniVTs.cjs → select-B-SSmUDe.cjs} +1 -1
- package/dist/{select-81jniVTs.cjs.map → select-B-SSmUDe.cjs.map} +1 -1
- package/dist/{select-9vXx1fhr.js → select-CEyhNtZ2.js} +3 -3
- package/dist/{select-9vXx1fhr.js.map → select-CEyhNtZ2.js.map} +1 -1
- package/dist/select.cjs +1 -1
- package/dist/select.js +1 -1
- package/dist/skeleton.cjs +1 -1
- package/dist/skeleton.js +2 -2
- package/dist/skills/INDEX.md +1 -1
- package/dist/skills/SKILL.md +6 -7
- package/dist/skills/boat.md +21 -15
- package/dist/skills/fab.md +75 -0
- package/dist/skills/schmancy/INDEX.md +1 -1
- package/dist/skills/schmancy/SKILL.md +6 -7
- package/dist/skills/schmancy/boat.md +21 -15
- package/dist/skills/schmancy/fab.md +75 -0
- package/dist/skills/schmancy/theme.md +1 -1
- package/dist/skills/theme.md +1 -1
- package/dist/slider.cjs +1 -1
- package/dist/slider.js +2 -2
- package/dist/{sound.service-D3ZSq1Kj.js → sound.service-DO4SmUUT.js} +1 -1
- package/dist/{sound.service-D3ZSq1Kj.js.map → sound.service-DO4SmUUT.js.map} +1 -1
- package/dist/{sound.service-CmIw63aM.cjs → sound.service-G_8GV_6L.cjs} +1 -1
- package/dist/{sound.service-CmIw63aM.cjs.map → sound.service-G_8GV_6L.cjs.map} +1 -1
- package/dist/{splash-screen-BOjrmGLk.js → splash-screen-B1mM4_xz.js} +2 -2
- package/dist/{splash-screen-BOjrmGLk.js.map → splash-screen-B1mM4_xz.js.map} +1 -1
- package/dist/{splash-screen-C5KAWXvA.cjs → splash-screen-cbz4bxjB.cjs} +1 -1
- package/dist/{splash-screen-C5KAWXvA.cjs.map → splash-screen-cbz4bxjB.cjs.map} +1 -1
- package/dist/splash-screen.cjs +1 -1
- package/dist/splash-screen.js +1 -1
- package/dist/{src-Bm1vop0l.cjs → src-czeiuT1m.cjs} +1 -1
- package/dist/{src-Bm1vop0l.cjs.map → src-czeiuT1m.cjs.map} +1 -1
- package/dist/{src-DoOhMBtI.js → src-tncsWsTY.js} +36 -35
- package/dist/{src-DoOhMBtI.js.map → src-tncsWsTY.js.map} +1 -1
- package/dist/{state-Cex3rmx2.cjs → state-Cx0aoL5e.cjs} +1 -1
- package/dist/{state-Cex3rmx2.cjs.map → state-Cx0aoL5e.cjs.map} +1 -1
- package/dist/{state-CWBRTSvE.js → state-DJDp3N7J.js} +1 -1
- package/dist/{state-CWBRTSvE.js.map → state-DJDp3N7J.js.map} +1 -1
- package/dist/state.cjs +1 -1
- package/dist/state.js +2 -2
- package/dist/steps.cjs +1 -1
- package/dist/steps.js +2 -2
- package/dist/{surface-PfiejLuw.cjs → surface-C3cxTcJD.cjs} +1 -1
- package/dist/{surface-PfiejLuw.cjs.map → surface-C3cxTcJD.cjs.map} +1 -1
- package/dist/{surface-9S5scTsD.js → surface-CYBl8_a3.js} +2 -2
- package/dist/{surface-9S5scTsD.js.map → surface-CYBl8_a3.js.map} +1 -1
- package/dist/surface.cjs +1 -1
- package/dist/surface.js +1 -1
- package/dist/switch.cjs +1 -1
- package/dist/switch.js +2 -2
- package/dist/table.cjs +1 -1
- package/dist/table.js +2 -2
- package/dist/{tabs-BBOjAmgG.js → tabs-DHy93Q3N.js} +2 -2
- package/dist/{tabs-BBOjAmgG.js.map → tabs-DHy93Q3N.js.map} +1 -1
- package/dist/{tabs-uYvb1P06.cjs → tabs-ORQ_Zd43.cjs} +1 -1
- package/dist/{tabs-uYvb1P06.cjs.map → tabs-ORQ_Zd43.cjs.map} +1 -1
- package/dist/tabs.cjs +1 -1
- package/dist/tabs.js +1 -1
- package/dist/teleport.cjs +1 -1
- package/dist/teleport.js +1 -1
- package/dist/{textarea-YPHX4g7Y.cjs → textarea-CEUaDURR.cjs} +1 -1
- package/dist/{textarea-YPHX4g7Y.cjs.map → textarea-CEUaDURR.cjs.map} +1 -1
- package/dist/{textarea-QzSj8Dkl.js → textarea-DHIMt-ly.js} +2 -2
- package/dist/{textarea-QzSj8Dkl.js.map → textarea-DHIMt-ly.js.map} +1 -1
- package/dist/textarea.cjs +1 -1
- package/dist/textarea.js +1 -1
- package/dist/theme-CJpjkqHr.cjs +181 -0
- package/dist/{theme-iKUaS9JB.cjs.map → theme-CJpjkqHr.cjs.map} +1 -1
- package/dist/{theme-C2Mp-VGt.js → theme-CgI9PRco.js} +6 -5
- package/dist/{theme-C2Mp-VGt.js.map → theme-CgI9PRco.js.map} +1 -1
- package/dist/{theme-button-CJmhxfMe.cjs → theme-button--FuBkuVr.cjs} +1 -1
- package/dist/{theme-button-CJmhxfMe.cjs.map → theme-button--FuBkuVr.cjs.map} +1 -1
- package/dist/{theme-button-DGWAXhzd.js → theme-button-D-FXb3oO.js} +2 -2
- package/dist/{theme-button-DGWAXhzd.js.map → theme-button-D-FXb3oO.js.map} +1 -1
- package/dist/theme-button.cjs +1 -1
- package/dist/theme-button.js +1 -1
- package/dist/theme.cjs +1 -1
- package/dist/theme.js +3 -3
- package/dist/{theme.service-hc4N-1Oz.js → theme.service-BfTK1Wtl.js} +1 -1
- package/dist/{theme.service-hc4N-1Oz.js.map → theme.service-BfTK1Wtl.js.map} +1 -1
- package/dist/{theme.service-p61RsJBF.cjs → theme.service-Dg7LO0Qz.cjs} +1 -1
- package/dist/{theme.service-p61RsJBF.cjs.map → theme.service-Dg7LO0Qz.cjs.map} +1 -1
- package/dist/tree.cjs +1 -1
- package/dist/tree.js +2 -2
- package/dist/{typography-DwV0sqht.js → typography-BEGLfHwz.js} +2 -2
- package/dist/{typography-DwV0sqht.js.map → typography-BEGLfHwz.js.map} +1 -1
- package/dist/{typography-Bdt8RlX2.cjs → typography-CxA3sx9B.cjs} +1 -1
- package/dist/{typography-Bdt8RlX2.cjs.map → typography-CxA3sx9B.cjs.map} +1 -1
- package/dist/typography.cjs +1 -1
- package/dist/typography.js +1 -1
- package/dist/visually-hidden.cjs +1 -1
- package/dist/visually-hidden.js +2 -2
- package/dist/{window-n4jN60B_.js → window-B_n4P9az.js} +3 -3
- package/dist/{window-n4jN60B_.js.map → window-B_n4P9az.js.map} +1 -1
- package/dist/{window-D2WfvNng.cjs → window-Vl1u1-EG.cjs} +1 -1
- package/dist/{window-D2WfvNng.cjs.map → window-Vl1u1-EG.cjs.map} +1 -1
- package/dist/window.cjs +1 -1
- package/dist/window.js +1 -1
- package/package.json +1 -1
- package/skills/schmancy/INDEX.md +1 -1
- package/skills/schmancy/SKILL.md +6 -7
- package/skills/schmancy/boat.md +21 -15
- package/skills/schmancy/fab.md +75 -0
- package/skills/schmancy/theme.md +1 -1
- package/src/CLAUDE.md +22 -16
- package/src/boat/boat.test.ts +130 -0
- package/src/boat/boat.ts +192 -186
- package/src/button/icon-button.ts +18 -30
- package/src/chips/assist-chip.ts +2 -263
- package/src/chips/chips.ts +2 -259
- package/src/chips/filter-chip.ts +2 -255
- package/src/chips/index.ts +2 -5
- package/src/chips/input-chip.ts +2 -413
- package/src/chips/suggestion-chip.ts +2 -266
- package/src/directives/fill.ts +28 -5
- package/src/fab/fab.test.ts +101 -0
- package/src/fab/fab.ts +226 -0
- package/src/fab/index.ts +1 -0
- package/src/form/fields/chips/assist-chip.ts +263 -0
- package/src/form/fields/chips/chips.ts +234 -0
- package/src/form/fields/chips/filter-chip.ts +255 -0
- package/src/form/fields/chips/index.ts +5 -0
- package/src/form/fields/chips/input-chip.ts +413 -0
- package/src/form/fields/chips/suggestion-chip.ts +266 -0
- package/src/form/fields/date-range/date-range.test.ts +44 -0
- package/src/form/fields/date-range/date-range.ts +103 -97
- package/src/form/fields/index.ts +1 -0
- package/src/index.ts +2 -1
- package/src/overlay/overlay.animations.ts +2 -3
- package/src/overlay/overlay.component.ts +8 -4
- package/src/overlay/overlay.types.ts +14 -2
- package/src/theme/theme.component.ts +1 -0
- package/src/theme/theme.style.css +3 -0
- package/types/src/boat/boat.d.ts +40 -25
- package/types/src/boat/boat.test.d.ts +2 -0
- package/types/src/button/icon-button.d.ts +3 -2
- package/types/src/chips/assist-chip.d.ts +1 -47
- package/types/src/chips/chips.d.ts +1 -43
- package/types/src/chips/filter-chip.d.ts +1 -67
- package/types/src/chips/index.d.ts +1 -5
- package/types/src/chips/input-chip.d.ts +1 -82
- package/types/src/chips/suggestion-chip.d.ts +1 -52
- package/types/src/fab/fab.d.ts +80 -0
- package/types/src/fab/fab.test.d.ts +2 -0
- package/types/src/fab/index.d.ts +1 -0
- package/types/src/form/fields/chips/assist-chip.d.ts +47 -0
- package/types/src/form/fields/chips/chips.d.ts +35 -0
- package/types/src/form/fields/chips/filter-chip.d.ts +67 -0
- package/types/src/form/fields/chips/index.d.ts +5 -0
- package/types/src/form/fields/chips/input-chip.d.ts +82 -0
- package/types/src/form/fields/chips/suggestion-chip.d.ts +52 -0
- package/types/src/form/fields/date-range/date-range.d.ts +5 -10
- package/types/src/form/fields/index.d.ts +1 -0
- package/types/src/index.d.ts +2 -1
- package/types/src/overlay/overlay.component.d.ts +1 -0
- package/types/src/overlay/overlay.types.d.ts +12 -2
- package/types/src/theme/theme.component.d.ts +1 -0
- package/dist/SchmancyElement-CA0Wqt8m.js +0 -284
- package/dist/SchmancyElement-CA0Wqt8m.js.map +0 -1
- package/dist/SchmancyElement-CYIif26I.cjs +0 -2
- package/dist/SchmancyElement-CYIif26I.cjs.map +0 -1
- package/dist/boat-BgpWcLnV.cjs +0 -38
- package/dist/boat-BgpWcLnV.cjs.map +0 -1
- package/dist/boat-Y5UMiJCV.js +0 -216
- package/dist/boat-Y5UMiJCV.js.map +0 -1
- package/dist/chips-CXZ4dJCK.cjs.map +0 -1
- package/dist/chips-Dg6Lk6BT.js.map +0 -1
- package/dist/date-range-BU6WX7d5.js.map +0 -1
- package/dist/date-range-C-_be3_E.cjs.map +0 -1
- package/dist/directives-fLwDj6b0.cjs.map +0 -1
- package/dist/directives-zi1Mm2er.js.map +0 -1
- package/dist/input-chip-57tgNXKT.cjs.map +0 -1
- package/dist/input-chip-C6Lq1927.js.map +0 -1
- package/dist/overlay-BpNhd74N.js.map +0 -1
- package/dist/overlay-UQR2Dy3u.cjs.map +0 -1
- package/dist/theme-iKUaS9JB.cjs +0 -181
|
@@ -1,266 +1,2 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { customElement, property, state } from 'lit/decorators.js'
|
|
4
|
-
import { classMap } from 'lit/directives/class-map.js'
|
|
5
|
-
import { BehaviorSubject, combineLatest } from 'rxjs'
|
|
6
|
-
import { takeUntil } from 'rxjs/operators'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Suggestion chip component - provides contextual recommendations to users
|
|
10
|
-
*
|
|
11
|
-
* IMPORTANT: Suggestion chips do NOT have a selected state. They are designed to
|
|
12
|
-
* provide suggestions and recommendations that trigger actions when clicked.
|
|
13
|
-
* Unlike filter chips, they cannot be toggled on/off.
|
|
14
|
-
*
|
|
15
|
-
* Pure Schmancy implementation with Tailwind CSS and RxJS state management
|
|
16
|
-
*/
|
|
17
|
-
@customElement('schmancy-suggestion-chip')
|
|
18
|
-
export class SchmancySuggestionChip extends SchmancyElement {
|
|
19
|
-
static styles = [css`
|
|
20
|
-
:host {
|
|
21
|
-
display: inline-block;
|
|
22
|
-
outline: none;
|
|
23
|
-
width: fit-content;
|
|
24
|
-
min-width: fit-content;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
:host([disabled]) {
|
|
28
|
-
pointer-events: none;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
.ripple {
|
|
32
|
-
position: absolute;
|
|
33
|
-
border-radius: 50%;
|
|
34
|
-
transform: scale(0);
|
|
35
|
-
animation: ripple 600ms linear;
|
|
36
|
-
background-color: rgba(0, 0, 0, 0.08);
|
|
37
|
-
pointer-events: none;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
@keyframes ripple {
|
|
41
|
-
to {
|
|
42
|
-
transform: scale(4);
|
|
43
|
-
opacity: 0;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
/* State layer for M3 hover/focus/pressed states */
|
|
48
|
-
.state-layer {
|
|
49
|
-
position: absolute;
|
|
50
|
-
inset: 0;
|
|
51
|
-
border-radius: inherit;
|
|
52
|
-
pointer-events: none;
|
|
53
|
-
background-color: currentColor;
|
|
54
|
-
opacity: 0;
|
|
55
|
-
transition: opacity 200ms ease;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
:host(:not([disabled])) button:hover .state-layer {
|
|
59
|
-
opacity: 0.08;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
:host(:not([disabled])) button:focus-visible .state-layer {
|
|
63
|
-
opacity: 0.1;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
:host(:not([disabled])) button:active .state-layer {
|
|
67
|
-
opacity: 0.1;
|
|
68
|
-
}
|
|
69
|
-
`];
|
|
70
|
-
/** Value identifier for the chip */
|
|
71
|
-
@property({ reflect: true }) value = ''
|
|
72
|
-
|
|
73
|
-
/** Optional icon name (Material Symbols) */
|
|
74
|
-
@property({ reflect: true }) icon = ''
|
|
75
|
-
|
|
76
|
-
/** Optional href for navigation */
|
|
77
|
-
@property({ reflect: true }) href = ''
|
|
78
|
-
|
|
79
|
-
/** Target for navigation (e.g., '_blank') */
|
|
80
|
-
@property({ reflect: true }) target = ''
|
|
81
|
-
|
|
82
|
-
/** Disable the chip */
|
|
83
|
-
@property({ type: Boolean, reflect: true }) disabled = false
|
|
84
|
-
|
|
85
|
-
/** Elevated style variant - flat by default per M3 spec */
|
|
86
|
-
@property({ type: Boolean, reflect: true }) elevated = false
|
|
87
|
-
|
|
88
|
-
// RxJS state streams
|
|
89
|
-
private hover$ = new BehaviorSubject<boolean>(false)
|
|
90
|
-
private pressed$ = new BehaviorSubject<boolean>(false)
|
|
91
|
-
private focused$ = new BehaviorSubject<boolean>(false)
|
|
92
|
-
|
|
93
|
-
// UI state - only ripples needed for rendering
|
|
94
|
-
@state() private ripples: Array<{ x: number; y: number; id: number }> = []
|
|
95
|
-
|
|
96
|
-
protected static shadowRootOptions = { ...LitElement.shadowRootOptions, delegatesFocus: true }
|
|
97
|
-
|
|
98
|
-
private nextRippleId = 0
|
|
99
|
-
|
|
100
|
-
connectedCallback() {
|
|
101
|
-
super.connectedCallback()
|
|
102
|
-
|
|
103
|
-
// Stream management for future extensions
|
|
104
|
-
// Currently, states are handled directly in event handlers
|
|
105
|
-
// This pipeline can be extended for more complex state interactions
|
|
106
|
-
combineLatest([
|
|
107
|
-
this.hover$,
|
|
108
|
-
this.pressed$,
|
|
109
|
-
this.focused$
|
|
110
|
-
]).pipe(
|
|
111
|
-
// States are managed through event handlers directly
|
|
112
|
-
// This pipeline is kept for potential future state combinations
|
|
113
|
-
takeUntil(this.disconnecting)
|
|
114
|
-
).subscribe()
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
private handleClick = (e: MouseEvent) => {
|
|
118
|
-
if (this.disabled) return
|
|
119
|
-
|
|
120
|
-
// Add ripple effect
|
|
121
|
-
const button = this.shadowRoot?.querySelector('button')
|
|
122
|
-
if (button) {
|
|
123
|
-
const rect = button.getBoundingClientRect()
|
|
124
|
-
const x = e.clientX - rect.left
|
|
125
|
-
const y = e.clientY - rect.top
|
|
126
|
-
const id = this.nextRippleId++
|
|
127
|
-
|
|
128
|
-
this.ripples = [...this.ripples, { x, y, id }]
|
|
129
|
-
|
|
130
|
-
// Remove ripple after animation
|
|
131
|
-
setTimeout(() => {
|
|
132
|
-
this.ripples = this.ripples.filter(r => r.id !== id)
|
|
133
|
-
}, 600)
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Navigate if href is provided
|
|
137
|
-
if (this.href) {
|
|
138
|
-
if (this.target === '_blank') {
|
|
139
|
-
window.open(this.href, '_blank')
|
|
140
|
-
} else {
|
|
141
|
-
window.location.href = this.href
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Dispatch action event
|
|
146
|
-
this.dispatchEvent(new CustomEvent('action', {
|
|
147
|
-
detail: { value: this.value },
|
|
148
|
-
bubbles: true,
|
|
149
|
-
composed: true
|
|
150
|
-
}))
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
private handleKeyDown = (e: KeyboardEvent) => {
|
|
154
|
-
if (this.disabled) return
|
|
155
|
-
|
|
156
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
157
|
-
e.preventDefault()
|
|
158
|
-
this.pressed$.next(true)
|
|
159
|
-
|
|
160
|
-
// Simulate click
|
|
161
|
-
const clickEvent = new MouseEvent('click', {
|
|
162
|
-
bubbles: true,
|
|
163
|
-
cancelable: true,
|
|
164
|
-
clientX: 0,
|
|
165
|
-
clientY: 0
|
|
166
|
-
})
|
|
167
|
-
this.handleClick(clickEvent)
|
|
168
|
-
|
|
169
|
-
setTimeout(() => this.pressed$.next(false), 100)
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private handleFocus = () => {
|
|
174
|
-
this.focused$.next(true)
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
private handleBlur = () => {
|
|
178
|
-
this.focused$.next(false)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
protected render(): unknown {
|
|
182
|
-
const hasIcon = !!this.icon;
|
|
183
|
-
|
|
184
|
-
const classes = {
|
|
185
|
-
'relative': true,
|
|
186
|
-
'inline-flex': true,
|
|
187
|
-
'items-center': true,
|
|
188
|
-
'gap-2': true,
|
|
189
|
-
'h-8': true, // M3: 32px height
|
|
190
|
-
'min-h-[32px]': true,
|
|
191
|
-
'rounded-full': true,
|
|
192
|
-
'cursor-pointer': !this.disabled,
|
|
193
|
-
'transition-all': true,
|
|
194
|
-
'duration-200': true,
|
|
195
|
-
'select-none': true,
|
|
196
|
-
'overflow-hidden': true,
|
|
197
|
-
|
|
198
|
-
// M3 Padding: 8px with icon, 16px without (leading), 16px trailing
|
|
199
|
-
'pl-2': hasIcon, // 8px with icon
|
|
200
|
-
'pl-4': !hasIcon, // 16px without icon
|
|
201
|
-
'pr-4': true, // 16px trailing
|
|
202
|
-
|
|
203
|
-
// M3 Colors for suggestion chips
|
|
204
|
-
'bg-surface-containerLow': true,
|
|
205
|
-
'text-surface-onVariant': true,
|
|
206
|
-
|
|
207
|
-
// Suggestion chips are flat by default (no elevation per M3)
|
|
208
|
-
|
|
209
|
-
// Focus state
|
|
210
|
-
'focus-visible:outline': !this.disabled,
|
|
211
|
-
'focus-visible:outline-2': !this.disabled,
|
|
212
|
-
'focus-visible:outline-primary': !this.disabled,
|
|
213
|
-
'focus-visible:outline-offset-2': !this.disabled,
|
|
214
|
-
|
|
215
|
-
// Disabled
|
|
216
|
-
'opacity-38': this.disabled, // M3 disabled opacity
|
|
217
|
-
'cursor-not-allowed': this.disabled
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
return html`
|
|
221
|
-
<button
|
|
222
|
-
type="button"
|
|
223
|
-
class=${classMap(classes)}
|
|
224
|
-
?disabled=${this.disabled}
|
|
225
|
-
@click=${this.handleClick}
|
|
226
|
-
@keydown=${this.handleKeyDown}
|
|
227
|
-
@mouseenter=${() => this.hover$.next(true)}
|
|
228
|
-
@mouseleave=${() => this.hover$.next(false)}
|
|
229
|
-
@mousedown=${() => this.pressed$.next(true)}
|
|
230
|
-
@mouseup=${() => this.pressed$.next(false)}
|
|
231
|
-
@focus=${this.handleFocus}
|
|
232
|
-
@blur=${this.handleBlur}
|
|
233
|
-
tabindex=${this.disabled ? '-1' : '0'}
|
|
234
|
-
role="button"
|
|
235
|
-
aria-disabled=${this.disabled}
|
|
236
|
-
aria-label=${this.value}
|
|
237
|
-
>
|
|
238
|
-
${this.icon ? html`
|
|
239
|
-
<schmancy-icon class="text-[18px] shrink-0">${this.icon}</schmancy-icon>
|
|
240
|
-
` : ''}
|
|
241
|
-
<span class="text-sm font-medium leading-5">
|
|
242
|
-
<slot></slot>
|
|
243
|
-
</span>
|
|
244
|
-
|
|
245
|
-
<!-- Ripple effects -->
|
|
246
|
-
${this.ripples.map(ripple => html`
|
|
247
|
-
<span
|
|
248
|
-
class="ripple"
|
|
249
|
-
style="left: ${ripple.x}px; top: ${ripple.y}px;"
|
|
250
|
-
></span>
|
|
251
|
-
`)}
|
|
252
|
-
|
|
253
|
-
<!-- State layer for M3 hover/focus/pressed states -->
|
|
254
|
-
<div class="state-layer"></div>
|
|
255
|
-
</button>
|
|
256
|
-
`
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
declare global {
|
|
261
|
-
interface HTMLElementTagNameMap {
|
|
262
|
-
'schmancy-suggestion-chip': SchmancySuggestionChip
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
export type SuggestionChipActionEvent = { value: string }
|
|
1
|
+
// Moved to src/form/fields/chips/ — this is a backward-compat re-export shim.
|
|
2
|
+
export * from '../form/fields/chips/suggestion-chip';
|
package/src/directives/fill.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AsyncDirective, directive } from 'lit/async-directive.js'
|
|
2
2
|
import { ElementPart, PartType } from 'lit/directive.js'
|
|
3
3
|
import { EMPTY, Subject, animationFrameScheduler, combineLatest, fromEvent, merge, timer } from 'rxjs'
|
|
4
|
-
import { auditTime, filter, startWith, switchMap, takeUntil, tap } from 'rxjs/operators'
|
|
4
|
+
import { auditTime, distinctUntilChanged, filter, map, startWith, switchMap, takeUntil, tap } from 'rxjs/operators'
|
|
5
5
|
import { theme } from '../theme/theme.service'
|
|
6
6
|
import { fromResizeObserver } from './layout'
|
|
7
7
|
|
|
@@ -50,6 +50,15 @@ class Fill extends AsyncDirective {
|
|
|
50
50
|
: EMPTY,
|
|
51
51
|
fromEvent(window, 'orientationchange'),
|
|
52
52
|
fromEvent(document, 'focusout', { passive: true }).pipe(switchMap(() => timer(100))),
|
|
53
|
+
// Observe `el` itself: this is the post-layout settle trigger
|
|
54
|
+
// (its initial callback fires once `rect.top/left` resolve) and
|
|
55
|
+
// the only DOM trigger for a top-level fill element whose
|
|
56
|
+
// `el.parentElement` is null. It is loop-safe ONLY because of
|
|
57
|
+
// the `distinctUntilChanged` gate below: write → RO fires →
|
|
58
|
+
// recompute → identical value → gate suppresses → no write →
|
|
59
|
+
// RO quiet (converges in ≤2 frames). The ~20s overlay hang was
|
|
60
|
+
// the *missing gate*, not the observation — without it every
|
|
61
|
+
// write re-fired the observer forever.
|
|
53
62
|
fromResizeObserver(el),
|
|
54
63
|
el.parentElement ? fromResizeObserver(el.parentElement) : EMPTY,
|
|
55
64
|
).pipe(auditTime(0, animationFrameScheduler), startWith(null)),
|
|
@@ -61,14 +70,28 @@ class Fill extends AsyncDirective {
|
|
|
61
70
|
const vv = window.visualViewport
|
|
62
71
|
return vv ? Math.abs(vv.scale - 1) <= 0.01 : true
|
|
63
72
|
}),
|
|
64
|
-
|
|
73
|
+
map(([, bottomOffset, isFullscreen]) => {
|
|
65
74
|
const vv = window.visualViewport
|
|
66
75
|
const rect = el.getBoundingClientRect()
|
|
76
|
+
return {
|
|
77
|
+
height: `${Math.max(0, (vv?.height ?? window.innerHeight) - rect.top)}px`,
|
|
78
|
+
width: `${Math.max(0, (vv?.width ?? window.innerWidth) - rect.left)}px`,
|
|
79
|
+
paddingBottom: `${isFullscreen ? 0 : bottomOffset}px`,
|
|
80
|
+
}
|
|
81
|
+
}),
|
|
82
|
+
// Idempotent gate: once geometry is stable the computed values
|
|
83
|
+
// stop changing, so no DOM write happens and no resize is
|
|
84
|
+
// emitted — the parent observer (and any ancestor's, e.g. the
|
|
85
|
+
// overlay's) goes quiet instead of ping-ponging.
|
|
86
|
+
distinctUntilChanged(
|
|
87
|
+
(a, b) => a.height === b.height && a.width === b.width && a.paddingBottom === b.paddingBottom,
|
|
88
|
+
),
|
|
89
|
+
tap(({ height, width, paddingBottom }) => {
|
|
67
90
|
const s = el.style
|
|
68
91
|
s.boxSizing = 'border-box'
|
|
69
|
-
s.height =
|
|
70
|
-
s.width =
|
|
71
|
-
s.paddingBottom =
|
|
92
|
+
s.height = height
|
|
93
|
+
s.width = width
|
|
94
|
+
s.paddingBottom = paddingBottom
|
|
72
95
|
s.minHeight = '0'
|
|
73
96
|
s.minWidth = '0'
|
|
74
97
|
s.overflow = 'hidden'
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
|
|
2
|
+
import './fab'
|
|
3
|
+
import '../icons/icon'
|
|
4
|
+
import { expectNoA11yViolations } from '../test-utils/a11y'
|
|
5
|
+
import type { SchmancyFab } from './fab'
|
|
6
|
+
|
|
7
|
+
const nextUpdate = () => new Promise(r => requestAnimationFrame(() => r(null)))
|
|
8
|
+
|
|
9
|
+
const base = (fab: SchmancyFab) =>
|
|
10
|
+
fab.shadowRoot!.querySelector('[part="base"]') as HTMLButtonElement
|
|
11
|
+
|
|
12
|
+
describe('schmancy-fab — M3 contract', () => {
|
|
13
|
+
let host: HTMLDivElement
|
|
14
|
+
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
host = document.createElement('div')
|
|
17
|
+
document.body.appendChild(host)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
afterEach(() => {
|
|
21
|
+
host.remove()
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('renders a non-disablable native button (M3: a FAB is never disabled)', async () => {
|
|
25
|
+
host.innerHTML = `<schmancy-fab aria-label="Compose"><schmancy-icon>edit</schmancy-icon></schmancy-fab>`
|
|
26
|
+
const fab = host.querySelector('schmancy-fab') as SchmancyFab
|
|
27
|
+
await nextUpdate()
|
|
28
|
+
const btn = base(fab)
|
|
29
|
+
expect(btn.tagName).toBe('BUTTON')
|
|
30
|
+
expect(btn.getAttribute('type')).toBe('button')
|
|
31
|
+
expect('disabled' in fab).toBe(false)
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
it('defaults to surface / medium: surface-containerHigh container, primary on-colour, 16dp shape', async () => {
|
|
35
|
+
host.innerHTML = `<schmancy-fab aria-label="Compose"><schmancy-icon>edit</schmancy-icon></schmancy-fab>`
|
|
36
|
+
const fab = host.querySelector('schmancy-fab') as SchmancyFab
|
|
37
|
+
await nextUpdate()
|
|
38
|
+
expect(fab.variant).toBe('surface')
|
|
39
|
+
expect(fab.size).toBe('medium')
|
|
40
|
+
expect(fab.extended).toBe(false)
|
|
41
|
+
const cls = base(fab).classList
|
|
42
|
+
expect(cls.contains('bg-surface-containerHigh')).toBe(true)
|
|
43
|
+
expect(cls.contains('text-primary-default')).toBe(true)
|
|
44
|
+
expect(cls.contains('size-14')).toBe(true)
|
|
45
|
+
expect(getComputedStyle(fab).borderTopLeftRadius).toBe('16px')
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
it.each([
|
|
49
|
+
['primary', 'bg-primary-container', 'text-primary-onContainer'],
|
|
50
|
+
['secondary', 'bg-secondary-container', 'text-secondary-onContainer'],
|
|
51
|
+
['tertiary', 'bg-tertiary-container', 'text-tertiary-onContainer'],
|
|
52
|
+
] as const)('maps the %s variant to its M3 container + on-container colour pair', async (variant, bg, fg) => {
|
|
53
|
+
host.innerHTML = `<schmancy-fab variant="${variant}" aria-label="x"><schmancy-icon>add</schmancy-icon></schmancy-fab>`
|
|
54
|
+
const fab = host.querySelector('schmancy-fab') as SchmancyFab
|
|
55
|
+
await nextUpdate()
|
|
56
|
+
const cls = base(fab).classList
|
|
57
|
+
expect(cls.contains(bg)).toBe(true)
|
|
58
|
+
expect(cls.contains(fg)).toBe(true)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
it('applies the M3 size geometry: small 12dp/40, large 28dp/36 icon', async () => {
|
|
62
|
+
host.innerHTML = `<schmancy-fab size="small" aria-label="x"><schmancy-icon>add</schmancy-icon></schmancy-fab>`
|
|
63
|
+
let fab = host.querySelector('schmancy-fab') as SchmancyFab
|
|
64
|
+
await nextUpdate()
|
|
65
|
+
expect(base(fab).classList.contains('size-10')).toBe(true)
|
|
66
|
+
expect(getComputedStyle(fab).borderTopLeftRadius).toBe('12px')
|
|
67
|
+
|
|
68
|
+
host.innerHTML = `<schmancy-fab size="large" aria-label="x"><schmancy-icon>add</schmancy-icon></schmancy-fab>`
|
|
69
|
+
fab = host.querySelector('schmancy-fab') as SchmancyFab
|
|
70
|
+
await nextUpdate()
|
|
71
|
+
expect(base(fab).classList.contains('size-24')).toBe(true)
|
|
72
|
+
expect(getComputedStyle(fab).borderTopLeftRadius).toBe('28px')
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
it('derives the extended form from a non-empty label and renders the label', async () => {
|
|
76
|
+
host.innerHTML = `<schmancy-fab label="Compose" variant="primary"><schmancy-icon>edit</schmancy-icon></schmancy-fab>`
|
|
77
|
+
const fab = host.querySelector('schmancy-fab') as SchmancyFab
|
|
78
|
+
await nextUpdate()
|
|
79
|
+
expect(fab.extended).toBe(true)
|
|
80
|
+
expect(fab.hasAttribute('extended')).toBe(true)
|
|
81
|
+
const btn = base(fab)
|
|
82
|
+
expect(btn.classList.contains('size-14')).toBe(false)
|
|
83
|
+
expect(btn.classList.contains('ps-4')).toBe(true)
|
|
84
|
+
expect(btn.classList.contains('pe-5')).toBe(true)
|
|
85
|
+
expect(btn.textContent).toContain('Compose')
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
it('reflects lowered and hides the icon slot from AT when a name is present', async () => {
|
|
89
|
+
host.innerHTML = `<schmancy-fab lowered label="New"><schmancy-icon>edit</schmancy-icon></schmancy-fab>`
|
|
90
|
+
const fab = host.querySelector('schmancy-fab') as SchmancyFab
|
|
91
|
+
await nextUpdate()
|
|
92
|
+
expect(fab.hasAttribute('lowered')).toBe(true)
|
|
93
|
+
expect(fab.shadowRoot!.querySelector('slot')!.getAttribute('aria-hidden')).toBe('true')
|
|
94
|
+
})
|
|
95
|
+
|
|
96
|
+
it('has no a11y violations as an icon-only FAB with an accessible name', async () => {
|
|
97
|
+
host.innerHTML = `<schmancy-fab aria-label="Compose message"><schmancy-icon>edit</schmancy-icon></schmancy-fab>`
|
|
98
|
+
await nextUpdate()
|
|
99
|
+
await expectNoA11yViolations(host)
|
|
100
|
+
})
|
|
101
|
+
})
|
package/src/fab/fab.ts
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { SchmancyElement } from '@mixins/index'
|
|
2
|
+
import { css, html, LitElement } from 'lit'
|
|
3
|
+
import { customElement, property, query } from 'lit/decorators.js'
|
|
4
|
+
import { ifDefined } from 'lit/directives/if-defined.js'
|
|
5
|
+
import { when } from 'lit/directives/when.js'
|
|
6
|
+
import { magnetic } from '../directives/magnetic'
|
|
7
|
+
|
|
8
|
+
export type FabVariant = 'surface' | 'primary' | 'secondary' | 'tertiary'
|
|
9
|
+
export type FabSize = 'small' | 'medium' | 'large'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Material 3 Floating Action Button.
|
|
13
|
+
*
|
|
14
|
+
* Mirrors the `md-fab` reference implementation
|
|
15
|
+
* (github.com/material-components/material-web) and the M3 spec
|
|
16
|
+
* (m3.material.io/components/floating-action-button): four colour
|
|
17
|
+
* variants, three container sizes, an extended form (set `label`),
|
|
18
|
+
* and a `lowered` elevation register. Per M3 guidance a FAB is never
|
|
19
|
+
* disabled, so there is no `disabled` property.
|
|
20
|
+
*
|
|
21
|
+
* Sizing, shape, icon size and elevation are M3 design tokens expressed
|
|
22
|
+
* as `:host` rules (the same token-driven model as `md-fab`'s SCSS);
|
|
23
|
+
* colour roles and the state layer are schmancy theme utilities. The
|
|
24
|
+
* host shrink-wraps the inner button and clips its rounded shape.
|
|
25
|
+
*
|
|
26
|
+
* @element schmancy-fab
|
|
27
|
+
* @slot - The icon (typically `<schmancy-icon>`).
|
|
28
|
+
* @csspart base - The underlying native `<button>`.
|
|
29
|
+
*/
|
|
30
|
+
@customElement('schmancy-fab')
|
|
31
|
+
export class SchmancyFab extends SchmancyElement {
|
|
32
|
+
static styles = [
|
|
33
|
+
css`
|
|
34
|
+
:host {
|
|
35
|
+
/* M3 FAB (medium) — 16dp shape, 24dp icon, resting level 3 */
|
|
36
|
+
display: inline-flex;
|
|
37
|
+
position: relative;
|
|
38
|
+
touch-action: manipulation;
|
|
39
|
+
overflow: hidden;
|
|
40
|
+
border-radius: 16px;
|
|
41
|
+
--_icon: 24px;
|
|
42
|
+
--_elevation: var(--schmancy-sys-elevation-3);
|
|
43
|
+
--_elevation-hover: var(--schmancy-sys-elevation-4);
|
|
44
|
+
box-shadow: var(--_elevation);
|
|
45
|
+
transition:
|
|
46
|
+
box-shadow 280ms cubic-bezier(0.34, 1.56, 0.64, 1),
|
|
47
|
+
transform 200ms cubic-bezier(0.34, 1.56, 0.64, 1);
|
|
48
|
+
}
|
|
49
|
+
/* M3 small FAB — 12dp shape */
|
|
50
|
+
:host([size='small']) {
|
|
51
|
+
border-radius: 12px;
|
|
52
|
+
}
|
|
53
|
+
/* M3 large FAB — 28dp shape, 36dp icon */
|
|
54
|
+
:host([size='large']) {
|
|
55
|
+
border-radius: 28px;
|
|
56
|
+
--_icon: 36px;
|
|
57
|
+
}
|
|
58
|
+
/* Extended FAB always uses the 16dp shape / 24dp icon */
|
|
59
|
+
:host([extended]) {
|
|
60
|
+
border-radius: 16px;
|
|
61
|
+
--_icon: 24px;
|
|
62
|
+
}
|
|
63
|
+
/* M3 lowered register — resting level 1, hover level 2 */
|
|
64
|
+
:host([lowered]) {
|
|
65
|
+
--_elevation: var(--schmancy-sys-elevation-1);
|
|
66
|
+
--_elevation-hover: var(--schmancy-sys-elevation-2);
|
|
67
|
+
}
|
|
68
|
+
:host(:hover) {
|
|
69
|
+
box-shadow: var(--_elevation-hover);
|
|
70
|
+
}
|
|
71
|
+
:host(:active) {
|
|
72
|
+
/* M3 pressed elevation == resting; schmancy spring press */
|
|
73
|
+
box-shadow: var(--_elevation);
|
|
74
|
+
transform: scale(0.96);
|
|
75
|
+
transition-duration: 100ms;
|
|
76
|
+
}
|
|
77
|
+
::slotted(*) {
|
|
78
|
+
font-size: var(--_icon);
|
|
79
|
+
width: var(--_icon);
|
|
80
|
+
height: var(--_icon);
|
|
81
|
+
}
|
|
82
|
+
:host([extended]) ::slotted(*) {
|
|
83
|
+
margin-inline-end: 12px;
|
|
84
|
+
}
|
|
85
|
+
@media (prefers-reduced-motion: reduce) {
|
|
86
|
+
:host {
|
|
87
|
+
transition: none;
|
|
88
|
+
}
|
|
89
|
+
:host(:active) {
|
|
90
|
+
transform: none;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
:host *,
|
|
94
|
+
* {
|
|
95
|
+
touch-action: manipulation;
|
|
96
|
+
}
|
|
97
|
+
`,
|
|
98
|
+
]
|
|
99
|
+
|
|
100
|
+
protected static shadowRootOptions = {
|
|
101
|
+
...LitElement.shadowRootOptions,
|
|
102
|
+
mode: 'open',
|
|
103
|
+
delegatesFocus: true,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@query('[part="base"]', true)
|
|
107
|
+
private nativeElement!: HTMLElement
|
|
108
|
+
|
|
109
|
+
private ariaLabelValue!: string
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Colour variant. M3 maps each to a container + on-container role.
|
|
113
|
+
* @attr
|
|
114
|
+
* @default 'surface'
|
|
115
|
+
*/
|
|
116
|
+
@property({ reflect: true, type: String })
|
|
117
|
+
public variant: FabVariant = 'surface'
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Container size. Ignored while extended (extended is always 56dp tall).
|
|
121
|
+
* @attr
|
|
122
|
+
* @default 'medium'
|
|
123
|
+
*/
|
|
124
|
+
@property({ reflect: true, type: String })
|
|
125
|
+
public size: FabSize = 'medium'
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Extended-FAB label. A non-empty value switches the FAB to its
|
|
129
|
+
* extended form (icon + text), exactly as `md-fab` derives extended
|
|
130
|
+
* from a truthy label.
|
|
131
|
+
* @attr
|
|
132
|
+
*/
|
|
133
|
+
@property({ type: String })
|
|
134
|
+
public label = ''
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Reflected mirror of "label is non-empty" so `:host([extended])`
|
|
138
|
+
* can drive the extended geometry. Synced from `label`; read it,
|
|
139
|
+
* don't set it.
|
|
140
|
+
* @attr
|
|
141
|
+
*/
|
|
142
|
+
@property({ type: Boolean, reflect: true })
|
|
143
|
+
public extended = false
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Lowers the FAB's elevation register (M3 lowered FAB).
|
|
147
|
+
* @attr
|
|
148
|
+
* @default false
|
|
149
|
+
*/
|
|
150
|
+
@property({ type: Boolean, reflect: true })
|
|
151
|
+
public lowered = false
|
|
152
|
+
|
|
153
|
+
public override set ariaLabel(value: string) {
|
|
154
|
+
const oldVal = this.ariaLabelValue
|
|
155
|
+
this.ariaLabelValue = value
|
|
156
|
+
if (this.hasAttribute('aria-label')) {
|
|
157
|
+
this.removeAttribute('aria-label')
|
|
158
|
+
}
|
|
159
|
+
this.requestUpdate('ariaLabel', oldVal)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
@property({ attribute: 'aria-label' })
|
|
163
|
+
public override get ariaLabel() {
|
|
164
|
+
return this.ariaLabelValue
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Sets focus on the FAB. */
|
|
168
|
+
public override focus(options?: FocusOptions) {
|
|
169
|
+
this.nativeElement.focus(options)
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/** Removes focus from the FAB. */
|
|
173
|
+
public override blur() {
|
|
174
|
+
this.nativeElement.blur()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
protected willUpdate(changed: Map<string, unknown>) {
|
|
178
|
+
if (changed.has('label')) this.extended = this.label.length > 0
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
render() {
|
|
182
|
+
const classes = {
|
|
183
|
+
'relative z-0 flex items-center justify-center overflow-hidden border-0 cursor-pointer outline-hidden focus-visible:outline-solid focus-visible:outline-2 focus-visible:outline-offset-2 outline-secondary-default':
|
|
184
|
+
true,
|
|
185
|
+
// M3 container — fixed square per size, content-width when extended
|
|
186
|
+
'size-10': !this.extended && this.size === 'small',
|
|
187
|
+
'size-14': !this.extended && this.size === 'medium',
|
|
188
|
+
'size-24': !this.extended && this.size === 'large',
|
|
189
|
+
'h-14 ps-4 pe-5 gap-3 text-sm font-medium leading-5': this.extended,
|
|
190
|
+
// M3 container + on-container colour roles per variant
|
|
191
|
+
'bg-surface-containerHigh text-primary-default': this.variant === 'surface',
|
|
192
|
+
'bg-primary-container text-primary-onContainer': this.variant === 'primary',
|
|
193
|
+
'bg-secondary-container text-secondary-onContainer': this.variant === 'secondary',
|
|
194
|
+
'bg-tertiary-container text-tertiary-onContainer': this.variant === 'tertiary',
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const stateLayerClasses = {
|
|
198
|
+
'absolute inset-0 z-0 opacity-0 transition-opacity duration-150 hover:opacity-8 focus-visible:opacity-10 active:opacity-10':
|
|
199
|
+
true,
|
|
200
|
+
'bg-primary-default': this.variant === 'surface',
|
|
201
|
+
'bg-primary-onContainer': this.variant === 'primary',
|
|
202
|
+
'bg-secondary-onContainer': this.variant === 'secondary',
|
|
203
|
+
'bg-tertiary-onContainer': this.variant === 'tertiary',
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
return html`
|
|
207
|
+
<button
|
|
208
|
+
${magnetic({ strength: 3, radius: 60 })}
|
|
209
|
+
part="base"
|
|
210
|
+
type="button"
|
|
211
|
+
aria-label=${ifDefined(this.ariaLabel)}
|
|
212
|
+
class="${this.classMap(classes)}"
|
|
213
|
+
>
|
|
214
|
+
<div class="${this.classMap(stateLayerClasses)}"></div>
|
|
215
|
+
<slot aria-hidden=${ifDefined(this.ariaLabel || this.label ? 'true' : undefined)}></slot>
|
|
216
|
+
${when(this.extended, () => html`<span class="relative z-0">${this.label}</span>`)}
|
|
217
|
+
</button>
|
|
218
|
+
`
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
declare global {
|
|
223
|
+
interface HTMLElementTagNameMap {
|
|
224
|
+
'schmancy-fab': SchmancyFab
|
|
225
|
+
}
|
|
226
|
+
}
|
package/src/fab/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './fab'
|