From 01d4355c2b12fd74f9ef8528517193af18e889ad Mon Sep 17 00:00:00 2001 From: Abdelrhman Said Date: Tue, 27 Oct 2026 22:49:01 +0300 Subject: [PATCH 01/12] test: isolate public and compiled view paths per parallel test process Parallel workers shared the Testbench public directory and the compiled views directory, so concurrent mkdir calls and tests that build, publish, or upload into public/ raced each other. --- tests/TestCase.php | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/tests/TestCase.php b/tests/TestCase.php index 5672e8c..d1a0562 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -19,8 +19,30 @@ protected function setUp(): void { parent::setUp(); - File::ensureDirectoryExists($this->app['config']->get('view.compiled')); - File::ensureDirectoryExists(dist_path()); + // Parallel workers create the same directories at once, so tolerate one that already exists. + File::makeDirectory($this->app['config']->get('view.compiled'), 0755, true, true); + File::makeDirectory(dist_path(), 0755, true, true); + } + + /** + * Resolve the application with a public directory private to the current test process. + * + * Tests build, publish, and upload into the public directory, and the package + * registers its publish paths before the environment is defined. + */ + protected function resolveApplication() + { + return tap(parent::resolveApplication(), fn ($app) => $app->usePublicPath(static::processPath('public'))); + } + + /** + * Get a scratch directory private to the current test process. + */ + protected static function processPath(string $path): string + { + $token = $_SERVER['TEST_TOKEN'] ?? getenv('TEST_TOKEN') ?: 'serial'; + + return sys_get_temp_dir() . "/redot-core-tests/{$token}/{$path}"; } /** @@ -57,7 +79,7 @@ protected function defineEnvironment($app): void $app['config']->set('permission.testing', true); $app['config']->set('queue.default', 'sync'); $app['config']->set('session.driver', 'array'); - $app['config']->set('view.compiled', sys_get_temp_dir() . '/redot-core-tests/views'); + $app['config']->set('view.compiled', static::processPath('views')); $app['config']->set('auth.guards.admins', ['driver' => 'session', 'provider' => 'admins']); $app['config']->set('auth.providers.admins', ['driver' => 'eloquent', 'model' => User::class]); From 01a43af0547c857d59616eb893995d45f935490b Mon Sep 17 00:00:00 2001 From: Abdelrhman Said Date: Tue, 27 Oct 2026 22:52:22 +0300 Subject: [PATCH 02/12] feat: ship the generic dashboard components, runtime and assets from core - Register the dashboard's generic Blade components from the package. They keep their names, and an application view under resources/components or a class under App\View\Components with the same name overrides them. - Ship functions.js, themer.js, the redot plugins, redot.css, the shared runtime, and the third-party libraries, published to public/vendor/redot by the new redot:publish command, which also publishes the datatables assets and replaces datatables:link. - Add and so layouts load the runtime without listing every file. - Build the package initializers into init.js, letting same-named application inits override them, and track package files outside the application in the dependency lock. - Extract language tokens from the package views and scripts. --- docs/content/commands/overview.md | 11 +- docs/content/components/overview.md | 10 + docs/content/frontend/asset-system.md | 32 +- docs/content/getting-started/installation.md | 2 +- docs/content/packages/datatables/frontend.md | 19 +- src/Datatables/config/datatables.php | 4 +- .../src/Commands/DatatablesLinkCommand.php | 77 -- .../src/DatatablesServiceProvider.php | 6 +- src/Foundation/public/css/redot.css | 524 ++++++++ src/Foundation/public/js/functions.js | 1070 +++++++++++++++++ src/Foundation/public/js/runtime.js | 137 +++ src/Foundation/public/js/themer.js | 42 + .../libraries/apexcharts/apexcharts.min.js | 5 + .../public/libraries/bootbox/bootbox.min.js | 7 + .../public/libraries/coloris/coloris.min.css | 1 + .../public/libraries/coloris/coloris.min.js | 1 + .../public/libraries/glare/glare.min.css | 1 + .../public/libraries/glare/glare.min.js | 17 + .../public/libraries/hugerte/hugerte.min.js | 719 +++++++++++ .../hugerte/icons/default/icons.min.js | 1 + .../public/libraries/hugerte/langs/ar.js | 407 +++++++ .../libraries/hugerte/models/dom/model.min.js | 7 + .../hugerte/plugins/accordion/plugin.min.js | 7 + .../hugerte/plugins/advlist/plugin.min.js | 7 + .../hugerte/plugins/anchor/plugin.min.js | 7 + .../hugerte/plugins/autolink/plugin.min.js | 7 + .../hugerte/plugins/autoresize/plugin.min.js | 7 + .../hugerte/plugins/autosave/plugin.min.js | 7 + .../hugerte/plugins/charmap/plugin.min.js | 7 + .../hugerte/plugins/code/plugin.min.js | 7 + .../hugerte/plugins/codesample/plugin.min.js | 14 + .../plugins/directionality/plugin.min.js | 7 + .../plugins/emoticons/js/emojiimages.min.js | 7 + .../plugins/emoticons/js/emojis.min.js | 6 + .../hugerte/plugins/emoticons/plugin.min.js | 7 + .../hugerte/plugins/fullscreen/plugin.min.js | 7 + .../hugerte/plugins/help/js/i18n/keynav/ar.js | 90 ++ .../hugerte/plugins/help/js/i18n/keynav/en.js | 90 ++ .../hugerte/plugins/help/plugin.min.js | 7 + .../hugerte/plugins/image/plugin.min.js | 7 + .../hugerte/plugins/importcss/plugin.min.js | 7 + .../plugins/insertdatetime/plugin.min.js | 7 + .../hugerte/plugins/link/plugin.min.js | 7 + .../hugerte/plugins/lists/plugin.min.js | 7 + .../hugerte/plugins/media/plugin.min.js | 7 + .../hugerte/plugins/nonbreaking/plugin.min.js | 7 + .../hugerte/plugins/pagebreak/plugin.min.js | 7 + .../hugerte/plugins/preview/plugin.min.js | 7 + .../hugerte/plugins/quickbars/plugin.min.js | 7 + .../hugerte/plugins/save/plugin.min.js | 7 + .../plugins/searchreplace/plugin.min.js | 7 + .../hugerte/plugins/table/plugin.min.js | 7 + .../hugerte/plugins/template/plugin.min.js | 7 + .../plugins/visualblocks/plugin.min.js | 7 + .../hugerte/plugins/visualchars/plugin.min.js | 7 + .../hugerte/plugins/wordcount/plugin.min.js | 7 + .../skins/content/dark/content.min.css | 1 + .../skins/content/default/content.min.css | 1 + .../skins/ui/oxide-dark/content.min.css | 1 + .../hugerte/skins/ui/oxide-dark/skin.min.css | 1 + .../hugerte/skins/ui/oxide/content.min.css | 1 + .../hugerte/skins/ui/oxide/skin.min.css | 1 + .../hugerte/themes/silver/theme.min.js | 719 +++++++++++ .../public/libraries/jquery/jquery.min.js | 2 + .../public/libraries/lodash/lodash.min.js | 136 +++ .../overlayscrollbars.min.css | 9 + .../overlayscrollbars.min.js | 10 + .../public/libraries/popper/popper.min.js | 6 + .../query-builder.compatibility.js | 9 + .../query-builder/query-builder.min.css | 6 + .../query-builder/query-builder.min.js | 29 + .../public/libraries/sortable/sortable.min.js | 2 + .../fonts/tabler-icons-filled.ttf | Bin 0 -> 234168 bytes .../fonts/tabler-icons-filled.woff | Bin 0 -> 96688 bytes .../fonts/tabler-icons-filled.woff2 | Bin 0 -> 72904 bytes .../tabler-icons/fonts/tabler-icons.ttf | Bin 0 -> 2884792 bytes .../tabler-icons/fonts/tabler-icons.woff | Bin 0 -> 793708 bytes .../tabler-icons/fonts/tabler-icons.woff2 | Bin 0 -> 455116 bytes .../libraries/tabler-icons/tabler-icons.json | 1 + .../tabler-icons/tabler-icons.min.css | 5 + .../libraries/tabler/css/tabler-flags.min.css | 1 + .../tabler/css/tabler-marketing.ltr.min.css | 1 + .../tabler/css/tabler-marketing.rtl.min.css | 1 + .../tabler/css/tabler-socials.min.css | 1 + .../tabler/css/tabler-vendors.min.css | 1 + .../libraries/tabler/css/tabler.ltr.min.css | 1 + .../libraries/tabler/css/tabler.rtl.min.css | 1 + .../public/libraries/tabler/img/flags/ad.svg | 1 + .../public/libraries/tabler/img/flags/ae.svg | 1 + .../public/libraries/tabler/img/flags/af.svg | 1 + .../libraries/tabler/img/flags/afrun.svg | 1 + .../public/libraries/tabler/img/flags/ag.svg | 1 + .../public/libraries/tabler/img/flags/ai.svg | 1 + .../public/libraries/tabler/img/flags/al.svg | 1 + .../public/libraries/tabler/img/flags/am.svg | 1 + .../public/libraries/tabler/img/flags/ao.svg | 1 + .../public/libraries/tabler/img/flags/aq.svg | 1 + .../public/libraries/tabler/img/flags/ar.svg | 1 + .../public/libraries/tabler/img/flags/as.svg | 1 + .../public/libraries/tabler/img/flags/at.svg | 1 + .../public/libraries/tabler/img/flags/au.svg | 1 + .../public/libraries/tabler/img/flags/aw.svg | 1 + .../public/libraries/tabler/img/flags/ax.svg | 1 + .../public/libraries/tabler/img/flags/az.svg | 1 + .../public/libraries/tabler/img/flags/ba.svg | 1 + .../public/libraries/tabler/img/flags/bb.svg | 1 + .../public/libraries/tabler/img/flags/bd.svg | 1 + .../public/libraries/tabler/img/flags/be.svg | 1 + .../public/libraries/tabler/img/flags/bf.svg | 1 + .../public/libraries/tabler/img/flags/bg.svg | 1 + .../public/libraries/tabler/img/flags/bh.svg | 1 + .../public/libraries/tabler/img/flags/bi.svg | 1 + .../public/libraries/tabler/img/flags/bj.svg | 1 + .../public/libraries/tabler/img/flags/bl.svg | 1 + .../public/libraries/tabler/img/flags/bm.svg | 1 + .../public/libraries/tabler/img/flags/bn.svg | 1 + .../public/libraries/tabler/img/flags/bo.svg | 1 + .../libraries/tabler/img/flags/bq-bo.svg | 1 + .../libraries/tabler/img/flags/bq-sa.svg | 1 + .../libraries/tabler/img/flags/bq-se.svg | 1 + .../public/libraries/tabler/img/flags/br.svg | 1 + .../public/libraries/tabler/img/flags/bs.svg | 1 + .../public/libraries/tabler/img/flags/bt.svg | 1 + .../public/libraries/tabler/img/flags/bv.svg | 1 + .../public/libraries/tabler/img/flags/bw.svg | 1 + .../public/libraries/tabler/img/flags/by.svg | 1 + .../public/libraries/tabler/img/flags/bz.svg | 1 + .../public/libraries/tabler/img/flags/ca.svg | 1 + .../public/libraries/tabler/img/flags/cc.svg | 1 + .../public/libraries/tabler/img/flags/cd.svg | 1 + .../public/libraries/tabler/img/flags/cf.svg | 1 + .../public/libraries/tabler/img/flags/cg.svg | 1 + .../public/libraries/tabler/img/flags/ch.svg | 1 + .../public/libraries/tabler/img/flags/ci.svg | 1 + .../public/libraries/tabler/img/flags/ck.svg | 1 + .../public/libraries/tabler/img/flags/cl.svg | 1 + .../public/libraries/tabler/img/flags/cm.svg | 1 + .../public/libraries/tabler/img/flags/cn.svg | 1 + .../public/libraries/tabler/img/flags/co.svg | 1 + .../public/libraries/tabler/img/flags/cr.svg | 1 + .../public/libraries/tabler/img/flags/cu.svg | 1 + .../public/libraries/tabler/img/flags/cv.svg | 1 + .../public/libraries/tabler/img/flags/cw.svg | 1 + .../public/libraries/tabler/img/flags/cx.svg | 1 + .../public/libraries/tabler/img/flags/cy.svg | 1 + .../public/libraries/tabler/img/flags/cz.svg | 1 + .../public/libraries/tabler/img/flags/de.svg | 1 + .../public/libraries/tabler/img/flags/dj.svg | 1 + .../public/libraries/tabler/img/flags/dk.svg | 1 + .../public/libraries/tabler/img/flags/dm.svg | 1 + .../public/libraries/tabler/img/flags/do.svg | 1 + .../public/libraries/tabler/img/flags/dz.svg | 1 + .../public/libraries/tabler/img/flags/ec.svg | 1 + .../public/libraries/tabler/img/flags/ee.svg | 1 + .../public/libraries/tabler/img/flags/eg.svg | 1 + .../public/libraries/tabler/img/flags/eh.svg | 1 + .../public/libraries/tabler/img/flags/er.svg | 1 + .../public/libraries/tabler/img/flags/es.svg | 1 + .../public/libraries/tabler/img/flags/et.svg | 1 + .../public/libraries/tabler/img/flags/eu.svg | 1 + .../public/libraries/tabler/img/flags/fi.svg | 1 + .../public/libraries/tabler/img/flags/fj.svg | 1 + .../public/libraries/tabler/img/flags/fk.svg | 1 + .../public/libraries/tabler/img/flags/fm.svg | 1 + .../public/libraries/tabler/img/flags/fo.svg | 1 + .../public/libraries/tabler/img/flags/fr.svg | 1 + .../public/libraries/tabler/img/flags/ga.svg | 1 + .../libraries/tabler/img/flags/gb-eng.svg | 1 + .../libraries/tabler/img/flags/gb-nir.svg | 1 + .../libraries/tabler/img/flags/gb-sct.svg | 1 + .../libraries/tabler/img/flags/gb-wls.svg | 1 + .../public/libraries/tabler/img/flags/gb.svg | 1 + .../public/libraries/tabler/img/flags/gd.svg | 1 + .../public/libraries/tabler/img/flags/ge.svg | 1 + .../public/libraries/tabler/img/flags/gf.svg | 1 + .../public/libraries/tabler/img/flags/gg.svg | 1 + .../public/libraries/tabler/img/flags/gh.svg | 1 + .../public/libraries/tabler/img/flags/gi.svg | 1 + .../public/libraries/tabler/img/flags/gl.svg | 1 + .../public/libraries/tabler/img/flags/gm.svg | 1 + .../public/libraries/tabler/img/flags/gn.svg | 1 + .../public/libraries/tabler/img/flags/gp.svg | 1 + .../public/libraries/tabler/img/flags/gq.svg | 1 + .../public/libraries/tabler/img/flags/gr.svg | 1 + .../public/libraries/tabler/img/flags/gs.svg | 1 + .../public/libraries/tabler/img/flags/gt.svg | 1 + .../public/libraries/tabler/img/flags/gu.svg | 1 + .../public/libraries/tabler/img/flags/gw.svg | 1 + .../public/libraries/tabler/img/flags/gy.svg | 1 + .../public/libraries/tabler/img/flags/hk.svg | 1 + .../public/libraries/tabler/img/flags/hm.svg | 1 + .../public/libraries/tabler/img/flags/hn.svg | 1 + .../public/libraries/tabler/img/flags/hr.svg | 1 + .../public/libraries/tabler/img/flags/ht.svg | 1 + .../public/libraries/tabler/img/flags/hu.svg | 1 + .../public/libraries/tabler/img/flags/id.svg | 1 + .../public/libraries/tabler/img/flags/ie.svg | 1 + .../public/libraries/tabler/img/flags/il.svg | 1 + .../public/libraries/tabler/img/flags/im.svg | 1 + .../public/libraries/tabler/img/flags/in.svg | 1 + .../public/libraries/tabler/img/flags/io.svg | 1 + .../public/libraries/tabler/img/flags/iq.svg | 1 + .../public/libraries/tabler/img/flags/ir.svg | 1 + .../public/libraries/tabler/img/flags/is.svg | 1 + .../public/libraries/tabler/img/flags/it.svg | 1 + .../public/libraries/tabler/img/flags/je.svg | 1 + .../public/libraries/tabler/img/flags/jm.svg | 1 + .../public/libraries/tabler/img/flags/jo.svg | 1 + .../public/libraries/tabler/img/flags/jp.svg | 1 + .../public/libraries/tabler/img/flags/ke.svg | 1 + .../public/libraries/tabler/img/flags/kg.svg | 1 + .../public/libraries/tabler/img/flags/kh.svg | 1 + .../public/libraries/tabler/img/flags/ki.svg | 1 + .../public/libraries/tabler/img/flags/km.svg | 1 + .../libraries/tabler/img/flags/kn-sk.svg | 1 + .../public/libraries/tabler/img/flags/kn.svg | 1 + .../public/libraries/tabler/img/flags/kp.svg | 1 + .../public/libraries/tabler/img/flags/kr.svg | 1 + .../public/libraries/tabler/img/flags/kw.svg | 1 + .../public/libraries/tabler/img/flags/ky.svg | 1 + .../public/libraries/tabler/img/flags/kz.svg | 1 + .../public/libraries/tabler/img/flags/la.svg | 1 + .../public/libraries/tabler/img/flags/lb.svg | 1 + .../public/libraries/tabler/img/flags/lc.svg | 1 + .../public/libraries/tabler/img/flags/li.svg | 1 + .../public/libraries/tabler/img/flags/lk.svg | 1 + .../public/libraries/tabler/img/flags/lr.svg | 1 + .../public/libraries/tabler/img/flags/ls.svg | 1 + .../public/libraries/tabler/img/flags/lt.svg | 1 + .../public/libraries/tabler/img/flags/lu.svg | 1 + .../public/libraries/tabler/img/flags/lv.svg | 1 + .../public/libraries/tabler/img/flags/ly.svg | 1 + .../public/libraries/tabler/img/flags/ma.svg | 1 + .../public/libraries/tabler/img/flags/mc.svg | 1 + .../public/libraries/tabler/img/flags/md.svg | 1 + .../public/libraries/tabler/img/flags/me.svg | 1 + .../public/libraries/tabler/img/flags/mf.svg | 1 + .../public/libraries/tabler/img/flags/mg.svg | 1 + .../public/libraries/tabler/img/flags/mh.svg | 1 + .../public/libraries/tabler/img/flags/mk.svg | 1 + .../public/libraries/tabler/img/flags/ml.svg | 1 + .../public/libraries/tabler/img/flags/mm.svg | 1 + .../public/libraries/tabler/img/flags/mn.svg | 1 + .../public/libraries/tabler/img/flags/mo.svg | 1 + .../public/libraries/tabler/img/flags/mp.svg | 1 + .../public/libraries/tabler/img/flags/mq.svg | 1 + .../public/libraries/tabler/img/flags/mr.svg | 1 + .../public/libraries/tabler/img/flags/ms.svg | 1 + .../public/libraries/tabler/img/flags/mt.svg | 1 + .../public/libraries/tabler/img/flags/mu.svg | 1 + .../public/libraries/tabler/img/flags/mv.svg | 1 + .../public/libraries/tabler/img/flags/mw.svg | 1 + .../public/libraries/tabler/img/flags/mx.svg | 1 + .../public/libraries/tabler/img/flags/my.svg | 1 + .../public/libraries/tabler/img/flags/mz.svg | 1 + .../public/libraries/tabler/img/flags/na.svg | 1 + .../public/libraries/tabler/img/flags/nc.svg | 1 + .../public/libraries/tabler/img/flags/ne.svg | 1 + .../public/libraries/tabler/img/flags/nf.svg | 1 + .../public/libraries/tabler/img/flags/ng.svg | 1 + .../public/libraries/tabler/img/flags/ni.svg | 1 + .../public/libraries/tabler/img/flags/nl.svg | 1 + .../public/libraries/tabler/img/flags/no.svg | 1 + .../public/libraries/tabler/img/flags/np.svg | 1 + .../public/libraries/tabler/img/flags/nr.svg | 1 + .../public/libraries/tabler/img/flags/nu.svg | 1 + .../public/libraries/tabler/img/flags/nz.svg | 1 + .../public/libraries/tabler/img/flags/om.svg | 1 + .../public/libraries/tabler/img/flags/pa.svg | 1 + .../public/libraries/tabler/img/flags/pe.svg | 1 + .../public/libraries/tabler/img/flags/pf.svg | 1 + .../public/libraries/tabler/img/flags/pg.svg | 1 + .../public/libraries/tabler/img/flags/ph.svg | 1 + .../public/libraries/tabler/img/flags/pk.svg | 1 + .../public/libraries/tabler/img/flags/pl.svg | 1 + .../public/libraries/tabler/img/flags/pm.svg | 1 + .../public/libraries/tabler/img/flags/pn.svg | 1 + .../public/libraries/tabler/img/flags/pr.svg | 1 + .../public/libraries/tabler/img/flags/ps.svg | 1 + .../public/libraries/tabler/img/flags/pt.svg | 1 + .../public/libraries/tabler/img/flags/pw.svg | 1 + .../public/libraries/tabler/img/flags/py.svg | 1 + .../public/libraries/tabler/img/flags/qa.svg | 1 + .../libraries/tabler/img/flags/rainbow.svg | 1 + .../public/libraries/tabler/img/flags/re.svg | 1 + .../public/libraries/tabler/img/flags/ro.svg | 1 + .../public/libraries/tabler/img/flags/rs.svg | 1 + .../public/libraries/tabler/img/flags/ru.svg | 1 + .../public/libraries/tabler/img/flags/rw.svg | 1 + .../public/libraries/tabler/img/flags/sa.svg | 1 + .../public/libraries/tabler/img/flags/sb.svg | 1 + .../public/libraries/tabler/img/flags/sc.svg | 1 + .../public/libraries/tabler/img/flags/sd.svg | 1 + .../public/libraries/tabler/img/flags/se.svg | 1 + .../public/libraries/tabler/img/flags/sg.svg | 1 + .../public/libraries/tabler/img/flags/sh.svg | 1 + .../public/libraries/tabler/img/flags/si.svg | 1 + .../public/libraries/tabler/img/flags/sj.svg | 1 + .../public/libraries/tabler/img/flags/sk.svg | 1 + .../public/libraries/tabler/img/flags/sl.svg | 1 + .../public/libraries/tabler/img/flags/sm.svg | 1 + .../public/libraries/tabler/img/flags/sn.svg | 1 + .../public/libraries/tabler/img/flags/so.svg | 1 + .../public/libraries/tabler/img/flags/sr.svg | 1 + .../public/libraries/tabler/img/flags/ss.svg | 1 + .../public/libraries/tabler/img/flags/st.svg | 1 + .../public/libraries/tabler/img/flags/sv.svg | 1 + .../public/libraries/tabler/img/flags/sx.svg | 1 + .../public/libraries/tabler/img/flags/sy.svg | 1 + .../public/libraries/tabler/img/flags/sz.svg | 1 + .../public/libraries/tabler/img/flags/tc.svg | 1 + .../public/libraries/tabler/img/flags/td.svg | 1 + .../public/libraries/tabler/img/flags/tf.svg | 1 + .../public/libraries/tabler/img/flags/tg.svg | 1 + .../public/libraries/tabler/img/flags/th.svg | 1 + .../public/libraries/tabler/img/flags/tj.svg | 1 + .../public/libraries/tabler/img/flags/tk.svg | 1 + .../public/libraries/tabler/img/flags/tl.svg | 1 + .../public/libraries/tabler/img/flags/tm.svg | 1 + .../public/libraries/tabler/img/flags/tn.svg | 1 + .../public/libraries/tabler/img/flags/to.svg | 1 + .../public/libraries/tabler/img/flags/tr.svg | 1 + .../public/libraries/tabler/img/flags/tt.svg | 1 + .../public/libraries/tabler/img/flags/tv.svg | 1 + .../public/libraries/tabler/img/flags/tw.svg | 1 + .../public/libraries/tabler/img/flags/tz.svg | 1 + .../public/libraries/tabler/img/flags/ua.svg | 1 + .../public/libraries/tabler/img/flags/ug.svg | 1 + .../public/libraries/tabler/img/flags/um.svg | 1 + .../libraries/tabler/img/flags/unasur.svg | 1 + .../public/libraries/tabler/img/flags/us.svg | 1 + .../public/libraries/tabler/img/flags/uy.svg | 1 + .../public/libraries/tabler/img/flags/uz.svg | 1 + .../public/libraries/tabler/img/flags/va.svg | 1 + .../public/libraries/tabler/img/flags/vc.svg | 1 + .../public/libraries/tabler/img/flags/ve.svg | 1 + .../public/libraries/tabler/img/flags/vg.svg | 1 + .../public/libraries/tabler/img/flags/vi.svg | 1 + .../public/libraries/tabler/img/flags/vn.svg | 1 + .../public/libraries/tabler/img/flags/vu.svg | 1 + .../public/libraries/tabler/img/flags/wf.svg | 1 + .../public/libraries/tabler/img/flags/ws.svg | 1 + .../public/libraries/tabler/img/flags/ye.svg | 1 + .../public/libraries/tabler/img/flags/yt.svg | 1 + .../public/libraries/tabler/img/flags/za.svg | 1 + .../public/libraries/tabler/img/flags/zm.svg | 1 + .../public/libraries/tabler/img/flags/zw.svg | 1 + .../tabler/img/social/apple-gray.svg | 3 + .../libraries/tabler/img/social/apple.svg | 3 + .../tabler/img/social/discord-gray.svg | 3 + .../libraries/tabler/img/social/discord.svg | 3 + .../tabler/img/social/dribbble-gray.svg | 3 + .../libraries/tabler/img/social/dribbble.svg | 4 + .../tabler/img/social/facebook-gray.svg | 3 + .../libraries/tabler/img/social/facebook.svg | 4 + .../tabler/img/social/figma-gray.svg | 3 + .../libraries/tabler/img/social/figma.svg | 7 + .../tabler/img/social/github-gray.svg | 10 + .../libraries/tabler/img/social/github.svg | 10 + .../tabler/img/social/google-gray.svg | 3 + .../libraries/tabler/img/social/google.svg | 6 + .../tabler/img/social/instagram-gray.svg | 5 + .../libraries/tabler/img/social/instagram.svg | 18 + .../tabler/img/social/linkedin-gray.svg | 3 + .../libraries/tabler/img/social/linkedin.svg | 3 + .../tabler/img/social/medium-gray.svg | 5 + .../libraries/tabler/img/social/medium.svg | 5 + .../libraries/tabler/img/social/meta-gray.svg | 5 + .../libraries/tabler/img/social/meta.svg | 17 + .../tabler/img/social/metamask-gray.svg | 12 + .../libraries/tabler/img/social/metamask.svg | 14 + .../tabler/img/social/pinterest-gray.svg | 3 + .../libraries/tabler/img/social/pinterest.svg | 4 + .../tabler/img/social/reddit-gray.svg | 6 + .../libraries/tabler/img/social/reddit.svg | 11 + .../tabler/img/social/signal-gray.svg | 10 + .../libraries/tabler/img/social/signal.svg | 10 + .../tabler/img/social/skype-gray.svg | 3 + .../libraries/tabler/img/social/skype.svg | 3 + .../tabler/img/social/snapchat-gray.svg | 10 + .../libraries/tabler/img/social/snapchat.svg | 11 + .../tabler/img/social/spotify-gray.svg | 3 + .../libraries/tabler/img/social/spotify.svg | 3 + .../tabler/img/social/telegram-gray.svg | 3 + .../libraries/tabler/img/social/telegram.svg | 10 + .../tabler/img/social/tiktok-gray.svg | 3 + .../libraries/tabler/img/social/tiktok.svg | 5 + .../tabler/img/social/tumblr-gray.svg | 3 + .../libraries/tabler/img/social/tumblr.svg | 3 + .../tabler/img/social/twitch-gray.svg | 5 + .../libraries/tabler/img/social/twitch.svg | 6 + .../libraries/tabler/img/social/vk-gray.svg | 3 + .../public/libraries/tabler/img/social/vk.svg | 4 + .../libraries/tabler/img/social/x-gray.svg | 3 + .../public/libraries/tabler/img/social/x.svg | 3 + .../tabler/img/social/youtube-gray.svg | 3 + .../libraries/tabler/img/social/youtube.svg | 11 + .../public/libraries/tabler/js/tabler.min.js | 13 + .../libraries/tabler/js/tabler.min.js.map | 1 + .../tempus-dominus/tempus-dominus.min.css | 1 + .../tempus-dominus/tempus-dominus.min.js | 6 + .../tom-select/tom-select.complete.min.js | 454 +++++++ .../libraries/tom-select/tom-select.min.css | 2 + .../public/plugins/redot-icon-picker.js | 336 ++++++ .../public/plugins/redot-repeater.js | 498 ++++++++ src/Foundation/public/plugins/redot-toasts.js | 158 +++ .../public/plugins/redot-uploader.js | 833 +++++++++++++ .../public/plugins/redot-validator-rules.js | 427 +++++++ .../public/plugins/redot-validator.js | 176 +++ .../public/plugins/redot-visibility.js | 131 ++ .../resources/components/alert.blade.php | 20 + .../resources/components/apex-chart.blade.php | 3 + .../components/assets/apexcharts.blade.php | 3 + .../assets/cloudflare-turnstile.blade.php | 7 + .../components/assets/coloris.blade.php | 7 + .../components/assets/hugerte.blade.php | 3 + .../components/assets/query-builder.blade.php | 11 + .../assets/redot-icon-picker.blade.php | 53 + .../assets/redot-repeater.blade.php | 3 + .../components/assets/redot-toasts.blade.php | 3 + .../assets/redot-uploader.blade.php | 3 + .../components/assets/tabler-flags.blade.php | 3 + .../assets/tabler-socials.blade.php | 3 + .../assets/tempus-dominus.blade.php | 11 + .../components/assets/tom-select.blade.php | 7 + .../components/attachments.blade.php | 43 + .../resources/components/avatar.blade.php | 4 + .../resources/components/captcha.blade.php | 7 + .../resources/components/checkboxes.blade.php | 15 + .../components/color-picker.blade.php | 5 + .../components/date-picker.blade.php | 12 + .../resources/components/empty.blade.php | 31 + .../resources/components/field.blade.php | 16 + .../resources/components/file-hint.blade.php | 5 + .../resources/components/flag.blade.php | 8 + .../resources/components/form-card.blade.php | 27 + .../resources/components/form.blade.php | 14 + .../resources/components/hint.blade.php | 3 + .../components/icon-picker.blade.php | 20 + .../resources/components/icon.blade.php | 7 + .../resources/components/input.blade.php | 42 + .../resources/components/label.blade.php | 10 + .../components/page-header.blade.php | 32 + .../resources/components/pagination.blade.php | 94 ++ .../components/query-builder.blade.php | 8 + .../components/radios-colored.blade.php | 15 + .../resources/components/radios.blade.php | 15 + .../resources/components/rating.blade.php | 13 + .../components/redot-scripts.blade.php | 45 + .../components/redot-styles.blade.php | 13 + .../components/repeater-card.blade.php | 21 + .../resources/components/repeater.blade.php | 50 + .../components/rich-editor.blade.php | 3 + .../components/select-remote.blade.php | 11 + .../resources/components/select.blade.php | 19 + .../components/social-icon.blade.php | 8 + .../resources/components/status.blade.php | 11 + .../resources/components/textarea.blade.php | 3 + .../resources/components/toasts.blade.php | 17 + .../resources/components/toggle.blade.php | 8 + .../translatable-switcher.blade.php | 30 + .../components/translatable.blade.php | 24 + .../resources/components/uploader.blade.php | 28 + src/Foundation/resources/inits/apex-chart.js | 45 + src/Foundation/resources/inits/coloris.js | 28 + src/Foundation/resources/inits/hugerte.js | 118 ++ src/Foundation/resources/inits/icon-picker.js | 21 + .../resources/inits/overlay-scrollbars.js | 104 ++ .../resources/inits/query-builder.js | 114 ++ src/Foundation/resources/inits/repeater.js | 22 + src/Foundation/resources/inits/sortable.js | 22 + .../resources/inits/tempus-dominus.js | 80 ++ src/Foundation/resources/inits/tomselect.js | 214 ++++ src/Foundation/resources/inits/turnstile.js | 28 + src/Foundation/resources/inits/uploader.js | 26 + .../src/Commands/BuildDependenciesCommand.php | 21 +- .../src/Commands/PublishAssetsCommand.php | 41 + .../Middleware/EnsureDependenciesBuilt.php | 3 +- .../src/Jobs/ExtractLanguageTokens.php | 2 + src/Foundation/src/RedotServiceProvider.php | 62 +- src/Foundation/src/View/Components/Alert.php | 54 + .../src/View/Components/ApexChart.php | 87 ++ .../src/View/Components/Attachments.php | 81 ++ src/Foundation/src/View/Components/Avatar.php | 45 + .../src/View/Components/Captcha.php | 43 + .../src/View/Components/Checkboxes.php | 56 + .../src/View/Components/ColorPicker.php | 20 + .../src/View/Components/Component.php | 19 + .../src/View/Components/DatePicker.php | 20 + .../src/View/Components/FileHint.php | 45 + src/Foundation/src/View/Components/Form.php | 63 + .../src/View/Components/FormCard.php | 70 ++ .../src/View/Components/FormField.php | 75 ++ .../src/View/Components/IconPicker.php | 20 + src/Foundation/src/View/Components/Input.php | 56 + .../src/View/Components/QueryBuilder.php | 56 + src/Foundation/src/View/Components/Radios.php | 43 + .../src/View/Components/RadiosColored.php | 37 + src/Foundation/src/View/Components/Rating.php | 39 + .../src/View/Components/Repeater.php | 36 + .../src/View/Components/RichEditor.php | 25 + src/Foundation/src/View/Components/Select.php | 49 + .../src/View/Components/SelectRemote.php | 128 ++ src/Foundation/src/View/Components/Status.php | 50 + .../src/View/Components/Textarea.php | 38 + src/Foundation/src/View/Components/Toasts.php | 41 + src/Foundation/src/View/Components/Toggle.php | 33 + .../src/View/Components/Translatable.php | 91 ++ .../src/View/Components/Uploader.php | 67 ++ .../Commands/BuildDependenciesCommandTest.php | 24 + .../Core/Components/TranslatableTest.php | 32 + tests/Feature/Core/ComponentsTest.php | 88 ++ .../EnsureDependenciesBuiltTest.php | 26 + tests/Feature/Core/ServiceProviderTest.php | 2 +- .../views/components/toasts.blade.php | 1 + .../Core/Jobs/ExtractLanguageTokensTest.php | 12 + 516 files changed, 11426 insertions(+), 121 deletions(-) delete mode 100644 src/Datatables/src/Commands/DatatablesLinkCommand.php create mode 100644 src/Foundation/public/css/redot.css create mode 100644 src/Foundation/public/js/functions.js create mode 100644 src/Foundation/public/js/runtime.js create mode 100644 src/Foundation/public/js/themer.js create mode 100644 src/Foundation/public/libraries/apexcharts/apexcharts.min.js create mode 100644 src/Foundation/public/libraries/bootbox/bootbox.min.js create mode 100644 src/Foundation/public/libraries/coloris/coloris.min.css create mode 100644 src/Foundation/public/libraries/coloris/coloris.min.js create mode 100644 src/Foundation/public/libraries/glare/glare.min.css create mode 100644 src/Foundation/public/libraries/glare/glare.min.js create mode 100644 src/Foundation/public/libraries/hugerte/hugerte.min.js create mode 100644 src/Foundation/public/libraries/hugerte/icons/default/icons.min.js create mode 100644 src/Foundation/public/libraries/hugerte/langs/ar.js create mode 100644 src/Foundation/public/libraries/hugerte/models/dom/model.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/accordion/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/advlist/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/anchor/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/autolink/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/autoresize/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/autosave/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/charmap/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/code/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/codesample/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/directionality/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/emoticons/js/emojiimages.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/emoticons/js/emojis.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/emoticons/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/fullscreen/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/help/js/i18n/keynav/ar.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/help/js/i18n/keynav/en.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/help/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/image/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/importcss/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/insertdatetime/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/link/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/lists/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/media/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/nonbreaking/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/pagebreak/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/preview/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/quickbars/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/save/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/searchreplace/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/table/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/template/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/visualblocks/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/visualchars/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/plugins/wordcount/plugin.min.js create mode 100644 src/Foundation/public/libraries/hugerte/skins/content/dark/content.min.css create mode 100644 src/Foundation/public/libraries/hugerte/skins/content/default/content.min.css create mode 100644 src/Foundation/public/libraries/hugerte/skins/ui/oxide-dark/content.min.css create mode 100644 src/Foundation/public/libraries/hugerte/skins/ui/oxide-dark/skin.min.css create mode 100644 src/Foundation/public/libraries/hugerte/skins/ui/oxide/content.min.css create mode 100644 src/Foundation/public/libraries/hugerte/skins/ui/oxide/skin.min.css create mode 100644 src/Foundation/public/libraries/hugerte/themes/silver/theme.min.js create mode 100644 src/Foundation/public/libraries/jquery/jquery.min.js create mode 100644 src/Foundation/public/libraries/lodash/lodash.min.js create mode 100644 src/Foundation/public/libraries/overlayscrollbars/overlayscrollbars.min.css create mode 100644 src/Foundation/public/libraries/overlayscrollbars/overlayscrollbars.min.js create mode 100644 src/Foundation/public/libraries/popper/popper.min.js create mode 100644 src/Foundation/public/libraries/query-builder/query-builder.compatibility.js create mode 100644 src/Foundation/public/libraries/query-builder/query-builder.min.css create mode 100644 src/Foundation/public/libraries/query-builder/query-builder.min.js create mode 100644 src/Foundation/public/libraries/sortable/sortable.min.js create mode 100644 src/Foundation/public/libraries/tabler-icons/fonts/tabler-icons-filled.ttf create mode 100644 src/Foundation/public/libraries/tabler-icons/fonts/tabler-icons-filled.woff create mode 100644 src/Foundation/public/libraries/tabler-icons/fonts/tabler-icons-filled.woff2 create mode 100644 src/Foundation/public/libraries/tabler-icons/fonts/tabler-icons.ttf create mode 100644 src/Foundation/public/libraries/tabler-icons/fonts/tabler-icons.woff create mode 100644 src/Foundation/public/libraries/tabler-icons/fonts/tabler-icons.woff2 create mode 100644 src/Foundation/public/libraries/tabler-icons/tabler-icons.json create mode 100644 src/Foundation/public/libraries/tabler-icons/tabler-icons.min.css create mode 100644 src/Foundation/public/libraries/tabler/css/tabler-flags.min.css create mode 100644 src/Foundation/public/libraries/tabler/css/tabler-marketing.ltr.min.css create mode 100644 src/Foundation/public/libraries/tabler/css/tabler-marketing.rtl.min.css create mode 100644 src/Foundation/public/libraries/tabler/css/tabler-socials.min.css create mode 100644 src/Foundation/public/libraries/tabler/css/tabler-vendors.min.css create mode 100644 src/Foundation/public/libraries/tabler/css/tabler.ltr.min.css create mode 100644 src/Foundation/public/libraries/tabler/css/tabler.rtl.min.css create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ad.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ae.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/af.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/afrun.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ag.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ai.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/al.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/am.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ao.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/aq.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ar.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/as.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/at.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/au.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/aw.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ax.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/az.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ba.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bb.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bd.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/be.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bf.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bg.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bh.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bi.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bj.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bl.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bn.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bo.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bq-bo.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bq-sa.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bq-se.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/br.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bs.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bt.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bv.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bw.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/by.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/bz.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ca.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cc.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cd.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cf.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cg.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ch.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ci.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ck.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cl.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cn.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/co.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cu.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cv.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cw.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cx.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cy.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/cz.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/de.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/dj.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/dk.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/dm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/do.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/dz.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ec.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ee.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/eg.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/eh.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/er.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/es.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/et.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/eu.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/fi.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/fj.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/fk.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/fm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/fo.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/fr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ga.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gb-eng.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gb-nir.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gb-sct.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gb-wls.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gb.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gd.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ge.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gf.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gg.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gh.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gi.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gl.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gn.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gp.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gq.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gs.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gt.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gu.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gw.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/gy.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/hk.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/hm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/hn.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/hr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ht.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/hu.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/id.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ie.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/il.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/im.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/in.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/io.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/iq.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ir.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/is.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/it.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/je.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/jm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/jo.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/jp.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ke.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/kg.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/kh.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ki.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/km.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/kn-sk.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/kn.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/kp.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/kr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/kw.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ky.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/kz.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/la.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/lb.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/lc.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/li.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/lk.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/lr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ls.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/lt.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/lu.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/lv.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ly.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ma.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mc.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/md.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/me.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mf.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mg.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mh.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mk.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ml.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mn.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mo.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mp.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mq.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ms.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mt.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mu.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mv.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mw.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mx.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/my.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/mz.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/na.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/nc.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ne.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/nf.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ng.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ni.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/nl.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/no.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/np.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/nr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/nu.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/nz.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/om.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/pa.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/pe.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/pf.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/pg.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ph.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/pk.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/pl.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/pm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/pn.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/pr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ps.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/pt.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/pw.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/py.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/qa.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/rainbow.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/re.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ro.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/rs.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ru.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/rw.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sa.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sb.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sc.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sd.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/se.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sg.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sh.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/si.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sj.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sk.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sl.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sn.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/so.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ss.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/st.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sv.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sx.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sy.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/sz.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tc.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/td.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tf.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tg.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/th.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tj.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tk.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tl.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tn.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/to.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tt.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tv.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tw.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/tz.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ua.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ug.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/um.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/unasur.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/us.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/uy.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/uz.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/va.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/vc.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ve.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/vg.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/vi.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/vn.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/vu.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/wf.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ws.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/ye.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/yt.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/za.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/zm.svg create mode 100644 src/Foundation/public/libraries/tabler/img/flags/zw.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/apple-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/apple.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/discord-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/discord.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/dribbble-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/dribbble.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/facebook-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/facebook.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/figma-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/figma.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/github-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/github.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/google-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/google.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/instagram-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/instagram.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/linkedin-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/linkedin.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/medium-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/medium.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/meta-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/meta.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/metamask-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/metamask.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/pinterest-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/pinterest.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/reddit-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/reddit.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/signal-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/signal.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/skype-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/skype.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/snapchat-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/snapchat.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/spotify-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/spotify.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/telegram-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/telegram.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/tiktok-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/tiktok.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/tumblr-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/tumblr.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/twitch-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/twitch.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/vk-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/vk.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/x-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/x.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/youtube-gray.svg create mode 100644 src/Foundation/public/libraries/tabler/img/social/youtube.svg create mode 100644 src/Foundation/public/libraries/tabler/js/tabler.min.js create mode 100644 src/Foundation/public/libraries/tabler/js/tabler.min.js.map create mode 100644 src/Foundation/public/libraries/tempus-dominus/tempus-dominus.min.css create mode 100644 src/Foundation/public/libraries/tempus-dominus/tempus-dominus.min.js create mode 100644 src/Foundation/public/libraries/tom-select/tom-select.complete.min.js create mode 100644 src/Foundation/public/libraries/tom-select/tom-select.min.css create mode 100644 src/Foundation/public/plugins/redot-icon-picker.js create mode 100644 src/Foundation/public/plugins/redot-repeater.js create mode 100644 src/Foundation/public/plugins/redot-toasts.js create mode 100644 src/Foundation/public/plugins/redot-uploader.js create mode 100644 src/Foundation/public/plugins/redot-validator-rules.js create mode 100644 src/Foundation/public/plugins/redot-validator.js create mode 100644 src/Foundation/public/plugins/redot-visibility.js create mode 100644 src/Foundation/resources/components/alert.blade.php create mode 100644 src/Foundation/resources/components/apex-chart.blade.php create mode 100644 src/Foundation/resources/components/assets/apexcharts.blade.php create mode 100644 src/Foundation/resources/components/assets/cloudflare-turnstile.blade.php create mode 100644 src/Foundation/resources/components/assets/coloris.blade.php create mode 100644 src/Foundation/resources/components/assets/hugerte.blade.php create mode 100644 src/Foundation/resources/components/assets/query-builder.blade.php create mode 100644 src/Foundation/resources/components/assets/redot-icon-picker.blade.php create mode 100644 src/Foundation/resources/components/assets/redot-repeater.blade.php create mode 100644 src/Foundation/resources/components/assets/redot-toasts.blade.php create mode 100644 src/Foundation/resources/components/assets/redot-uploader.blade.php create mode 100644 src/Foundation/resources/components/assets/tabler-flags.blade.php create mode 100644 src/Foundation/resources/components/assets/tabler-socials.blade.php create mode 100644 src/Foundation/resources/components/assets/tempus-dominus.blade.php create mode 100644 src/Foundation/resources/components/assets/tom-select.blade.php create mode 100644 src/Foundation/resources/components/attachments.blade.php create mode 100644 src/Foundation/resources/components/avatar.blade.php create mode 100644 src/Foundation/resources/components/captcha.blade.php create mode 100644 src/Foundation/resources/components/checkboxes.blade.php create mode 100644 src/Foundation/resources/components/color-picker.blade.php create mode 100644 src/Foundation/resources/components/date-picker.blade.php create mode 100644 src/Foundation/resources/components/empty.blade.php create mode 100644 src/Foundation/resources/components/field.blade.php create mode 100644 src/Foundation/resources/components/file-hint.blade.php create mode 100644 src/Foundation/resources/components/flag.blade.php create mode 100644 src/Foundation/resources/components/form-card.blade.php create mode 100644 src/Foundation/resources/components/form.blade.php create mode 100644 src/Foundation/resources/components/hint.blade.php create mode 100644 src/Foundation/resources/components/icon-picker.blade.php create mode 100644 src/Foundation/resources/components/icon.blade.php create mode 100644 src/Foundation/resources/components/input.blade.php create mode 100644 src/Foundation/resources/components/label.blade.php create mode 100644 src/Foundation/resources/components/page-header.blade.php create mode 100644 src/Foundation/resources/components/pagination.blade.php create mode 100644 src/Foundation/resources/components/query-builder.blade.php create mode 100644 src/Foundation/resources/components/radios-colored.blade.php create mode 100644 src/Foundation/resources/components/radios.blade.php create mode 100644 src/Foundation/resources/components/rating.blade.php create mode 100644 src/Foundation/resources/components/redot-scripts.blade.php create mode 100644 src/Foundation/resources/components/redot-styles.blade.php create mode 100644 src/Foundation/resources/components/repeater-card.blade.php create mode 100644 src/Foundation/resources/components/repeater.blade.php create mode 100644 src/Foundation/resources/components/rich-editor.blade.php create mode 100644 src/Foundation/resources/components/select-remote.blade.php create mode 100644 src/Foundation/resources/components/select.blade.php create mode 100644 src/Foundation/resources/components/social-icon.blade.php create mode 100644 src/Foundation/resources/components/status.blade.php create mode 100644 src/Foundation/resources/components/textarea.blade.php create mode 100644 src/Foundation/resources/components/toasts.blade.php create mode 100644 src/Foundation/resources/components/toggle.blade.php create mode 100644 src/Foundation/resources/components/translatable-switcher.blade.php create mode 100644 src/Foundation/resources/components/translatable.blade.php create mode 100644 src/Foundation/resources/components/uploader.blade.php create mode 100644 src/Foundation/resources/inits/apex-chart.js create mode 100644 src/Foundation/resources/inits/coloris.js create mode 100644 src/Foundation/resources/inits/hugerte.js create mode 100644 src/Foundation/resources/inits/icon-picker.js create mode 100644 src/Foundation/resources/inits/overlay-scrollbars.js create mode 100644 src/Foundation/resources/inits/query-builder.js create mode 100644 src/Foundation/resources/inits/repeater.js create mode 100644 src/Foundation/resources/inits/sortable.js create mode 100644 src/Foundation/resources/inits/tempus-dominus.js create mode 100644 src/Foundation/resources/inits/tomselect.js create mode 100644 src/Foundation/resources/inits/turnstile.js create mode 100644 src/Foundation/resources/inits/uploader.js create mode 100644 src/Foundation/src/Commands/PublishAssetsCommand.php create mode 100644 src/Foundation/src/View/Components/Alert.php create mode 100644 src/Foundation/src/View/Components/ApexChart.php create mode 100644 src/Foundation/src/View/Components/Attachments.php create mode 100644 src/Foundation/src/View/Components/Avatar.php create mode 100644 src/Foundation/src/View/Components/Captcha.php create mode 100644 src/Foundation/src/View/Components/Checkboxes.php create mode 100644 src/Foundation/src/View/Components/ColorPicker.php create mode 100644 src/Foundation/src/View/Components/Component.php create mode 100644 src/Foundation/src/View/Components/DatePicker.php create mode 100644 src/Foundation/src/View/Components/FileHint.php create mode 100644 src/Foundation/src/View/Components/Form.php create mode 100644 src/Foundation/src/View/Components/FormCard.php create mode 100644 src/Foundation/src/View/Components/FormField.php create mode 100644 src/Foundation/src/View/Components/IconPicker.php create mode 100644 src/Foundation/src/View/Components/Input.php create mode 100644 src/Foundation/src/View/Components/QueryBuilder.php create mode 100644 src/Foundation/src/View/Components/Radios.php create mode 100644 src/Foundation/src/View/Components/RadiosColored.php create mode 100644 src/Foundation/src/View/Components/Rating.php create mode 100644 src/Foundation/src/View/Components/Repeater.php create mode 100644 src/Foundation/src/View/Components/RichEditor.php create mode 100644 src/Foundation/src/View/Components/Select.php create mode 100644 src/Foundation/src/View/Components/SelectRemote.php create mode 100644 src/Foundation/src/View/Components/Status.php create mode 100644 src/Foundation/src/View/Components/Textarea.php create mode 100644 src/Foundation/src/View/Components/Toasts.php create mode 100644 src/Foundation/src/View/Components/Toggle.php create mode 100644 src/Foundation/src/View/Components/Translatable.php create mode 100644 src/Foundation/src/View/Components/Uploader.php create mode 100644 tests/Feature/Core/Commands/BuildDependenciesCommandTest.php create mode 100644 tests/Feature/Core/Components/TranslatableTest.php create mode 100644 tests/Feature/Core/ComponentsTest.php create mode 100644 tests/Fixtures/views/components/toasts.blade.php create mode 100644 tests/Unit/Core/Jobs/ExtractLanguageTokensTest.php diff --git a/docs/content/commands/overview.md b/docs/content/commands/overview.md index 2ed10ec..93f1706 100644 --- a/docs/content/commands/overview.md +++ b/docs/content/commands/overview.md @@ -42,18 +42,13 @@ Creates a symbolic link from the framework's `public/` directory to a sibling di - **`--name`** — the name of the link to create (defaults to `public_html`). -## `datatables:link` +## `redot:publish` ```bash -php artisan datatables:link -php artisan datatables:link --force -php artisan datatables:link --relative +php artisan redot:publish ``` -Creates a symbolic link from `public/vendor/datatables` to the Datatables package assets. Required once per install (and again after upgrades) so the table's CSS/JS are served statically. Prefer `vendor:publish --tag=datatables::assets` if symlinks are unavailable. - -- **`--force`** — recreate the symlink if it already exists. -- **`--relative`** — create a relative symlink. +Publishes the Redot front-end assets — the shared runtime, plugins, styles, Datatables assets, and the third-party libraries they use — to `public/vendor/redot`. It replaces the whole directory, so files removed from the package don't linger. The starter kit runs it from Composer's `post-update-cmd`, so assets stay current after every `redot/core` upgrade. ## `permissions:sync` diff --git a/docs/content/components/overview.md b/docs/content/components/overview.md index 19dd2c7..d076565 100644 --- a/docs/content/components/overview.md +++ b/docs/content/components/overview.md @@ -30,6 +30,15 @@ To give a custom control the same label, hint, and required marker, wrap it in [ Components that wrap a JavaScript widget (date pickers, selects, the rich editor, uploader, …) light up automatically through the [asset & init system](/frontend/asset-system) — you don't wire up any JS yourself. +## Overriding a component + +The components on this page ship inside the `redot/core` package, so they update with `composer update`. Only the branding and integration components ([Logo](/components/logo), [Favicon](/components/favicon), [Page Loader](/components/page-loader), [Countries](/components/countries), [Facebook Pixel](/components/facebook-pixel), and [Google Analytics](/components/google-analytics)) live in your application. You can still replace a package component in your application without renaming it: + +- **Markup** — add a view with the same name under `resources/components`, such as `resources/components/toasts.blade.php`. Your view is used instead of the package's. +- **Behavior** — add a class with the same name under `App\View\Components`, such as `App\View\Components\Toasts`. Extend the package class (`Redot\View\Components\Toasts`) to change only what you need. + +The JavaScript and CSS these components load ship with core, along with the third-party libraries they use (jQuery, Tabler, Tom Select, HugeRTE, Coloris, …). `php artisan redot:publish` copies them to `public/vendor/redot` and runs on every `composer update`, so don't edit them there. + ## Component index ### Form inputs @@ -61,6 +70,7 @@ Components that wrap a JavaScript widget (date pickers, selects, the rich editor - [Form Card](/components/form-card) — `` - [Page Header](/components/page-header), [Page Loader](/components/page-loader) - [Pagination](/components/pagination) +- [Redot Styles & Scripts](/frontend/asset-system#loading-the-runtime) — `` / ``, the shared runtime for a layout - [Empty](/components/empty) — empty-state placeholder - [Layouts](/layouts/overview) — page shells (``, …) diff --git a/docs/content/frontend/asset-system.md b/docs/content/frontend/asset-system.md index 687c98b..b753d07 100644 --- a/docs/content/frontend/asset-system.md +++ b/docs/content/frontend/asset-system.md @@ -1,6 +1,6 @@ # Asset & Init System -The dashboard frontend is shipped as static assets under `public/assets` — there is no Vite/Webpack build for the platform layer. A small artisan step compiles per-feature "init" scripts and translations, and a runtime `init()` bootstrap attaches them to any element that carries an `init="..."` attribute. This page is the canonical reference for how JavaScript widgets get wired up. +The dashboard frontend is shipped as static assets — there is no Vite/Webpack build for the platform layer. The shared runtime (`functions.js`, `themer.js`, the `redot-*` plugins, and `redot.css`) ships with `redot/core`, together with the third-party libraries it relies on, and `php artisan redot:publish` copies all of it to `public/vendor/redot`. Your application's own assets live under `public/assets`. A small artisan step compiles per-feature "init" scripts and translations, and a runtime `init()` bootstrap attaches them to any element that carries an `init="..."` attribute. This page is the canonical reference for how JavaScript widgets get wired up. ## Enabling a widget with `init` @@ -33,6 +33,33 @@ Each has its own page with the options it accepts: - [Turnstile](/frontend/inits/turnstile) — Cloudflare captcha - [Uploader](/frontend/inits/uploader) +## Loading the runtime + +A layout loads the whole shared runtime with two components, so the list of libraries and their order stays with `redot/core` and updates with it: + +```blade + + ... + + + + + + {{ $slot }} + + + + + @stack('plugins-scripts') + @stack('scripts') + +``` + +- **``** — Tabler (in the given `direction`, defaulting to the current language's), Tabler Icons, Glare, OverlayScrollbars, the `plugins-styles` stack, and `redot.css`. Load your application CSS right after it so your rules win. +- **``** — jQuery, Lodash, Tabler, `functions.js`, the bundled plugins, the translations and initializer bundles, the runtime (`runtime.js`: running initializers as markup appears, client-side form validation, the CSRF header and session-expiry dialog for AJAX, lightbox links, and Bootbox defaults), toasts, and the restoring of submitted input and validation errors. Load your application script right after it; `app.js` is yours to fill. + +The scaffold layout already uses both. To change what they load, [override](/components/overview) `resources/components/redot-styles.blade.php` or `redot-scripts.blade.php`. + ## Loading a widget's vendor files Components load the third-party scripts and styles their widget needs. If you put an `init` attribute on your own markup instead, include the matching `` component so those files are on the page: @@ -93,9 +120,12 @@ php artisan dependencies:build 2. Use it from Blade: `
`. 3. The next request rebuilds `dist/` and your initializer is live as `init="my-widget"`. +The built-in initializers ship with `redot/core`. To change one, add a file with the same name to `public/assets/inits` (for example `public/assets/inits/tomselect.js`); it replaces the package version in the build. + ## Gotchas - **Never edit `public/assets/dist/*` by hand** — it is regenerated. Edit the source `public/assets/inits/*.js` and `lang/*` files instead. +- **Never edit `public/vendor/redot/*`** — `redot:publish` replaces it on every `composer update`. Override a component or initializer in your application instead. - An element is initialized only once. If you re-render it and need it re-initialized, render fresh markup rather than reusing an already-initialized element. ## Related diff --git a/docs/content/getting-started/installation.md b/docs/content/getting-started/installation.md index 46f13b9..da7a588 100644 --- a/docs/content/getting-started/installation.md +++ b/docs/content/getting-started/installation.md @@ -55,7 +55,7 @@ php artisan migrate The bundled packages expose their own tags, all following the `package::resource` convention. Their config, views, lang, and routes load automatically; publish only to override. -- **Datatables** — `datatables::config`, `datatables::views`, `datatables::lang`, `datatables::assets`. Run `php artisan datatables:link` (or publish `datatables::assets`) so CSS/JS are available under `public/vendor/datatables`. See [Datatables](/packages/datatables/overview). +- **Datatables** — `datatables::config`, `datatables::views`, `datatables::lang`. Its CSS/JS are published with the rest of the Redot assets by `php artisan redot:publish`. See [Datatables](/packages/datatables/overview). - **Toastify** — `toastify::config`. See [Toastify](/packages/toastify). - **Auth, Sidebar, LangExtractor** — nothing to publish; they are wired up for you. diff --git a/docs/content/packages/datatables/frontend.md b/docs/content/packages/datatables/frontend.md index 1262ffd..e159bf5 100644 --- a/docs/content/packages/datatables/frontend.md +++ b/docs/content/packages/datatables/frontend.md @@ -69,24 +69,7 @@ A datatable is a Livewire component, so mount it with Livewire's tag syntax. Pub ## Assets -The package ships plain JS and CSS under `public/vendor/datatables` — there's no build step or `npm` publish. Link them once (like `storage:link`), then the table injects them automatically the first time one renders: - -```bash -php artisan datatables:link -php artisan datatables:link --force -php artisan datatables:link --relative -``` - -- **`--force`** — recreate the symlink if it already exists. -- **`--relative`** — create a relative symlink (useful in some deploy layouts). - -Prefer a copy instead of a symlink? Publish the assets: - -```bash -php artisan vendor:publish --tag=datatables::assets --force -``` - -Re-run the link (or publish with `--force`) after upgrading `redot/core` so CSS/JS stay current. The scripts expect the dashboard's globals: jQuery, Bootstrap dropdowns, Livewire, and the helpers from `functions.js` — confirmable [actions](/packages/datatables/actions) prompt through `warnBeforeAction`, and non-GET actions submit through `formRequest` (which reads the CSRF token from the layout's `csrf-token` meta tag). See the [Asset & Init System](/frontend/asset-system) for how front-end assets are served. +The package ships plain JS and CSS — there's no build step or `npm` publish. [`redot:publish`](/commands/overview) copies them to `public/vendor/redot/datatables` with the rest of the Redot assets, and the table injects them automatically the first time one renders. The scripts expect the dashboard's globals: jQuery, Bootstrap dropdowns, Livewire, and the helpers from `functions.js` — confirmable [actions](/packages/datatables/actions) prompt through `warnBeforeAction`, and non-GET actions submit through `formRequest` (which reads the CSRF token from the layout's `csrf-token` meta tag). See the [Asset & Init System](/frontend/asset-system) for how front-end assets are served. The script exposes its helpers as `window.Datatables` — the package views consume them (the Alpine components behind the root card, the select-page checkbox, and the action click handling) instead of inlining the logic. If you publish and customize the views, reuse the same helpers: `Datatables.table()` and `Datatables.pageSelection()` for the Alpine state, and `Datatables.confirmed()` / `Datatables.submit()` / `Datatables.url()` / `Datatables.invoke()` for action behavior. diff --git a/src/Datatables/config/datatables.php b/src/Datatables/config/datatables.php index 9062ae5..550b0b3 100644 --- a/src/Datatables/config/datatables.php +++ b/src/Datatables/config/datatables.php @@ -18,8 +18,8 @@ */ 'assets' => [ - 'css' => 'vendor/datatables/datatables.css', - 'js' => 'vendor/datatables/datatables.js', + 'css' => 'vendor/redot/datatables/datatables.css', + 'js' => 'vendor/redot/datatables/datatables.js', ], 'export' => [ diff --git a/src/Datatables/src/Commands/DatatablesLinkCommand.php b/src/Datatables/src/Commands/DatatablesLinkCommand.php deleted file mode 100644 index e714f8a..0000000 --- a/src/Datatables/src/Commands/DatatablesLinkCommand.php +++ /dev/null @@ -1,77 +0,0 @@ -isRemovableSymlink($link, $this->option('force'))) { - error("The [$link] link already exists."); - - return self::FAILURE; - } - - if (is_link($link)) File::delete($link); - if (! is_dir(dirname($link))) File::makeDirectory(dirname($link), 0755, true); - - if ($this->option('relative')) { - File::relativeLink($target, $link); - } else { - File::link($target, $link); - } - - info('Datatables assets linked successfully.'); - - return self::SUCCESS; - } - - /** - * Determine if the provided path is a symlink that can be removed. - */ - protected function isRemovableSymlink(string $link, bool $force): bool - { - return is_link($link) && $force; - } -} diff --git a/src/Datatables/src/DatatablesServiceProvider.php b/src/Datatables/src/DatatablesServiceProvider.php index 2e28911..99d6980 100644 --- a/src/Datatables/src/DatatablesServiceProvider.php +++ b/src/Datatables/src/DatatablesServiceProvider.php @@ -4,7 +4,6 @@ use Illuminate\Support\ServiceProvider; use Redot\Datatables\Commands\DatatableMakeCommand; -use Redot\Datatables\Commands\DatatablesLinkCommand; class DatatablesServiceProvider extends ServiceProvider { @@ -31,7 +30,6 @@ public function boot(): void $this->commands([ DatatableMakeCommand::class, - DatatablesLinkCommand::class, ]); } @@ -71,7 +69,7 @@ protected function lang(): void protected function assets(): void { $this->publishes([ - __DIR__ . '/../public' => public_path('vendor/datatables'), - ], 'datatables::assets'); + __DIR__ . '/../public' => public_path('vendor/redot/datatables'), + ], 'redot::assets'); } } diff --git a/src/Foundation/public/css/redot.css b/src/Foundation/public/css/redot.css new file mode 100644 index 0000000..9dea5d3 --- /dev/null +++ b/src/Foundation/public/css/redot.css @@ -0,0 +1,524 @@ +/* --------------------------------- + * Global Styles + * --------------------------------- */ + +[role='tab'].has-invalid-feedback { + color: var(--tblr-danger) !important; +} + +a:not(.text-reset):not([class*='text-decoration-']) { + text-decoration: none !important; +} + +.avatar .ti { + display: inline-flex; + align-items: center; + justify-content: center; +} + +/* --------------------------------- + * Global Utilities + * --------------------------------- */ + +.hidden-on-empty:empty { + display: none; +} + +.flex-center { + display: flex; + align-items: center; + justify-content: center; +} + +/* --------------------------------- + * Redot Visibility + * --------------------------------- */ + +[visible-when]:not([is-visible='true']) { + display: none; +} + +/* --------------------------------- + * Inline Loading + * --------------------------------- */ + +.inline-loading { + overflow: hidden; +} + +.inline-loading-overlay { + position: absolute; + inset: 0; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + background-color: color-mix(in srgb, var(--tblr-bg-surface) 72%, transparent); + -webkit-backdrop-filter: blur(4px); + backdrop-filter: blur(4px); + border-radius: inherit; +} + +.inline-loading-overlay.unlocked { + pointer-events: none; +} + +.inline-loading-overlay .spinner-border-lg, +.inline-loading-overlay .spinner-grow-lg { + --tblr-spinner-width: 2.5rem; + --tblr-spinner-height: 2.5rem; + --tblr-spinner-border-width: 3px; +} + +/* --------------------------------- + * Icon Picker Component + * --------------------------------- */ + +[iconpicker-modal] { + display: grid; + grid-template-rows: auto auto 1fr auto; + gap: 0.75rem; + height: 420px; +} + +[iconpicker-modal] [iconpicker-list] { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(40px, 1fr)); + grid-auto-rows: min-content; + grid-gap: 10px; + padding: 10px; + border: 1px solid var(--tblr-border-color); + border-radius: var(--tblr-border-radius); + overflow-y: auto; + scrollbar-width: none; + -ms-overflow-style: none; +} + +[iconpicker-modal] [iconpicker-list]::-webkit-scrollbar { + display: none; +} + +[iconpicker-modal] [iconpicker-icon] { + display: flex; + justify-content: center; + align-items: center; + width: 40px; + height: 40px; + text-align: center; + color: var(--tblr-body-color); + border: 1px solid var(--tblr-border-color); + border-radius: 4px; + cursor: pointer; +} + +[iconpicker-modal] [iconpicker-icon].selected { + color: var(--tblr-primary); + border-color: var(--tblr-primary); +} + +[iconpicker-modal] [iconpicker-empty] { + grid-column: 1 / -1; + text-align: center; + padding-block: 3rem; +} + +.icon-rotate-90 { + transform: rotate(90deg); +} + +.icon-rotate-180 { + transform: rotate(180deg); +} + +.icon-rotate-270 { + transform: rotate(270deg); +} + +.icon-flip-horizontal { + transform: scaleX(-1); +} + +.icon-flip-vertical { + transform: scaleY(-1); +} + +/* --------------------------------- + * Translatable Component + * --------------------------------- */ + +[translatable-tab].has-invalid-feedback { + border-color: var(--tblr-danger); +} + +[translatable-tab].has-invalid-feedback span { + display: flex; + align-items: center; +} + +[translatable-tab].has-invalid-feedback span::before { + content: '\eb55'; + font-family: 'tabler-icons'; + margin-inline-end: 5px; +} + +.card-header:has([translatable-switcher]) { + padding-block: 10px; +} + +/* --------------------------------- + * Rating Component + * --------------------------------- */ + +.rating-field { + display: inline-flex; + flex-direction: row-reverse; +} + +.rating-field input[type='radio'] { + display: none; +} + +.rating-field label { + cursor: pointer; +} + +.rating-field label i { + color: var(--tblr-border-color); +} + +.rating-field label i { + font-size: var(--star-size); +} + +.rating-field:not(:hover) input[type='radio']:checked ~ label i, +.rating-field input[type='radio']:hover ~ label i { + color: var(--tblr-yellow); +} + +/* --------------------------------- + * Repeater Component + * --------------------------------- */ + +.repeater-toolbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 5px; + padding: 5px; + margin-bottom: 10px; + border: 1px solid var(--tblr-border-color); + border-radius: var(--tblr-border-radius); + background-color: var(--tblr-body-bg); +} + +.repeater-toolbar label { + margin: 0; + font-size: 1rem; + padding-inline-start: 5px; +} + +table div[repeater-item] { + display: contents; +} + +/* --------------------------------- + * Uploader & Attachments Components + * --------------------------------- */ + +[uploader-container], +[attachments-container] { + --uploader-row: 2.25rem; + --uploader-thumb: 1.75rem; +} + +[uploader-container]:not(.has-files) [uploader-wrapper] { + border-style: dashed; + background-color: transparent; + box-shadow: none; +} + +[uploader-wrapper]:focus-within { + border-color: var(--tblr-primary); +} + +[uploader-container] [uploader-wrapper].drag-over { + border-style: solid; + border-color: var(--tblr-primary); + background-color: color-mix(in srgb, var(--tblr-primary) 5%, var(--tblr-bg-surface)); + box-shadow: 0 0 0 0.25rem color-mix(in srgb, var(--tblr-primary) 14%, transparent); +} + +[uploader-trigger] { + min-height: calc(var(--uploader-row) - var(--tblr-border-width) * 2); + padding-block: 0; + padding-inline: 0.625rem; + background-color: transparent; + color: var(--tblr-secondary-color); + font-size: 0.8125rem; + line-height: 1.25rem; + white-space: nowrap; + cursor: pointer; + transition: + background-color 0.15s ease, + color 0.15s ease; +} + +[uploader-trigger]:hover { + background-color: var(--tblr-bg-surface-secondary); + color: var(--tblr-primary); +} + +[uploader-trigger]:focus-visible { + outline: 2px solid var(--tblr-primary); + outline-offset: -2px; +} + +[uploader-trigger] > i { + opacity: 0.7; +} + +[uploader-labels] { + min-width: 0; +} + +[uploader-empty] { + display: inline; +} + +[uploader-empty]::before { + content: '·'; + margin-inline: 0.375rem; + opacity: 0.55; +} + +[uploader-dropping] { + display: none; +} + +[uploader-wrapper].drag-over [uploader-trigger] { + background-color: transparent; + color: var(--tblr-primary); +} + +[uploader-wrapper].drag-over [uploader-idle] { + display: none; +} + +[uploader-wrapper].drag-over [uploader-dropping] { + display: inline; +} + +[uploader-list], +[attachments-list] { + max-height: calc(var(--uploader-row) * 6.5); + overflow-x: hidden; + overflow-y: auto; + scrollbar-width: thin; + cursor: initial; +} + +[attachments-none] { + min-height: calc(var(--uploader-row) - var(--tblr-border-width) * 2); + padding-inline: 0.625rem; + font-size: 0.8125rem; +} + +.uploader-item { + min-height: var(--uploader-row); + padding-block: 0.1875rem; + padding-inline: 0.5rem 0.375rem; + box-shadow: inset 0 -1px 0 var(--tblr-border-color); + transition: background-color 0.15s ease; +} + +[uploader-list] .uploader-item { + cursor: grab; +} + +[attachments-list] .uploader-item { + color: var(--tblr-body-color); + cursor: pointer; +} + +[attachments-list] .uploader-item:last-child { + box-shadow: none; +} + +.uploader-item:hover { + background-color: var(--tblr-bg-surface-secondary); +} + +.uploader-item::before { + content: ''; + position: absolute; + inset-block: 0; + inset-inline-start: 0; + width: 0.1875rem; + background-color: transparent; + transition: background-color 0.2s ease; +} + +.uploader-item.status-pending { + opacity: 0.75; +} + +.uploader-item.status-pending::before { + background-color: var(--tblr-border-color); +} + +.uploader-item.status-uploading::before { + background-color: var(--tblr-info); +} + +.uploader-item.status-uploaded::before { + background-color: var(--tblr-success); +} + +.uploader-item.status-error { + background-color: color-mix(in srgb, var(--tblr-danger) 7%, transparent); +} + +.uploader-item.status-error::before { + background-color: var(--tblr-danger); +} + +.uploader-item-preview { + width: var(--uploader-thumb); + height: var(--uploader-thumb); + background-color: var(--tblr-bg-surface-secondary); +} + +.uploader-item-image { + object-fit: cover; +} + +.uploader-item-preview i { + font-size: 0.8125rem; + color: var(--tblr-secondary-color); +} + +.uploader-item-preview .lightbox-preview { + background-color: rgba(0, 0, 0, 0.55); + opacity: 0; + cursor: pointer; + transition: opacity 0.15s ease; +} + +.uploader-item-preview .lightbox-preview::after { + content: '\ea9a'; + font-family: 'tabler-icons'; + font-size: 0.625rem; + color: var(--tblr-white); +} + +.uploader-item:hover .lightbox-preview, +.uploader-item .lightbox-preview:focus-visible { + opacity: 1; +} + +.uploader-item:not(.status-uploaded) .lightbox-preview { + display: none; +} + +.uploader-item-info { + min-width: 0; +} + +.uploader-item-name { + min-width: 0; + font-size: 0.8125rem; + line-height: 1.25rem; + color: var(--tblr-body-color); +} + +.uploader-item-size { + direction: ltr; + unicode-bidi: isolate; + font-size: 0.75rem; + font-variant-numeric: tabular-nums; +} + +.uploader-item-progress { + position: absolute; + inset-inline: 0; + inset-block-end: 0; +} + +.uploader-item-progress .progress { + height: 0.125rem; +} + +.uploader-item-progress .progress-bar { + background-color: var(--tblr-primary); + transition: width 0.3s ease; +} + +.uploader-item-actions { + gap: 0.0625rem; +} + +.uploader-item-actions .btn { + width: 1.625rem; + height: 1.625rem; + min-width: 0; + min-height: 0; + padding: 0; + border: 0; + background-color: transparent; + box-shadow: none; + color: var(--tblr-secondary-color); + font-size: 0.75rem; +} + +.uploader-item-actions .btn:hover { + background-color: var(--tblr-bg-surface-tertiary, var(--tblr-border-color)); + color: var(--tblr-body-color); +} + +.uploader-item-actions .btn:focus-visible { + outline: 2px solid var(--tblr-primary); + outline-offset: -2px; +} + +.uploader-item-actions [action='remove']:hover { + background-color: color-mix(in srgb, var(--tblr-danger) 14%, transparent); + color: var(--tblr-danger); +} + +[attachments-list] .uploader-item:hover .btn { + color: var(--tblr-primary); +} + +.uploader-item.sortable-ghost { + opacity: 0.3; +} + +.uploader-item.sortable-drag { + cursor: grabbing; + background-color: var(--tblr-bg-surface); + border-radius: var(--tblr-border-radius-lg); + box-shadow: 0 0.5rem 1rem -0.25rem rgba(0, 0, 0, 0.18); +} + +@media (hover: none) { + [uploader-list] .uploader-item { + cursor: initial; + touch-action: pan-y; + } + + [uploader-list] .uploader-item-preview { + cursor: grab; + touch-action: none; + } + + .uploader-item-actions, + .uploader-item-preview .lightbox-preview { + opacity: 1; + pointer-events: auto; + } + + [uploader-empty] { + display: none !important; + } +} diff --git a/src/Foundation/public/js/functions.js b/src/Foundation/public/js/functions.js new file mode 100644 index 0000000..3c739bc --- /dev/null +++ b/src/Foundation/public/js/functions.js @@ -0,0 +1,1070 @@ +/* --------------------------------- + * jQuery Extensions + * --------------------------------- */ + +if (typeof window.$ !== 'undefined') { + $.fn.extend({ + /** + * Check if the given element has the given attribute. + * + * @param {string} name + * @returns {boolean} + */ + hasAttr: function (name) { + let $element = this; + + // Early return if the element is not found + if ($element.length === 0) { + return false; + } + + return $element.get(0).hasAttribute(name); + }, + + /** + * Get the theme of the given element. + * + * @param {object} $element + * @returns {string} + */ + theme: function () { + let $element = this; + + let attr = 'data-bs-theme'; + let theme = $element.closest(`[${attr}]`).attr(attr); + + // If the theme is inherit, return the theme of the html element + if (theme === 'inherit') return $('html').attr(attr); + + return theme; + }, + }); + + /** + * Query the given selector. + * + * @param {string} selector + * @param {string|object} context + * @returns {object} + */ + window.$.query = function (selector, context = document) { + // Get the context jQuery object + const $context = context instanceof jQuery ? context : $(context); + + // Early return if the selector is already a jQuery object + if (selector instanceof jQuery) return selector; + + let patterns = [ + selector, + `#${selector}`, + `.${selector}`, + `[name="${selector}"]`, + `[name^="${selector}"]`, + `[${selector}]`, + ]; + + try { + for (const pattern of patterns) { + if ($context.find(pattern).length) { + return $context.find(pattern); + } + } + } catch (error) { + // ... + } + + return $(selector); + }; +} + +/* --------------------------------- + * Translations + * --------------------------------- */ + +/** + * Translate the given key with the given parameters. + * + * @param {string} key + * @param {object} params + * @returns {string} + */ +function __(key, params = {}) { + if (typeof window.__translations === 'undefined') { + return key; + } + + let translation = window.__translations[key] || key; + + for (const [param, value] of Object.entries(params)) { + translation = translation.replaceAll(`:${param}`, value); + } + + return translation; +} + +/* --------------------------------- + * Type & Value Helpers + * --------------------------------- */ + +/** + * Check if the given value is JSON. + * + * @param {string} value + * @returns {boolean} + */ +function isJson(value) { + try { + JSON.parse(value); + } catch (error) { + return false; + } + + return true; +} + +/** + * Convert the given string to a primitive value. + * + * @param {string} string + * @returns any + */ +function stringToPrimitive(string) { + const primitives = { + true: true, + false: false, + null: null, + undefined: undefined, + }; + + // If the value is a primitive, return it. + if (string in primitives) return primitives[string]; + + // If the value is a property of the window object, return it. + if (string.startsWith('window.')) return _.get(window, string.replace('window.', ''), string); + + // If the value starts with `return`, evaluate it and return the result. + if (string.startsWith('return ')) return new Function(string)(); + + // If the value is a numeric string, return it. + if (string.match(/^-?\d+$/)) return Number(string); + + // Try to parse the value as JSON and return it. + return isJson(string) ? JSON.parse(string) : string; +} + +/** + * Slugify the given string. + * + * @param {string} string + * @param {object} options + * @returns {string} + */ +function slugify(string, options = {}) { + const defaultOptions = { + replacement: '-', + remove: undefined, + lower: true, + strict: false, + trim: true, + }; + + const opts = { + ...defaultOptions, + ...options, + }; + + let slug = string.normalize().replace(opts.remove, '').replace(/\s+/g, ' '); + + if (opts.strict) { + slug = slug.replace(/[^A-Za-z0-9\s]/g, ''); + } + + if (opts.trim) { + slug = slug.trim(); + } + + slug = slug.replace(/\s+/g, opts.replacement); + + if (opts.lower) { + slug = slug.toLowerCase(); + } + + return slug; +} + +/* --------------------------------- + * Fuzzy Search + * --------------------------------- */ + +/** + * Score how well `query` fuzzy-matches `text`. + * Returns a higher score for better matches, or null when there is no match. + * + * Matching rules: + * - Exact substring matches rank highest (earlier + denser is better) + * - Otherwise characters must appear in order (subsequence) + * - Consecutive hits and matches at word starts score higher + * + * @param {string} query + * @param {string} text + * @returns {number|null} + */ +function fuzzyScore(query, text) { + if (!query || !text) return null; + + query = query.toLowerCase(); + text = text.toLowerCase(); + + // Exact substring: prefer earlier and denser matches + const index = text.indexOf(query); + if (index !== -1) { + return 1000 - index + (query.length / text.length) * 100; + } + + let qi = 0; + let score = 0; + let consecutive = 0; + let lastMatch = -1; + + for (let ti = 0; ti < text.length && qi < query.length; ti++) { + if (text[ti] !== query[qi]) continue; + + consecutive = lastMatch === ti - 1 ? consecutive + 1 : 1; + score += 1 + consecutive * 5; + + // Bonus for matching at the start of a word / segment + if (ti === 0 || /[\s\-_\/]/.test(text[ti - 1])) { + score += 10; + } + + lastMatch = ti; + qi++; + } + + return qi === query.length ? score : null; +} + +/* --------------------------------- + * Confirmation Dialogs + * --------------------------------- */ + +/** + * Show a confirmation dialog before executing the given action. + * + * @param {function} action + * @param {object} options + */ +function warnBeforeAction(action, options = {}) { + const defaultOptions = { + size: 'small', + title: __('Are you sure?'), + message: __('This action cannot be undone.'), + onEscape: true, + backdrop: true, + buttons: { + cancel: { + label: __('No'), + className: 'btn', + }, + confirm: { + label: __('Yes'), + className: 'btn-danger', + callback: function () { + return action.call(this); + }, + }, + }, + }; + + bootbox.dialog(_.merge(defaultOptions, options)); +} + +/** + * Wait for the user to confirm the given message. + * + * @param {object} options + */ +function awaitConfirmation(options = {}) { + return new Promise((resolve, reject) => { + const defaultOptions = { + size: 'small', + message: __('Are you sure?'), + onEscape: function () { + reject(); + }, + backdrop: true, + buttons: { + cancel: { + label: __('No'), + className: 'btn', + callback: function () { + return reject(); + }, + }, + confirm: { + label: __('Yes'), + className: 'btn-primary', + callback: function () { + return resolve(); + }, + }, + }, + }; + + bootbox.dialog(_.merge(defaultOptions, options)); + }); +} + +/* --------------------------------- + * Form Validation + * --------------------------------- */ + +/** + * Validate the given form. + * + * @param {object} $form + * @returns {boolean} + */ +function validateForm($form, verbose = false) { + const errors = RedotValidator.errors($form); + + // No errors, submit the form + if (Object.keys(errors).length === 0) { + return true; + } + + // Append the errors to the form if verbose mode is enabled + if (verbose) { + appendErrorsToForm($form, errors); + scrollToFirstError($form); + } + + return false; +} + +/** + * Append the given errors to the given form. + * + * @param {object} $form + * @param {object} errors + * @returns {void} + */ +function appendErrorsToForm($form, errors = {}) { + $form.find('.invalid-feedback').remove(); + $form.find('.is-invalid').removeClass('is-invalid'); + $form.find('.has-invalid-feedback').removeClass('has-invalid-feedback'); + + for (const [key, value] of Object.entries(errors)) { + const normalizedKey = key.replace(/\.([^\.]+)/g, '[$1]'); + const possibleKeys = [key, `${key}[]`, normalizedKey, `${normalizedKey}[]`]; + + let $input = $form.find(possibleKeys.map((key) => `[name="${key}"]`).join(', ')); + + // If the input is not found, try to find it by the validation key. + if ($input.length === 0) { + $form.find(`[validation-key]`).each(function () { + const key = $(this).attr('validation-key'); + + if (possibleKeys.includes($(this).attr(key))) { + $input = $(this); + } + }); + } + + let $container = null; + + if ($input.attr('validation-container')) { + $container = $($input.attr('validation-container')); + } else if ($form.attr('validation-container')) { + $container = $($form.attr('validation-container')); + } else { + $container = $input.parent(); + } + + const $feedback = $(`
`); + + $input.addClass('is-invalid'); + $container.addClass('has-invalid-feedback').append($feedback); + + let messages = Object.values(value); + let message = messages.shift(); + + if (messages.length) { + // If there are more than one error, add a counter for the remaining errors + message += ' ' + __('(and :count more error)', { count: messages.length }); + } + + $feedback.html(`${message}`); + + if ($input.closest('.input-group').length) { + $input.closest('.input-group').addClass('has-invalid-feedback'); + } + + $input.parents('.tab-pane').each(function () { + const tabpane = $(this).attr('id'); + $(`[href="#${tabpane}"]`).addClass('has-invalid-feedback'); + }); + } +} + +function scrollToFirstError($form) { + // Get the first error element + const $firstError = $form.find('.is-invalid').first(); + + // Early return if the first error element is not found + if ($firstError.length === 0) return; + + // Early return if the form has the attribute 'dont-scroll-to-error' + if ($form.hasAttr('dont-scroll-to-error')) return; + + // Show the tab containing the first error element + $firstError.parents('.tab-pane').each(function () { + const tabpane = $(this).attr('id'); + $(`[href="#${tabpane}"]`).tab('show'); + }); + + // Scroll to the first error element + $firstError.get(0).scrollIntoView({ + behavior: 'smooth', + block: 'center', + }); + + // Early return if the form has the attribute 'dont-toast' + if ($form.hasAttr('dont-toast')) return; + + toastify().error(__('You have errors in your form. Please correct them and try again.')); +} + +/* --------------------------------- + * Form Fields + * --------------------------------- */ + +/** + * Serialize the given fields. + * + * @param {object} $fields + * @returns {object} + */ +function serializeFields($fields, key = 'name') { + const data = {}; + + $fields.find(`[${key}]`).each(function () { + const identifier = $(this).attr(key).replace(/\[\]$/, ''); + + // Set the field value to the data object. + _.set(data, identifier, getFieldValue($(this), $fields, key)); + }); + + return data; +} + +/** + * Get the value of the given field. + * + * @param {object} $field + * @param {object} form + * @param {string} key + * @returns any + */ +function getFieldValue($field, form = 'body', key = 'name') { + const type = $field.attr('type'); + const identifier = $field.attr(key); + + if (type === 'checkbox' && $field.closest('.form-switch').length) { + return $field.is(':checked'); + } + + if (type === 'checkbox') { + const checked = $(form).find(`[${key}="${identifier}"]:checked`); + return checked.map((i, el) => $(el).val()).get(); + } + + if (type === 'radio') { + return $(form).find(`[${key}="${identifier}"]:checked`).val() || null; + } + + if (type === 'number' && $field.hasAttr('as-text') === false) { + return +$field.val(); + } + + if (window.hugerte && hugerte.get($field.attr('id'))) { + return hugerte.get($field.attr('id')).getContent(); + } + + if ($field.data('uploader')) { + return $field.data('uploader').getFiles(); + } + + return $field.val(); +} + +/** + * Deserialize the given data to the given fields. + * + * @param {object} $fields + * @param {object} data + * @returns {void} + */ +function deserializeFields($fields, data = {}, key = 'name') { + $fields.find(`[${key}]`).each(function () { + const $field = $(this); + const identifier = $(this).attr(key).replace(/\[\]$/, ''); + const value = _.get(data, identifier); + + // Early return if the value is not found. + if (typeof value === 'undefined') { + return; + } + + setFieldValue($field, value, $fields, key); + + // Trigger the change event after setting the value. + $field.trigger('change'); + }); +} + +/** + * Set the value of the given field. + * + * @param {object} $field + * @param {any} value + * @param {object} form + * @param {string} key + * @returns {void} + */ +function setFieldValue($field, value, form = 'body', key = 'name') { + const type = $field.attr('type'); + const identifier = $field.attr(key); + + // Early return if the field is a file input. + if (type === 'file') { + return; + } + + if (type === 'checkbox' && $field.closest('.form-switch').length) { + return $field.prop('checked', value); + } + + if (type === 'checkbox') { + const checked = _.castArray(value); + const checkboxes = $(form).find(`[${key}="${identifier}"]`); + + // Uncheck all checkboxes before checking the selected ones. + checkboxes.prop('checked', false); + + return checkboxes.filter((i, el) => checked.includes($(el).val())).prop('checked', true); + } + + if (type === 'radio') { + return $(form).find(`[${key}="${identifier}"][value="${value}"]`).prop('checked', true); + } + + if (type === 'number') { + return $field.val(+value); + } + + if ($field.is('select')) { + if ($field.hasAttr('select-query')) { + return $field.attr('select-preload-values', Array.isArray(value) ? value.join(',') : value); + } + + if (value === null || value === '') { + return $field.val(null); + } + + // Convert the value to an array if it's not already one. + value = Array.isArray(value) ? value : value.toString().split(','); + + const tomselect = $field.data('tomselect'); + + // Add saved tags that are not among the select's predefined options. + for (const val of value) { + const $option = $field.find('option').filter((i, option) => option.value === String(val)); + + if ($option.length) { + $option.attr('selected', true); + } else if ($field.hasAttr('tags')) { + $field.append(new Option(val, val, true, true)); + + if (tomselect) { + tomselect.addOption({ value: val, text: val }); + } + } + } + + // Set the value for the tom select element. + if (tomselect) { + tomselect.setValue(value); + } + + return $field.val(value); + } + + if (window.hugerte && hugerte.get($field.attr('id'))) { + return hugerte.get($field.attr('id')).setContent(value); + } + + if ($field.data('repeater')) { + return $field.data('repeater').set(value); + } + + if ($field.data('uploader')) { + return $field.data('uploader').setFiles(value); + } + + if ($field.data('picker')) { + return $field.data('picker').dates.setFromInput(value); + } + + return $field.val(value); +} + +/** + * Check if the other field matches the given value. + * + * @param {jQuery} field + * @param {string} other + * @param {any} otherValue + * @returns {boolean} + */ +function checkOtherField(field, other, otherValue) { + let $form = field.closest('form'); + + // Fallback to body if the form is not found + if ($form.length === 0) { + $form = $('body'); + } + + // Check if the other field inside a repeater item + if (field.closest('[repeater-item]').length) { + const item = field.closest('[repeater-item]'); + const otherField = item.find(`[initial-name^="${other}"]`); + + if (otherField.length) { + return getFieldValue(otherField.first(), item, 'initial-name') == otherValue; + } + } + + if ($form.find(`[name="${other}"]`).length) { + return getFieldValue($form.find(`[name="${other}"]`).first(), $form) == otherValue; + } + + return false; +} + +/* --------------------------------- + * DOM & UI Utilities + * --------------------------------- */ + +/** + * Get computed CSS property value(s) from the given element. + * + * @param {Element} element + * @param {string|string[]} properties + * @returns {string|object} + */ +function getCssProperties(element, properties) { + const styles = getComputedStyle(element); + const keys = Array.isArray(properties) ? properties : [properties]; + const values = {}; + + for (const property of keys) { + values[property] = styles.getPropertyValue(property).trim(); + } + + return Array.isArray(properties) ? values : values[properties]; +} + +/** + * Make the given element draggable. + * + * @param {string} selector + * @param {number} minDiff + */ +function makeDraggable(selector, minDiff = 5) { + const $target = $(selector); + + let isMouseDown = false, + lastX, + lastY; + + $target.on('mousedown', (e) => { + isMouseDown = true; + lastX = e.pageX; + lastY = e.pageY; + }); + + $target.on('mouseup mouseleave', () => { + isMouseDown = false; + + $target.removeClass('dragging'); + $target.css('cursor', 'initial'); + }); + + $target.on('mousemove', (e) => { + if (!isMouseDown) { + return; + } + + let diffX = e.pageX - lastX; + let diffY = e.pageY - lastY; + + $target.addClass('dragging'); + $target.css('cursor', 'grabbing'); + + if (Math.abs(diffX) > minDiff || Math.abs(diffY) > minDiff) { + $target.scrollLeft($target.scrollLeft() - diffX); + $target.scrollTop($target.scrollTop() - diffY); + lastX = e.pageX; + lastY = e.pageY; + } + }); +} + +/** + * Send a form request to the given URL. + * + * @param {string} url + * @param {object} data + * @param {string} method + */ +function formRequest(url, data = {}, method = 'POST') { + const $form = $('
', { + method: method.toUpperCase() === 'GET' ? 'GET' : 'POST', + action: url, + }); + + $form.append($('', { type: 'hidden', name: '_token', value: $('meta[name="csrf-token"]').attr('content') })); + $form.append($('', { type: 'hidden', name: '_method', value: method })); + + for (const [key, value] of Object.entries(data)) { + $form.append($('', { type: 'hidden', name: key, value: value })); + } + + $form.appendTo('body').submit(); +} + +/** + * Copy the given text to the clipboard. + * + * @param {string} text + */ +function copyToClipboard(text) { + return navigator.clipboard.writeText(text); +} + +/** + * Toggle fullscreen mode for the given element. + * + * @param {string} selector + */ +function toggleFullscreen(selector = 'html', className = 'fullscreen') { + document.requestFullscreen = document.requestFullscreen || document.webkitRequestFullscreen; + document.fullscreenElement = document.fullscreenElement || document.webkitFullscreenElement; + document.exitFullscreen = document.exitFullscreen || document.webkitExitFullscreen; + + if (document.fullscreenElement) { + document.exitFullscreen(); + $(selector).removeClass(className); + } else { + $(selector).addClass(className); + $(selector).get(0).requestFullscreen(); + } +} + +/** + * Apply selected files to the given avatar. + * + * @param {string} source + * @param {string} target + * @returns {void} + */ +function applyAvatarPreview(source, target) { + const $input = $(source); + const $preview = $(target); + const reader = new FileReader(); + + reader.addEventListener('load', () => { + $preview.css({ + backgroundImage: `url(${reader.result})`, + }); + + $preview.empty(); + }); + + reader.readAsDataURL($input.get(0).files[0]); +} + +/** + * Create a loading overlay for the given element. + * Returns `show` and `hide` functions. Shows immediately unless `show` is false. + * + * @param {object} $element + * @param {object} options + * @returns {{ show: function, hide: function }} + */ +function createLoading($element, options = {}) { + const defaultOptions = { + delay: 0, + fade: true, + lock: true, + show: true, + callbacks: { + show: () => {}, + hide: () => {}, + }, + spinner: { + size: 'md', + type: 'border', + color: null, + }, + }; + + // Merge the default options with the given options. + options = _.merge(defaultOptions, options); + + const duration = options.fade === true ? 150 : options.fade || 0; + const $elements = $.query($element); + + // Generate the HTML for the spinner. + const { type, size, color } = options.spinner; + const kind = type === 'grow' ? 'spinner-grow' : 'spinner-border'; + const classes = [kind]; + + if (size === 'sm' || size === 'lg') { + classes.push(`${kind}-${size}`); + } + + if (color) { + classes.push(`text-${color}`); + } + + spinnerHtml = `
`; + + // Define the fade function. + const fade = ($overlay, opacity, complete) => { + if (duration) { + $overlay.stop(true).animate({ opacity }, duration, complete); + } else { + complete(); + } + }; + + // Define the cleanup function. + const cleanup = ($el) => { + $el.removeClass('inline-loading') + .removeAttr('aria-busy') + .removeData('inline-loading-timer inline-loading-shown'); + + if ($el.hasAttr('inline-loading-static')) { + $el.css('position', '').removeAttr('inline-loading-static'); + } + }; + + // Define the show element function. + const showElement = ($el) => { + // Early return if the element already has a loading overlay or timer. + if ($el.children('[inline-loading]').length || $el.data('inline-loading-timer')) { + return; + } + + const apply = () => { + $el.removeData('inline-loading-timer'); + + if ($el.css('position') === 'static') { + $el.attr('inline-loading-static', true).css('position', 'relative'); + } + + const $overlay = $( + `
${spinnerHtml}
`, + ); + + $el.addClass('inline-loading').attr('aria-busy', true).append($overlay); + + if (duration) { + $overlay.css('opacity', 0); + } + + fade($overlay, 1, () => { + $el.data('inline-loading-shown', true); + options.callbacks.show(); + }); + }; + + if (options.delay) { + $el.data('inline-loading-timer', setTimeout(apply, options.delay)); + } else { + apply(); + } + }; + + // Define the hide element function. + const hideElement = ($el) => { + const timer = $el.data('inline-loading-timer'); + const shown = $el.data('inline-loading-shown'); + const $overlay = $el.children('[inline-loading]'); + + if (timer) { + clearTimeout(timer); + } + + if (!$overlay.length) { + cleanup($el); + return; + } + + fade($overlay, 0, () => { + $overlay.remove(); + cleanup($el); + + if (shown) { + options.callbacks.hide(); + } + }); + }; + + // Define the show and hide functions. + const show = () => $elements.each((_, el) => showElement($(el))); + const hide = () => $elements.each((_, el) => hideElement($(el))); + + if (options.show) { + show(); + } + + return { show, hide }; +} + +/* --------------------------------- + * Date & Time + * --------------------------------- */ + +/** + * Format the given date as a localized relative time (e.g. "5 minutes ago"). + * + * @param {string|number|Date} date + * @param {object} options + * @returns {string} + */ +function relativeTime(date, options = {}) { + const locale = options.locale || document.documentElement.lang || 'en'; + + const formatter = new Intl.RelativeTimeFormat(locale, { + numeric: options.numeric || 'always', + style: options.style || 'long', + }); + + const units = [ + ['year', 31536000], + ['month', 2592000], + ['week', 604800], + ['day', 86400], + ['hour', 3600], + ['minute', 60], + ['second', 1], + ]; + + const seconds = Math.max(1, Math.round((Date.now() - new Date(date).getTime()) / 1000)); + + for (const [unit, size] of units) { + if (seconds >= size || unit === 'second') { + return formatter.format(-Math.round(seconds / size), unit); + } + } +} + +/** + * Keep every [relative-time] element within the root updated in realtime. + * + * @param {HTMLElement} root + * @param {object} options + * @returns {number} The interval id, so it can be cleared by the caller. + */ +function liveRelativeTimes(root = document.body, options = {}) { + const update = () => { + root.querySelectorAll('time[relative-time]').forEach((element) => { + const datetime = element.getAttribute('datetime'); + + if (datetime) { + element.textContent = relativeTime(datetime, options); + } + }); + }; + + update(); + + return setInterval(update, options.interval || 1000); +} + +/* --------------------------------- + * Initialization + * --------------------------------- */ + +/** + * Initialize the given initiators. + * + * @param {string} selector + */ +function init(selector = 'body') { + const $selector = $(selector).attr('init') ? $(selector).parent() : $(selector); + + // Initialize non-initialized initiators. + $selector.find('[init]:not([initialized])').each(function () { + let inits = $(this).attr('init').split(' '); + + // Trigger before all initiators. + $selector.trigger('init.before'); + + for (const init of inits) { + if (!window.__inits[init]) { + console.error(`Initiator "${init}" is not defined.`); + continue; + } + + // Trigger before the initiator. + $selector.trigger(`init.before.${init}`); + + const options = this.hasAttribute(init) ? stringToPrimitive($(this).attr(init)) : {}; + window.__inits[init](this, options); // Call the initiator with the given options. + + // Trigger after the initiator. + $selector.trigger(`init.after.${init}`); + } + + // Trigger after all initiators. + $selector.trigger('init.after'); + + $(this).attr('initialized', true); + }); + + // Watch for visibility changes. + if (RedotVisibility.instance) RedotVisibility.instance.watch(); +} + +/** + * Get the options from the given selector. + * + * @param {string} selector + * @param {string} prefix + * @param {boolean} camelCase + * @returns {object} + */ +function getOptionsFromSelector(selector, prefix, camelCase = true) { + const attributes = $(selector).get(0).attributes; + const options = {}; + + for (const attribute of attributes) { + if (!attribute.name.startsWith(prefix)) { + continue; + } + + let key = attribute.name.replace(prefix, ''); + let value = stringToPrimitive(attribute.value); + + // Convert the key to camel case if needed. + if (camelCase) key = key.replace(/-([a-z])/g, (g) => g[1].toUpperCase()); + + _.set(options, key, value); + } + + return options; +} diff --git a/src/Foundation/public/js/runtime.js b/src/Foundation/public/js/runtime.js new file mode 100644 index 0000000..b50f37c --- /dev/null +++ b/src/Foundation/public/js/runtime.js @@ -0,0 +1,137 @@ +/* --------------------------------- + * Observe initiators + * --------------------------------- */ + +$(document).ready(() => { + // Initialize the visibility plugin. + RedotVisibility.init(); + + // Watch for DOM changes and call the init function. + const observer = new MutationObserver(() => { + window.init(); + }); + + // Listen for DOM changes and call the init function. + observer.observe(document.body, { + childList: true, + subtree: true, + }); + + // Call the init function on page load. + window.init(); +}); + +/* --------------------------------- + * Anchor links + * --------------------------------- */ + +// The tag makes bare "#hash" hrefs resolve against the site root, +// which triggers a full navigation. Handle same-page anchors manually. +// Add the `disable-anchor` attribute to a link to opt out of this behavior. +$(document).on('click', 'a[href^="#"]:not([data-bs-toggle]):not([disable-anchor])', (event) => { + if (event.isDefaultPrevented()) return; + if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return; + + const hash = $(event.currentTarget).attr('href'); + + // A bare "#" has no target, but left alone it would resolve against the + // tag and navigate to the site root — swallow it instead. + if (hash === '#') return event.preventDefault(); + + const target = document.getElementById(hash.slice(1)); + if (!target) return; + + event.preventDefault(); + target.scrollIntoView({ behavior: 'smooth' }); + history.pushState(null, '', location.pathname + location.search + hash); +}); + +/* --------------------------------- + * Bootbox + * --------------------------------- */ + +bootbox.setDefaults({ + animate: true, + backdrop: 'static', + centerVertical: true, + container: 'body', +}); + +/* --------------------------------- + * Glare + * --------------------------------- */ + +$(document).on('click', '[data-lightbox]', (event) => { + if (event.isDefaultPrevented()) return; + if (event.button !== 0 || event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) return; + + event.preventDefault(); + Glare.open([event.currentTarget], { defaultType: 'iframe' }); +}); + +/* --------------------------------- + * Ajax + * --------------------------------- */ + +$.ajaxSetup({ + headers: { + 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'), + }, + statusCode: { + 419: () => { + bootbox.dialog({ + title: __('Session Expired'), + message: __('Your session has expired. Please refresh the page to continue.'), + onEscape: false, + buttons: { + confirm: { + label: __('Refresh'), + className: 'btn-primary', + callback: () => window.location.reload(), + }, + }, + }); + }, + }, +}); + +/* --------------------------------- + * Redot Visibility + * --------------------------------- */ + +// Disable validation on hidden elements +$(document).on('visibility:updated', '[visible-when]', (event, visible) => { + const $container = $(event.target); + const $targets = $container.is('[validation]') ? $container : $container.find('[validation]'); + + if (visible) { + $targets.removeAttr('disable-validation'); + } else { + $targets.attr('disable-validation', true); + } +}); + +/* --------------------------------- + * Redot Validator + * --------------------------------- */ + +// Disable HTML5 validation +$('form').attr('novalidate', true); + +$(document).on('submit', 'form:not([disable-validation])', (event) => { + event.preventDefault(); + + const $form = $(event.target); + const isValid = validateForm($form, true); + + // No errors, submit the form + if (isValid) { + const $submit = $form.find('[type="submit"]'); + const $spinner = $(''); + + $submit.prepend($spinner); + $submit.prop('disabled', true); + + return event.target.submit(); + } +}); diff --git a/src/Foundation/public/js/themer.js b/src/Foundation/public/js/themer.js new file mode 100644 index 0000000..40711b8 --- /dev/null +++ b/src/Foundation/public/js/themer.js @@ -0,0 +1,42 @@ +(() => { + 'use strict'; + + // The key to use when storing the theme in localStorage + window.themerKey = window.themerKey || 'theme'; + window.themeConfig = window.themeConfig || {}; + + const config = Object.assign( + { + theme: window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light', + base: 'default', + font: 'sans-serif', + primary: 'blue', + radius: 1, + }, + window.themeConfig, + ); + + for (const key in config) { + const storedTheme = localStorage.getItem(`${themerKey}-${key}`); + const selectedValue = storedTheme ? storedTheme : config[key]; + + // Set the attribute on the document element + document.documentElement.setAttribute(`data-bs-${key === 'theme' ? 'theme' : 'theme-' + key}`, selectedValue); + } + + document.addEventListener('DOMContentLoaded', () => { + document.querySelectorAll('[set-theme]').forEach((element) => { + element.addEventListener('click', (event) => { + event.preventDefault(); + + let theme = element.getAttribute('set-theme'); + + document.documentElement.setAttribute('data-bs-theme', theme); + localStorage.setItem(`${themerKey}-theme`, theme); + + // Dispatch a custom event to let other scripts know the theme has changed + document.dispatchEvent(new CustomEvent('theme:changed')); + }); + }); + }); +})(); diff --git a/src/Foundation/public/libraries/apexcharts/apexcharts.min.js b/src/Foundation/public/libraries/apexcharts/apexcharts.min.js new file mode 100644 index 0000000..a29e53d --- /dev/null +++ b/src/Foundation/public/libraries/apexcharts/apexcharts.min.js @@ -0,0 +1,5 @@ +/*! + * ApexCharts v7.3.0 + * (c) 2018-2026 ApexCharts + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).ApexCharts=e()}(this,function(){"use strict";var t=Object.defineProperty,e=Object.defineProperties,i=Object.getOwnPropertyDescriptors,s=Object.getOwnPropertySymbols,a=Object.prototype.hasOwnProperty,r=Object.prototype.propertyIsEnumerable,n=(e,i,s)=>i in e?t(e,i,{enumerable:!0,configurable:!0,writable:!0,value:s}):e[i]=s,o=(t,e)=>{for(var i in e||(e={}))a.call(e,i)&&n(t,i,e[i]);if(s)for(var i of s(e))r.call(e,i)&&n(t,i,e[i]);return t},l=(t,s)=>e(t,i(s)),h=(t,e,i)=>n(t,"symbol"!=typeof e?e+"":e,i),c=(t,e,i)=>new Promise((s,a)=>{var r=t=>{try{o(i.next(t))}catch(t){a(t)}},n=t=>{try{o(i.throw(t))}catch(t){a(t)}},o=t=>t.done?s(t.value):Promise.resolve(t.value).then(r,n);o((i=i.apply(t,e)).next())});class d{static isSSR(){return"undefined"==typeof window||"undefined"==typeof document}static isBrowser(){return!this.isSSR()}static hasAPI(t){return!this.isSSR()&&void 0!==window[t]}static getApex(){return"undefined"!=typeof window&&window.Apex?window.Apex:"undefined"!=typeof global&&global.Apex?global.Apex:{}}}class p{constructor(t,e=null){this.nodeName=t,this.namespaceURI=e,this.attributes=new Map,this.children=[],this.textContent="",this.style={},this.classList=new u,this.parentNode=null,this._ssrWidth=void 0,this._ssrHeight=void 0,this._ssrMode=void 0}setAttribute(t,e){this.attributes.set(t,e)}getAttribute(t){return this.attributes.get(t)}removeAttribute(t){this.attributes.delete(t)}hasAttribute(t){return this.attributes.has(t)}appendChild(t){if(t&&t!==this){if(t.parentNode&&t.parentNode!==this)t.parentNode.removeChild(t);else if(t.parentNode===this){const e=this.children.indexOf(t);-1!==e&&this.children.splice(e,1)}t.parentNode=this,this.children.push(t)}return t}removeChild(t){const e=this.children.indexOf(t);return-1!==e&&(this.children.splice(e,1),t.parentNode=null),t}insertBefore(t,e){if(!e)return this.appendChild(t);if(t.parentNode&&t.parentNode!==this)t.parentNode.removeChild(t);else if(t.parentNode===this){const e=this.children.indexOf(t);-1!==e&&this.children.splice(e,1)}const i=this.children.indexOf(e);return-1!==i&&(t.parentNode=this,this.children.splice(i,0,t)),t}cloneNode(t=!1){const e=new p(this.nodeName,this.namespaceURI);return e.textContent=this.textContent,this.attributes.forEach((t,i)=>{e.attributes.set(i,t)}),Object.assign(e.style,this.style),t&&this.children.forEach(t=>{t.cloneNode&&e.appendChild(t.cloneNode(!0))}),e}getBoundingClientRect(){return{width:this._ssrWidth||0,height:this._ssrHeight||0,top:0,left:0,right:this._ssrWidth||0,bottom:this._ssrHeight||0,x:0,y:0}}getRootNode(){let t=this;for(;t.parentNode;)t=t.parentNode;return t}querySelector(){return null}querySelectorAll(){return[]}getElementsByClassName(){return[]}addEventListener(){}removeEventListener(){}get childNodes(){return this.children}toString(){let t="";if(this.attributes.forEach((e,i)=>{t+=` ${i}="${e}"`}),0===this.children.length&&!this.textContent)return`<${this.nodeName}${t}/>`;const e=this.children.map(t=>t.toString()).join("");return`<${this.nodeName}${t}>${this.textContent}${e}`}get innerHTML(){return this.children.map(t=>t.toString()).join("")}set innerHTML(t){this.children=[],this.textContent=t}get outerHTML(){return this.toString()}get isConnected(){return!0}}class u{constructor(){this.classes=new Set}add(...t){t.forEach(t=>this.classes.add(t))}remove(...t){t.forEach(t=>this.classes.delete(t))}contains(t){return this.classes.has(t)}toggle(t,e){return!0===e?(this.classes.add(t),!0):!1===e||this.classes.has(t)?(this.classes.delete(t),!1):(this.classes.add(t),!0)}toString(){return Array.from(this.classes).join(" ")}}class g{constructor(){this.SVGNS="http://www.w3.org/2000/svg",this.XLINKNS="http://www.w3.org/1999/xlink"}createElementNS(t,e){return new p(e,t)}createTextNode(t){const e={nodeName:"#text",nodeType:3,textContent:t,toString:()=>e.textContent};return e}querySelector(){return null}querySelectorAll(){return[]}getComputedStyle(){return{}}getBoundingClientRect(t){return t&&t.getBoundingClientRect?t.getBoundingClientRect():{width:0,height:0,top:0,left:0,right:0,bottom:0,x:0,y:0}}createXMLSerializer(){return{serializeToString:t=>t.toString?t.toString():""}}createDOMParser(){return{parseFromString(t,e){const i=new p("root");return i.innerHTML=t,{documentElement:i}}}}}let f=null,x=null,m=null;class b{static init(){d.isSSR()&&!f&&(f=new g)}static createElement(t){return d.isSSR()?(f||this.init(),f.createElementNS(null,t)):document.createElement(t)}static createElementNS(t,e){return d.isSSR()?(f||this.init(),f.createElementNS(t,e)):document.createElementNS(t,e)}static createTextNode(t){return d.isSSR()?(f||this.init(),f.createTextNode(t)):document.createTextNode(t)}static querySelector(t){return d.isSSR()?null:document.querySelector(t)}static querySelectorAll(t){return d.isSSR()?[]:document.querySelectorAll(t)}static getComputedStyle(t){return d.isSSR()?{}:window.getComputedStyle(t)}static matchMedia(t){if(d.isSSR()||"function"!=typeof window.matchMedia)return null;try{return window.matchMedia(t)}catch(t){return null}}static getBoundingClientRect(t){return d.isSSR()?(f||this.init(),f.getBoundingClientRect(t)):t?t.getBoundingClientRect():{width:0,height:0,top:0,left:0,right:0,bottom:0,x:0,y:0}}static getXMLSerializer(){return d.isSSR()?(f||this.init(),x||(x=f.createXMLSerializer()),x):(x||(x=new XMLSerializer),x)}static getDOMParser(){return d.isSSR()?(f||this.init(),m||(m=f.createDOMParser()),m):(m||(m=new DOMParser),m)}static addWindowEventListener(t,e,i){d.isBrowser()&&window.addEventListener(t,e,i)}static removeWindowEventListener(t,e,i){d.isBrowser()&&window.removeEventListener(t,e,i)}static requestAnimationFrame(t){return d.isBrowser()?window.requestAnimationFrame(t):(t(0),null)}static cancelAnimationFrame(t){d.isBrowser()&&t&&window.cancelAnimationFrame(t)}static elementExists(t){return!!t&&(d.isSSR()?!0===t._ssrMode||void 0!==t.nodeName:!!t.getRootNode&&(t.getRootNode({composed:!0})===document||t.isConnected))}static getWindow(){return d.isBrowser()?window:null}static getDocument(){return d.isBrowser()?document:null}static _getShim(){return f}static _resetShim(){f=null,x=null,m=null}}const y=new WeakMap;let w=0,v=class t{static isObject(t){return t&&"object"==typeof t&&!Array.isArray(t)}static is(t,e){return Object.prototype.toString.call(e)==="[object "+t+"]"}static isSafari(){return d.isBrowser()&&/^((?!chrome|android).)*safari/i.test(navigator.userAgent)}static extend(t,e){if(!this.isObject(t)&&this.isObject(e))return this.clone(e);const i=Object.assign({},t);return this.isObject(t)&&this.isObject(e)&&Object.keys(e).forEach(s=>{this.isObject(e[s])?s in t?i[s]=this.extend(t[s],e[s]):Object.assign(i,{[s]:e[s]}):Object.assign(i,{[s]:e[s]})}),i}static copySeriesShallow(t){return Array.isArray(t)?t.map(t=>this.isObject(t)?o({},t):t):t}static extendArray(e,i){const s=[];return e.map(e=>{s.push(t.extend(i,e))}),e=s}static monthMod(t){return t%12}static clone(t,e=new WeakMap,i=!1){if(null===t||"object"!=typeof t)return t;if(e.has(t))return e.get(t);let s;if(Array.isArray(t))if(i)s=t.slice();else{s=[],e.set(t,s);for(let i=0;i{if("function"!=typeof e)return e;let i=y.get(e);return void 0===i&&(i=++w,y.set(e,i)),`__apx_fn_${i}`})}static shallowEqual(t,e){if(t===e)return!0;if(!t||!e)return!1;if("object"!=typeof t||"object"!=typeof e)return t===e;const i=Object.keys(t),s=Object.keys(e);if(i.length!==s.length)return!1;for(const s of i)if(t[s]!==e[s])return!1;return!0}static log10(t){return Math.log(t)/Math.LN10}static roundToBase10(t){return Math.pow(10,Math.floor(Math.log10(t)))}static roundToBase(t,e){return Math.pow(e,Math.floor(Math.log(t)/Math.log(e)))}static parseNumber(t){return"number"==typeof t||null===t?t:parseFloat(t)}static stripNumber(t,e=2){return Number.isInteger(t)?t:parseFloat(t.toPrecision(e))}static randomId(){return(Math.random()+1).toString(36).substring(4)}static noExponents(t){return t.toString().includes("e")?Math.round(t):t}static elementExists(t){return!(!t||!t.isConnected)}static getDimensions(t){if(!t)return[0,0];if(d.isSSR())return[t._ssrWidth||400,t._ssrHeight||300];let e;try{e=getComputedStyle(t,null)}catch(e){return[t.clientWidth||0,t.clientHeight||0]}let i=t.clientWidth,s=t.clientHeight;if(!i||!s){const e=t.getBoundingClientRect();i=i||e.width,s=s||e.height}return s-=parseFloat(e.paddingTop)+parseFloat(e.paddingBottom),i-=parseFloat(e.paddingLeft)+parseFloat(e.paddingRight),[i,s]}static getBoundingClientRect(t){if(!t)return{top:0,right:0,bottom:0,left:0,width:0,height:0,x:0,y:0};if(d.isSSR())return b.getBoundingClientRect(t);const e=t.getBoundingClientRect();return{top:e.top,right:e.right,bottom:e.bottom,left:e.left,width:t.clientWidth,height:t.clientHeight,x:e.left,y:e.top}}static getLargestStringFromArr(t){return t.reduce((t,e)=>(Array.isArray(e)&&(e=e.reduce((t,e)=>t.length>e.length?t:e)),t.length>e.length?t:e),0)}static hexToRgba(t="#999999",e=.6){"#"!==t.substring(0,1)&&(t="#999999");const i=t.replace("#",""),s=i.match(new RegExp("(.{"+i.length/3+"})","g"))||[];for(let t=0;tt+t).join("")),/^[0-9a-fA-F]{6}$/.test(e)?[parseInt(e.slice(0,2),16),parseInt(e.slice(2,4),16),parseInt(e.slice(4,6),16)]:null}static relativeLuminance([t,e,i]){const s=t=>{const e=t/255;return e<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4)};return.2126*s(t)+.7152*s(e)+.0722*s(i)}static getContrastRatio(e,i){const s=t.parseHex(e),a=t.parseHex(i);if(!s||!a)return 0;const r=t.relativeLuminance(s),n=t.relativeLuminance(a);return(Math.max(r,n)+.05)/(Math.min(r,n)+.05)}static rgb2hex(t){return(t=t.match(/^rgba?[\s+]?\([\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?,[\s+]?(\d+)[\s+]?/i))&&4===t.length?"#"+("0"+parseInt(t[1],10).toString(16)).slice(-2)+("0"+parseInt(t[2],10).toString(16)).slice(-2)+("0"+parseInt(t[3],10).toString(16)).slice(-2):""}shadeRGBColor(t,e){const i=e.split(","),s=t<0?0:255,a=t<0?-1*t:t,r=parseInt(i[0].slice(4),10),n=parseInt(i[1],10),o=parseInt(i[2],10);return"rgb("+(Math.round((s-r)*a)+r)+","+(Math.round((s-n)*a)+n)+","+(Math.round((s-o)*a)+o)+")"}shadeHexColor(t,e){const i=parseInt(e.slice(1),16),s=t<0?0:255,a=t<0?-1*t:t,r=i>>16,n=i>>8&255,o=255&i;return"#"+(16777216+65536*(Math.round((s-r)*a)+r)+256*(Math.round((s-n)*a)+n)+(Math.round((s-o)*a)+o)).toString(16).slice(1)}shadeColor(e,i){return t.isColorHex(i)?this.shadeHexColor(e,i):this.shadeRGBColor(e,i)}static isColorHex(t){return/(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)|(^#[0-9A-F]{8}$)/i.test(t)}static isCSSVariable(t){if("string"!=typeof t)return!1;const e=t.trim();return e.startsWith("var(")&&e.endsWith(")")}static getThemeColor(e){if(!t.isCSSVariable(e))return e;if(d.isSSR())return e;const i=document.createElement("div");let s;i.style.cssText="position:fixed; left: -9999px; visibility:hidden;",i.style.color=e,document.body.appendChild(i);try{s=window.getComputedStyle(i).color}finally{i.parentNode&&i.parentNode.removeChild(i)}return s}static applyOpacityToColor(t,e){const i=Number(e);if(!Number.isFinite(i))return t;if(i<=0)return"transparent";if(i>=1)return t;return`color-mix(in srgb, ${t} ${Math.round(100*i)}%, transparent)`}static getPolygonPos(t,e){const i=[],s=2*Math.PI/e;for(let a=0;a{}[\]\\/]/gi,e),i}static negToZero(t){return t<0?0:t}static moveIndexInArray(t,e,i){if(i>=t.length){let e=i-t.length+1;for(;e--;)t.push(void 0)}return t.splice(i,0,t.splice(e,1)[0]),t}static extractNumber(t){return parseFloat(t.replace(/[^\d.]*/g,""))}static findAncestor(t,e){for(;(t=t.parentElement)&&!t.classList.contains(e););return t}static setELstyles(t,e){for(const i in e)Object.prototype.hasOwnProperty.call(e,i)&&(t.style[i]=e[i])}static preciseAddition(t,e){const i=(String(t).split(".")[1]||"").length,s=(String(e).split(".")[1]||"").length,a=Math.pow(10,Math.max(i,s));return(Math.round(t*a)+Math.round(e*a))/a}static isNumber(t){return!isNaN(t)&&parseFloat(String(Number(t)))===t&&!isNaN(parseInt(t,10))}static isFloat(t){return Number(t)===t&&t%1!=0}static isMsEdge(){if(d.isSSR())return!1;const t=window.navigator.userAgent,e=t.indexOf("Edge/");return e>0&&parseInt(t.substring(e+5,t.indexOf(".",e)),10)}static getGCD(t,e,i=7){let s=Math.pow(10,i-Math.floor(Math.log10(Math.max(t,e))));for(s>1?(t=Math.round(Math.abs(t)*s),e=Math.round(Math.abs(e)*s)):s=1;e;){const i=e;e=t%e,t=i}return t/s}static getPrimeFactors(t){const e=[];let i=2;for(;t>=2;)t%i==0?(e.push(i),t/=i):i++;return e}static mod(t,e,i=7){const s=Math.pow(10,i-Math.floor(Math.log10(Math.max(t,e))));return(t=Math.round(Math.abs(t)*s))%(e=Math.round(Math.abs(e)*s))/s}};class A{constructor(t){this.w=t,this.months31=[1,3,5,7,8,10,12],this.months30=[2,4,6,9,11],this.daysCntOfYear=[0,31,59,90,120,151,181,212,243,273,304,334]}isValidDate(t){return"number"!=typeof t&&!isNaN(this.parseDate(t))}getTimeStamp(t){if(isNaN(Date.parse(t)))return t;return this.w.config.xaxis.labels.datetimeUTC?new Date(new Date(t).toISOString().substr(0,25)).getTime():new Date(t).getTime()}getDate(t){return this.w.config.xaxis.labels.datetimeUTC?new Date(new Date(t).toUTCString()):new Date(t)}parseDate(t){const e=Date.parse(t);if(!isNaN(e))return this.getTimeStamp(t);if("string"!=typeof t)return NaN;let i=Date.parse(t.replace(/-/g,"/").replace(/[a-z]+/gi," "));return i=this.getTimeStamp(i),i}parseDateWithTimezone(t){return Date.parse(t.replace(/-/g,"/").replace(/[a-z]+/gi," "))}formatDate(t,e){const i=this.w.globals.locale,s=this.w.config.xaxis.labels.datetimeUTC,a=["\0",...i.months],r=["\x01",...i.shortMonths],n=["\x02",...i.days],o=["\x03",...i.shortDays];function l(t,e=2){let i=t+"";for(;i.length12?p-12:0===p?12:p;e=(e=(e=(e=e.replace(/(^|[^\\])HH+/g,"$1"+l(p))).replace(/(^|[^\\])H/g,"$1"+p)).replace(/(^|[^\\])hh+/g,"$1"+l(u))).replace(/(^|[^\\])h/g,"$1"+u);const g=s?t.getUTCMinutes():t.getMinutes();e=(e=e.replace(/(^|[^\\])mm+/g,"$1"+l(g))).replace(/(^|[^\\])m/g,"$1"+g);const f=s?t.getUTCSeconds():t.getSeconds();e=(e=e.replace(/(^|[^\\])ss+/g,"$1"+l(f))).replace(/(^|[^\\])s/g,"$1"+f);let x=s?t.getUTCMilliseconds():t.getMilliseconds();e=e.replace(/(^|[^\\])fff+/g,"$1"+l(x,3)),x=Math.round(x/10),e=e.replace(/(^|[^\\])ff/g,"$1"+l(x)),x=Math.round(x/10);const m=p<12?"AM":"PM";e=(e=(e=e.replace(/(^|[^\\])f/g,"$1"+x)).replace(/(^|[^\\])TT+/g,"$1"+m)).replace(/(^|[^\\])T/g,"$1"+m.charAt(0));const b=m.toLowerCase();e=(e=e.replace(/(^|[^\\])tt+/g,"$1"+b)).replace(/(^|[^\\])t/g,"$1"+b.charAt(0));let y=-t.getTimezoneOffset(),w=s||!y?"Z":y>0?"+":"-";if(!s){y=Math.abs(y);const t=y%60;w+=l(Math.floor(y/60))+":"+l(t)}e=e.replace(/(^|[^\\])K/g,"$1"+w);const v=(s?t.getUTCDay():t.getDay())+1;return e=(e=(e=(e=(e=e.replace(new RegExp(n[0],"g"),n[v])).replace(new RegExp(o[0],"g"),o[v])).replace(new RegExp(a[0],"g"),a[c])).replace(new RegExp(r[0],"g"),r[c])).replace(/\\(.)/g,"$1")}getTimeUnitsfromTimestamp(t,e){const i=this.w;void 0!==i.config.xaxis.min&&(t=i.config.xaxis.min),void 0!==i.config.xaxis.max&&(e=i.config.xaxis.max);const s=this.getDate(t),a=this.getDate(e),r=this.formatDate(s,"yyyy MM dd HH mm ss fff").split(" "),n=this.formatDate(a,"yyyy MM dd HH mm ss fff").split(" ");return{minMillisecond:parseInt(r[6],10),maxMillisecond:parseInt(n[6],10),minSecond:parseInt(r[5],10),maxSecond:parseInt(n[5],10),minMinute:parseInt(r[4],10),maxMinute:parseInt(n[4],10),minHour:parseInt(r[3],10),maxHour:parseInt(n[3],10),minDate:parseInt(r[2],10),maxDate:parseInt(n[2],10),minMonth:parseInt(r[1],10)-1,maxMonth:parseInt(n[1],10)-1,minYear:parseInt(r[0],10),maxYear:parseInt(n[0],10)}}isLeapYear(t){return t%4==0&&t%100!=0||t%400==0}calculcateLastDaysOfMonth(t,e,i){return this.determineDaysOfMonths(t,e)-i}determineDaysOfYear(t){let e=365;return this.isLeapYear(t)&&(e=366),e}determineRemainingDaysOfYear(t,e,i){let s=this.daysCntOfYear[e]+i;return e>1&&this.isLeapYear(t)&&s++,s}determineDaysOfMonths(t,e){let i=30;switch(t=v.monthMod(t),!0){case this.months30.indexOf(t)>-1:2===t&&(i=this.isLeapYear(e)?29:28);break;case this.months31.indexOf(t)>-1:default:i=31}return i}getDateFields(t,e){const i=new Date(t);return e?{year:i.getUTCFullYear(),month:i.getUTCMonth(),date:i.getUTCDate(),hour:i.getUTCHours(),minute:i.getUTCMinutes(),second:i.getUTCSeconds(),ms:i.getUTCMilliseconds(),weekday:i.getUTCDay()}:{year:i.getFullYear(),month:i.getMonth(),date:i.getDate(),hour:i.getHours(),minute:i.getMinutes(),second:i.getSeconds(),ms:i.getMilliseconds(),weekday:i.getDay()}}addInterval(t,e,i,s){const a=new Date(t);if(s)switch(e){case"year":a.setUTCFullYear(a.getUTCFullYear()+i);break;case"month":a.setUTCMonth(a.getUTCMonth()+i);break;case"week":a.setUTCDate(a.getUTCDate()+7*i);break;case"day":a.setUTCDate(a.getUTCDate()+i);break;case"hour":a.setUTCHours(a.getUTCHours()+i);break;case"minute":a.setUTCMinutes(a.getUTCMinutes()+i);break;case"second":a.setUTCSeconds(a.getUTCSeconds()+i)}else switch(e){case"year":a.setFullYear(a.getFullYear()+i);break;case"month":a.setMonth(a.getMonth()+i);break;case"week":a.setDate(a.getDate()+7*i);break;case"day":a.setDate(a.getDate()+i);break;case"hour":a.setHours(a.getHours()+i);break;case"minute":a.setMinutes(a.getMinutes()+i);break;case"second":a.setSeconds(a.getSeconds()+i)}return a.getTime()}ceilToBoundary(t,e,i,s){const a=new Date(t);if(s)switch(e){case"second":{const e=a.getUTCSeconds(),s=Math.ceil(e/i)*i;return s===e&&0===a.getUTCMilliseconds()?t:(a.setUTCMilliseconds(0),a.setUTCSeconds(s),a.getTime())}case"minute":{const e=a.getUTCMinutes(),s=Math.ceil(e/i)*i;return s===e&&0===a.getUTCSeconds()&&0===a.getUTCMilliseconds()?t:(a.setUTCMilliseconds(0),a.setUTCSeconds(0),a.setUTCMinutes(s),a.getTime())}case"hour":{const e=a.getUTCHours(),s=Math.ceil(e/i)*i;return s===e&&0===a.getUTCMinutes()&&0===a.getUTCSeconds()&&0===a.getUTCMilliseconds()?t:(a.setUTCMilliseconds(0),a.setUTCSeconds(0),a.setUTCMinutes(0),a.setUTCHours(s),a.getTime())}case"day":return 0===a.getUTCHours()&&0===a.getUTCMinutes()&&0===a.getUTCSeconds()&&0===a.getUTCMilliseconds()?t:(a.setUTCMilliseconds(0),a.setUTCSeconds(0),a.setUTCMinutes(0),a.setUTCHours(0),a.setUTCDate(a.getUTCDate()+1),a.getTime());case"week":{const e=6048e5,s=Date.UTC(1970,0,5);a.setUTCMilliseconds(0),a.setUTCSeconds(0),a.setUTCMinutes(0),a.setUTCHours(0);const r=a.getTime(),n=Math.ceil((r-s)/e),o=s+Math.ceil(n/i)*i*e;return o>=t?o:o+i*e}case"month":{const e=a.getUTCMonth(),s=Math.ceil(e/i)*i;return s===e&&1===a.getUTCDate()&&0===a.getUTCHours()&&0===a.getUTCMinutes()&&0===a.getUTCSeconds()&&0===a.getUTCMilliseconds()?t:(a.setUTCMilliseconds(0),a.setUTCSeconds(0),a.setUTCMinutes(0),a.setUTCHours(0),a.setUTCDate(1),a.setUTCMonth(s),a.getTime())}case"year":{const e=a.getUTCFullYear(),s=Math.ceil(e/i)*i;return s===e&&0===a.getUTCMonth()&&1===a.getUTCDate()&&0===a.getUTCHours()&&0===a.getUTCMinutes()&&0===a.getUTCSeconds()&&0===a.getUTCMilliseconds()?t:Date.UTC(s,0,1)}}else switch(e){case"second":{const e=a.getSeconds(),s=Math.ceil(e/i)*i;return s===e&&0===a.getMilliseconds()?t:(a.setMilliseconds(0),a.setSeconds(s),a.getTime())}case"minute":{const e=a.getMinutes(),s=Math.ceil(e/i)*i;return s===e&&0===a.getSeconds()&&0===a.getMilliseconds()?t:(a.setMilliseconds(0),a.setSeconds(0),a.setMinutes(s),a.getTime())}case"hour":{const e=a.getHours(),s=Math.ceil(e/i)*i;return s===e&&0===a.getMinutes()&&0===a.getSeconds()&&0===a.getMilliseconds()?t:(a.setMilliseconds(0),a.setSeconds(0),a.setMinutes(0),a.setHours(s),a.getTime())}case"day":return 0===a.getHours()&&0===a.getMinutes()&&0===a.getSeconds()&&0===a.getMilliseconds()?t:(a.setMilliseconds(0),a.setSeconds(0),a.setMinutes(0),a.setHours(0),a.setDate(a.getDate()+1),a.getTime());case"week":{const e=6048e5,s=new Date(1970,0,5).getTime();a.setMilliseconds(0),a.setSeconds(0),a.setMinutes(0),a.setHours(0);const r=a.getTime(),n=Math.ceil((r-s)/e),o=s+Math.ceil(n/i)*i*e;return o>=t?o:o+i*e}case"month":{const e=a.getMonth(),s=Math.ceil(e/i)*i;return s===e&&1===a.getDate()&&0===a.getHours()&&0===a.getMinutes()&&0===a.getSeconds()&&0===a.getMilliseconds()?t:(a.setMilliseconds(0),a.setSeconds(0),a.setMinutes(0),a.setHours(0),a.setDate(1),a.setMonth(s),a.getTime())}case"year":{const e=a.getFullYear(),s=Math.ceil(e/i)*i;return s===e&&0===a.getMonth()&&1===a.getDate()&&0===a.getHours()&&0===a.getMinutes()&&0===a.getSeconds()&&0===a.getMilliseconds()?t:new Date(s,0,1).getTime()}}return t}isAtBoundary(t,e,i){const s=this.getDateFields(t,i);switch(e){case"year":return 0===s.month&&1===s.date&&0===s.hour&&0===s.minute&&0===s.second&&0===s.ms;case"month":return 1===s.date&&0===s.hour&&0===s.minute&&0===s.second&&0===s.ms;case"day":return 0===s.hour&&0===s.minute&&0===s.second&&0===s.ms;case"hour":return 0===s.minute&&0===s.second&&0===s.ms;case"minute":return 0===s.second&&0===s.ms;case"second":return 0===s.ms}return!1}}class S{constructor(t){this.w=t,this.tooltipKeyFormat="dd MMM"}xLabelFormat(t,e,i,s){const a=this.w;if("datetime"===a.config.xaxis.type&&void 0===a.config.xaxis.labels.formatter&&void 0===a.config.tooltip.x.formatter){const t=new A(this.w);return t.formatDate(t.getDate(e),a.config.tooltip.x.format)}return t(e,i,s)}defaultGeneralFormatter(t){return Array.isArray(t)?t.map(t=>t):t}defaultYFormatter(t,e){const i=this.w;if(v.isNumber(t))if(0!==i.globals.yValueDecimal)t=t.toFixed(void 0!==e.decimalsInFloat?e.decimalsInFloat:i.globals.yValueDecimal);else{const e=t.toFixed(0);t=Number(e)===t?e:t.toFixed(1)}return t}setLabelFormatters(){const t=this.w,e=t.formatters;return e.xaxisTooltipFormatter=t=>this.defaultGeneralFormatter(t),e.ttKeyFormatter=t=>this.defaultGeneralFormatter(t),e.ttZFormatter=t=>t,e.legendFormatter=t=>this.defaultGeneralFormatter(t),void 0!==t.config.xaxis.labels.formatter?e.xLabelFormatter=t.config.xaxis.labels.formatter:e.xLabelFormatter=e=>{if(v.isNumber(e)){if(!t.config.xaxis.convertedCatToNumeric&&"numeric"===t.config.xaxis.type){if(v.isNumber(t.config.xaxis.decimalsInFloat))return e.toFixed(t.config.xaxis.decimalsInFloat);{const i=t.globals.maxX-t.globals.minX;if(i>0){const t=i/10,s=Math.max(0,-Math.floor(Math.log10(t)));return e.toFixed(s)}return e.toFixed(0)}}if(t.globals.isBarHorizontal){if(t.globals.maxY-t.globals.minY<4)return e.toFixed(1)}return e.toFixed(0)}return e},"function"==typeof t.config.tooltip.x.formatter?e.ttKeyFormatter=t.config.tooltip.x.formatter:e.ttKeyFormatter=e.xLabelFormatter,"function"==typeof t.config.xaxis.tooltip.formatter&&(e.xaxisTooltipFormatter=t.config.xaxis.tooltip.formatter),(Array.isArray(t.config.tooltip.y)||void 0!==t.config.tooltip.y.formatter)&&(e.ttVal=t.config.tooltip.y),void 0!==t.config.tooltip.z.formatter&&(e.ttZFormatter=t.config.tooltip.z.formatter),void 0!==t.config.legend.formatter&&(e.legendFormatter=t.config.legend.formatter),e.yLabelFormatters=[],t.config.yaxis.forEach((i,s)=>{if(void 0!==i.labels.formatter)e.yLabelFormatters[s]=i.labels.formatter;else if("violin"===t.config.chart.type){const i=t=>"number"==typeof t&&isFinite(t)?""+Math.round(100*t)/100:t;e.yLabelFormatters[s]=e=>t.globals.xyCharts?Array.isArray(e)?e.map(i):i(e):e}else e.yLabelFormatters[s]=e=>t.globals.xyCharts?Array.isArray(e)?e.map(t=>this.defaultYFormatter(t,i)):this.defaultYFormatter(e,i):e}),t.globals}heatmapLabelFormatters(){const t=this.w;if("heatmap"===t.config.chart.type){t.globals.yAxisScale[0].result=t.seriesData.seriesNames.slice();const e=t.seriesData.seriesNames.reduce((t,e)=>t.length>e.length?t:e,0);t.globals.yAxisScale[0].niceMax=e,t.globals.yAxisScale[0].niceMin=e}}}const C={name:"en",options:{months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],toolbar:{exportToSVG:"Download SVG",exportToPNG:"Download PNG",exportToCSV:"Download CSV",menu:"Menu",selection:"Selection",selectionZoom:"Selection Zoom",zoomIn:"Zoom In",zoomOut:"Zoom Out",pan:"Panning",reset:"Reset Zoom",measure:"Measure"}}};class k{constructor(){this.yAxis={show:!0,showAlways:!1,showForNullSeries:!0,seriesName:void 0,opposite:!1,reversed:!1,logarithmic:!1,logBase:10,tickAmount:void 0,stepSize:void 0,forceNiceScale:!1,alignZero:!1,max:void 0,min:void 0,floating:!1,decimalsInFloat:void 0,labels:{show:!0,showDuplicates:!1,minWidth:0,maxWidth:160,offsetX:0,offsetY:0,align:void 0,rotate:0,padding:20,style:{colors:[],fontSize:"11px",fontWeight:400,fontFamily:void 0,cssClass:""},formatter:void 0},axisBorder:{show:!1,color:"#e0e0e0",width:1,offsetX:0,offsetY:0},axisTicks:{show:!1,color:"#e0e0e0",width:6,offsetX:0,offsetY:0},title:{text:void 0,rotate:-90,offsetY:0,offsetX:0,style:{color:void 0,fontSize:"11px",fontWeight:900,fontFamily:void 0,cssClass:""}},tooltip:{enabled:!1,offsetX:0},crosshairs:{show:!0,position:"front",stroke:{color:"#b6b6b6",width:1,dashArray:0}}},this.pointAnnotation={id:void 0,x:0,y:null,yAxisIndex:0,seriesIndex:void 0,mouseEnter:void 0,mouseLeave:void 0,click:void 0,marker:{size:4,fillColor:"#fff",strokeWidth:2,strokeColor:"#333",shape:"circle",offsetX:0,offsetY:0,cssClass:""},label:{borderColor:"#c2c2c2",borderWidth:1,borderRadius:2,text:void 0,textAnchor:"middle",offsetX:0,offsetY:0,mouseEnter:void 0,mouseLeave:void 0,click:void 0,style:{background:"#fff",color:void 0,fontSize:"11px",fontFamily:void 0,fontWeight:400,cssClass:"",padding:{left:5,right:5,top:2,bottom:2}}},customSVG:{SVG:void 0,cssClass:void 0,offsetX:0,offsetY:0},image:{path:void 0,width:20,height:20,offsetX:0,offsetY:0},tooltip:{enabled:!1,text:void 0,formatter:void 0,theme:void 0,offsetX:0,offsetY:0}},this.yAxisAnnotation={id:void 0,y:0,y2:null,strokeDashArray:1,fillColor:"#c2c2c2",borderColor:"#c2c2c2",borderWidth:1,opacity:.3,offsetX:0,offsetY:0,width:"100%",yAxisIndex:0,label:{borderColor:"#c2c2c2",borderWidth:1,borderRadius:2,text:void 0,textAnchor:"end",position:"right",offsetX:0,offsetY:-3,mouseEnter:void 0,mouseLeave:void 0,click:void 0,style:{background:"#fff",color:void 0,fontSize:"11px",fontFamily:void 0,fontWeight:400,cssClass:"",padding:{left:5,right:5,top:2,bottom:2}}}},this.xAxisAnnotation={id:void 0,x:0,x2:null,strokeDashArray:1,fillColor:"#c2c2c2",borderColor:"#c2c2c2",borderWidth:1,opacity:.3,offsetX:0,offsetY:0,label:{borderColor:"#c2c2c2",borderWidth:1,borderRadius:2,text:void 0,textAnchor:"middle",orientation:"vertical",position:"top",offsetX:0,offsetY:0,mouseEnter:void 0,mouseLeave:void 0,click:void 0,style:{background:"#fff",color:void 0,fontSize:"11px",fontFamily:void 0,fontWeight:400,cssClass:"",padding:{left:5,right:5,top:2,bottom:2}}}},this.text={x:0,y:0,text:"",textAnchor:"start",foreColor:void 0,fontSize:"13px",fontFamily:void 0,fontWeight:400,appendTo:".apexcharts-annotations",backgroundColor:"transparent",borderColor:"#c2c2c2",borderRadius:0,borderWidth:0,paddingLeft:4,paddingRight:4,paddingTop:2,paddingBottom:2}}init(){return{annotations:{yaxis:[this.yAxisAnnotation],xaxis:[this.xAxisAnnotation],points:[this.pointAnnotation],texts:[],images:[],shapes:[]},plugins:[],trellis:{by:void 0,row:void 0,column:void 0,emptyPanels:"placeholder",data:void 0,x:void 0,y:void 0,seriesBy:void 0,columns:"auto",minPanelWidth:220,gap:12,aspectRatio:1.6,panelHeight:void 0,order:"first-seen",limit:void 0,virtualize:"auto",scales:{x:"shared",y:"shared",color:"shared",size:"shared"},header:{show:!0,formatter:void 0,style:{fontSize:void 0,fontWeight:void 0,color:void 0}},axes:{labels:"edges"},legend:"shared",toolbar:"shared",tooltip:"panel",zoom:"sync",promote:!0,radiusByTotal:!1,targetTicks:3,panel:void 0},chart:{animations:{enabled:!0,speed:800,easing:"easeInOutSine",animateGradually:{delay:150,enabled:!0},dynamicAnimation:{enabled:!0,speed:350,easing:void 0},chartTypeMorph:{enabled:!0,speed:600},respectReducedMotion:!0,largeDatasetThreshold:1e3},background:"",locales:[C],defaultLocale:"en",perspectives:{serializeOptions:["theme","xaxis","yaxis","title","subtitle"]},history:{enabled:!1,maxDepth:100,coalesceMs:250,keyboard:!0},renderer:"svg",rendererThreshold:8e3,layers:{series:"auto",grid:"svg",annotations:"svg",dataLabels:"svg"},dropShadow:{enabled:!1,enabledOnSeries:void 0,top:2,left:2,blur:4,color:"#000",opacity:.7},events:{animationEnd:void 0,beforeMount:void 0,mounted:void 0,updated:void 0,click:void 0,mouseMove:void 0,mouseLeave:void 0,xAxisLabelClick:void 0,legendClick:void 0,markerClick:void 0,selection:void 0,dataPointSelection:void 0,dataPointMouseEnter:void 0,dataPointMouseLeave:void 0,beforeZoom:void 0,beforeResetZoom:void 0,zoomed:void 0,scrolled:void 0,brushScrolled:void 0,crossFilter:void 0,filterChange:void 0,annotationDragged:void 0,annotationEdited:void 0,annotationCreated:void 0,annotationStyled:void 0,annotationDeleted:void 0,measured:void 0,keyDown:void 0,keyUp:void 0},foreColor:"#373d3f",fontFamily:"Helvetica, Arial, sans-serif",height:"auto",parentHeightOffset:15,redrawOnParentResize:!0,redrawOnWindowResize:!0,print:{enabled:!0,width:700},id:void 0,group:void 0,nonce:void 0,license:void 0,offsetX:0,offsetY:0,injectStyleSheet:!0,selection:{enabled:!1,type:"x",fill:{color:"#24292e",opacity:.1},stroke:{width:1,color:"#24292e",opacity:.4,dashArray:3},xaxis:{min:void 0,max:void 0},yaxis:{min:void 0,max:void 0}},sparkline:{enabled:!1},brush:{enabled:!1,autoScaleYaxis:!0,target:void 0,targets:void 0},link:{enabled:!1,mode:"highlight",dimOpacity:.2,id:void 0,dimension:void 0,reduce:void 0,type:void 0,bins:void 0,order:void 0,seriesName:void 0},ink:{enabled:!1,palette:!1,snap:!1,noteColors:void 0},measure:{enabled:!1,mode:"span",key:"m",pinOnRelease:!0,colors:{up:void 0,down:void 0,neutral:void 0,guide:void 0},band:!0,guides:!0,markers:!0,format:{x:void 0,y:void 0,percent:void 0},label:void 0},contextMenu:{enabled:!1,items:["annotate","xline","yline","measure"],labels:{annotate:void 0,xline:void 0,yline:void 0,measure:void 0},noteText:"Note",line:{text:"",strokeDashArray:4,color:void 0}},stacked:!1,stackOnlyBar:!0,stackType:"normal",streaming:{enabled:!1,maxPoints:void 0},toolbar:{show:!0,offsetX:0,offsetY:0,tools:{download:!0,selection:!0,zoom:!0,zoomin:!0,zoomout:!0,pan:!0,reset:!0,measure:!0,customIcons:[]},export:{csv:{filename:void 0,columnDelimiter:",",headerCategory:"category",headerValue:"value",categoryFormatter:void 0,valueFormatter:void 0},png:{filename:void 0},svg:{filename:void 0},scale:void 0,width:void 0,embedFonts:!0},autoSelected:"zoom"},type:"line",width:"100%",zoom:{enabled:!0,type:"x",autoScaleYaxis:!1,allowMouseWheelZoom:"auto",pinch:"auto",zoomedArea:{fill:{color:"#90CAF9",opacity:.4},stroke:{color:"#0D47A1",opacity:.4,width:1}}},pan:{inertia:!0,friction:.92},accessibility:{enabled:!0,description:void 0,announcements:{enabled:!0},keyboard:{enabled:!0,navigation:{enabled:!0,wrapAround:!1}}},dataReducer:{enabled:!1,algorithm:"lttb",targetPoints:250,threshold:500}},parsing:{x:void 0,y:void 0},plotOptions:{line:{isSlopeChart:!1,colors:{threshold:0,colorAboveThreshold:void 0,colorBelowThreshold:void 0}},area:{fillTo:"origin"},bar:{horizontal:!1,columnWidth:"70%",barHeight:"70%",distributed:!1,borderRadius:0,borderRadiusApplication:"around",rangeBarOverlap:!0,rangeBarGroupRows:!1,hideZeroBarsWhenGrouped:!1,isDumbbell:!1,dumbbellColors:void 0,dumbbell:{connector:{color:void 0,opacity:.55},dataLabels:{enabled:!1,offset:6,colorFromMarker:!0,formatter:void 0,style:{fontSize:"12px",fontFamily:void 0,fontWeight:600,colors:void 0}},tooltip:{differenceLabel:"Difference"}},isFunnel:!1,isFunnel3d:!0,colors:{ranges:[],backgroundBarColors:[],backgroundBarOpacity:1,backgroundBarRadius:0},dataLabels:{position:"top",maxItems:100,hideOverflowingLabels:!0,orientation:"horizontal",total:{enabled:!1,formatter:void 0,offsetX:0,offsetY:0,style:{color:"#373d3f",fontSize:"12px",fontFamily:void 0,fontWeight:600}}}},bubble:{zScaling:!0,minBubbleRadius:void 0,maxBubbleRadius:void 0,minZ:void 0,maxZ:void 0},scatter:{jitter:{enabled:!1,x:0,y:0,distributed:!1,maxPoints:5e3}},candlestick:{colors:{upward:"#00B746",downward:"#EF403C"},wick:{useFillColor:!0}},boxPlot:{colors:{upper:"#00E396",lower:"#008FFB"},whiskers:"minmax",points:{show:!1,shape:"circle",size:2.5,jitter:.5,maxPoints:3e3,opacity:.9,fillColor:"series-dark",strokeColor:"#fff",strokeWidth:1}},violin:{bandwidthScale:1,kde:{bandwidth:void 0,resolution:64},normalize:"individual",side:"both",box:{show:!1,width:"15%",whiskers:"minmax",strokeWidth:1,fillColor:void 0,capWidth:.5},points:{show:!0,shape:"circle",size:2.5,jitter:.5,constrainToViolin:!0,position:"center",laneWidth:"40%",maxPoints:3e3,opacity:.9,fillColor:"series-dark",strokeColor:"#fff",strokeWidth:1}},histogram:{bins:"auto",binWidth:void 0,range:void 0,normalize:"count",cumulative:!1,overlap:!0},heatmap:{shape:"rect",radius:2,enableShades:!0,shadeIntensity:.5,reverseNegativeShade:!1,distributed:!1,useFillColorAsStroke:!1,colorScale:{inverse:!1,ranges:[],min:void 0,max:void 0,gradientLegend:{enabled:!1,width:"70%",height:"70%",thickness:12,align:"center",stops:16,showLabels:!0,showHoverValue:!0,labelStyle:{fontSize:"11px",fontFamily:void 0,colors:void 0},arrow:{size:8,color:void 0},formatter:void 0}}},waterfall:{colors:{positive:"#00A86F",negative:"#FF4560",subtotal:void 0,total:void 0},connectors:{show:!0,color:void 0,strokeWidth:1,strokeDashArray:3}},streamgraph:{offset:"wiggle",order:"inside-out",hover:{show:!0,opacity:.35},labels:{show:!0,minWidth:24,minFontSize:9,maxFontSize:30,style:{fontSize:"auto",fontFamily:void 0,fontWeight:600,colors:void 0}}},funnel:{shape:"rectangle",lastShape:"flat"},treemap:{enableShades:!0,shadeIntensity:.5,distributed:!1,reverseNegativeShade:!1,useFillColorAsStroke:!1,borderRadius:4,dataLabels:{format:"scale",minFontSize:4},colorScale:{inverse:!1,ranges:[],min:void 0,max:void 0,colorValue:void 0,gradient:{enabled:void 0,min:void 0,max:void 0,midpoint:void 0,symmetric:!0,colors:void 0,stops:void 0},gradientLegend:{enabled:!1,width:"70%",height:"70%",thickness:12,align:"center",stops:16,showLabels:!0,showHoverValue:!0,labelStyle:{fontSize:"11px",fontFamily:void 0,colors:void 0},arrow:{size:8,color:void 0},formatter:void 0}},nested:{enabled:void 0,drilldownAsLevels:!1},parents:{show:"auto",padding:4,fill:void 0,fillOpacity:1,borderColor:void 0,borderWidth:1,borderRadius:void 0,hover:{show:!0,color:void 0,width:2},header:{show:!0,height:22,minWidth:40,align:"left",offsetX:0,offsetY:0,showValue:!1,formatter:void 0,style:{fontSize:"12px",fontFamily:void 0,fontWeight:600,color:void 0,background:void 0,cssClass:""}},tooltip:{formatter:void 0}},levels:[],zoom:{enabled:!1,breadcrumb:void 0},seriesTitle:{show:!0,offsetY:1,offsetX:1,borderColor:"#000",borderWidth:1,borderRadius:2,style:{background:"rgba(0, 0, 0, 0.6)",color:"#fff",fontSize:"12px",fontFamily:void 0,fontWeight:400,cssClass:"",padding:{left:6,right:6,top:2,bottom:2}}}},unit:{layout:"grouped",positions:void 0,transition:"group",shape:"circle",image:{src:void 0,width:20,height:20,tint:!1},pictogram:{mark:void 0,fit:"contain",scale:1,padding:0,fallback:"circle"},size:"auto",columns:{size:"inherit"},grid:{columns:10,total:void 0,fillFrom:"bottom",split:!1,tileColumns:void 0,max:void 0,trackColor:void 0},scatter:{y:"lanes",spread:"swarm",orientation:"horizontal",tickAmount:5,xMin:void 0,xMax:void 0,xTitle:void 0,xFormatter:void 0,yTickAmount:5,yMin:void 0,yMax:void 0,yTitle:void 0,yFormatter:void 0,sizeField:"z",sizeRange:void 0,laneLabelWidth:void 0,gridlines:!0},sizeByValue:{enabled:!1,maxRadius:"auto",minRadius:void 0,scale:"area"},spacing:1.05,borderRadius:0,gather:{motion:"auto",spring:"crisp",easing:"outCubic",overshoot:1.70158,enter:"burst"},arc:{startAngle:-90,endAngle:90,innerRadiusRatio:.4,rows:"auto"},unitValue:1,maxUnits:5e3,sortByGroup:!0,clusterLabels:{show:!0,position:"top",curved:!0,fontSize:"13px",fontFamily:void 0,fontWeight:600,color:void 0,offsetY:0,formatter:void 0,external:{show:!1,connector:{show:!0,width:1.5,color:void 0,gap:8,length:22},offsetX:0,offsetY:0}},tooltip:{formatter:void 0}},radialBar:{inverseOrder:!1,startAngle:0,endAngle:360,offsetX:0,offsetY:0,shape:"arc",min:0,max:100,bands:[],bandsStyle:{strokeWidth:"40%",gap:0,hideTrackWhenPresent:!0},ticks:{show:!1,major:{count:11,length:10,width:2,color:"#666",placement:"outside"},minor:{count:4,length:5,width:1,color:"#999",placement:"outside"},labels:{show:!1,offset:6,fontSize:"11px",fontFamily:void 0,fontWeight:400,color:"#666",formatter:t=>String(t)}},needle:{color:"#333",length:"85%",baseWidth:4,tipWidth:1,offsetY:0,showValueArc:!1,animation:{enabled:!0,duration:800,easing:"ease-out"}},hollow:{margin:5,size:"50%",background:"transparent",image:void 0,imageWidth:150,imageHeight:150,imageOffsetX:0,imageOffsetY:0,imageClipped:!0,position:"front",stroke:void 0,strokeWidth:1,strokeDasharray:void 0,dropShadow:{enabled:!1,top:0,left:0,blur:3,color:"#000",opacity:.5}},track:{show:!0,startAngle:void 0,endAngle:void 0,background:"#f2f2f2",strokeWidth:"97%",opacity:1,margin:5,dropShadow:{enabled:!1,top:0,left:0,blur:3,color:"#000",opacity:.5}},dataLabels:{show:!0,name:{show:!0,fontSize:"16px",fontFamily:void 0,fontWeight:600,color:void 0,offsetY:0,formatter:t=>t},value:{show:!0,fontSize:"14px",fontFamily:void 0,fontWeight:400,color:void 0,offsetY:16,formatter:t=>t+"%"},total:{show:!1,label:"Total",fontSize:"16px",fontWeight:600,fontFamily:void 0,color:void 0,formatter:t=>t.globals.seriesTotals.reduce((t,e)=>t+e,0)/t.seriesData.series.length+"%"}},barLabels:{enabled:!1,offsetX:0,offsetY:0,useSeriesColors:!0,fontFamily:void 0,fontWeight:600,fontSize:"16px",formatter:t=>t,onClick:void 0}},pie:{customScale:1,offsetX:0,offsetY:0,startAngle:0,endAngle:360,expandOnClick:!0,expandOffset:10,hoverOutline:{show:!0,size:8,gap:0,opacity:.3,color:void 0},borderRadius:0,spacing:0,dataLabels:{offset:0,minAngleToShowLabel:10,external:{show:!1,offsetX:0,offsetY:0,fontSize:void 0,fontFamily:void 0,fontWeight:void 0,color:void 0,formatter:void 0,connector:{show:!0,width:1,color:void 0,length:16,gap:6}}},donut:{size:"65%",background:"transparent",labels:{show:!1,name:{show:!0,fontSize:"16px",fontFamily:void 0,fontWeight:600,color:void 0,offsetY:-10,formatter:t=>t},value:{show:!0,fontSize:"20px",fontFamily:void 0,fontWeight:400,color:void 0,offsetY:10,formatter:t=>t},total:{show:!1,showAlways:!1,label:"Total",fontSize:"16px",fontWeight:400,fontFamily:void 0,color:void 0,formatter:t=>t.globals.seriesTotals.reduce((t,e)=>t+e,0)}}}},polarArea:{rings:{strokeWidth:1,strokeColor:"#e8e8e8"},spokes:{strokeWidth:1,connectorColors:"#e8e8e8"}},sunburst:{offsetX:0,offsetY:0,startAngle:0,endAngle:360,innerSize:"15%",borderRadius:0,spacing:1,leaf:"extend",partition:"normalize",tint:.14,zoomOnClick:!0,dataLabels:{show:!0,minAngleToShow:8,style:{fontSize:"12px",fontFamily:void 0,fontWeight:400,colors:void 0}}},radar:{size:void 0,offsetX:0,offsetY:0,polygons:{strokeWidth:1,strokeColors:"#e8e8e8",connectorColors:"#e8e8e8",fill:{colors:void 0}}}},colors:void 0,dataLabels:{enabled:!0,enabledOnSeries:void 0,formatter:t=>null!==t?t:"",textAnchor:"middle",distributed:!1,offsetX:0,offsetY:0,style:{fontSize:"12px",fontFamily:void 0,fontWeight:600,colors:void 0},background:{enabled:!0,foreColor:"#fff",backgroundColor:void 0,borderRadius:2,padding:4,opacity:.9,borderWidth:1,borderColor:"#fff",dropShadow:{enabled:!1,top:1,left:1,blur:1,color:"#000",opacity:.8}},dropShadow:{enabled:!1,top:1,left:1,blur:1,color:"#000",opacity:.8},animate:{enabled:!0},countUp:{enabled:!1}},fill:{type:"solid",colors:void 0,opacity:.85,gradient:{shade:"dark",type:"horizontal",shadeIntensity:.5,gradientToColors:void 0,inverseColors:!0,opacityFrom:1,opacityTo:1,stops:[0,50,100],colorStops:[]},image:{src:[],width:void 0,height:void 0},pattern:{style:"squares",width:6,height:6,strokeWidth:2}},forecastDataPoints:{count:0,fillOpacity:.5,strokeWidth:void 0,dashArray:4},grid:{show:!0,borderColor:"#e0e0e0",strokeDashArray:0,position:"back",xaxis:{lines:{show:!1}},yaxis:{lines:{show:!0}},row:{colors:void 0,opacity:.5},column:{colors:void 0,opacity:.5},padding:{top:0,right:10,bottom:0,left:12}},labels:[],drilldown:{enabled:!1,series:[],breadcrumb:{show:!0,position:"top-left",separator:" / ",rootLabel:"All",offsetX:0,offsetY:0},animation:{enabled:!0,zoomFromPoint:!1,speed:260},loading:{show:!0},cache:!0,marker:{show:!0,size:6,strokeColor:"#fff"}},legend:{show:!0,showForSingleSeries:!1,showForNullSeries:!0,showForZeroSeries:!0,floating:!1,position:"bottom",horizontalAlign:"center",inverseOrder:!1,fontSize:"12px",fontFamily:void 0,fontWeight:400,width:void 0,height:void 0,formatter:void 0,tooltipHoverFormatter:void 0,offsetX:-20,offsetY:4,customLegendItems:[],clusterGroupedSeries:!0,clusterGroupedSeriesOrientation:"vertical",labels:{colors:void 0,useSeriesColors:!1},markers:{size:7,fillColors:void 0,strokeWidth:1,shape:void 0,offsetX:0,offsetY:0,customHTML:void 0,onClick:void 0},itemMargin:{horizontal:5,vertical:4},onItemClick:{toggleDataSeries:!0},onItemHover:{highlightDataSeries:!0}},markers:{discrete:[],size:0,colors:void 0,strokeColors:"#fff",strokeWidth:2,strokeOpacity:.9,strokeDashArray:0,fillOpacity:1,shape:"circle",offsetX:0,offsetY:0,showNullDataPoints:!0,onClick:void 0,onDblClick:void 0,hover:{size:void 0,sizeOffset:3},largeDatasetThreshold:0},noData:{text:void 0,align:"center",offsetX:0,offsetY:0,style:{color:void 0,fontSize:"14px",fontFamily:void 0}},responsive:[],series:void 0,states:{hover:{filter:{type:"lighten",value:.15}},active:{allowMultipleDataPointsSelection:!1,filter:{type:"darken",value:.35}}},title:{text:void 0,align:"left",margin:5,offsetX:0,offsetY:0,floating:!1,style:{fontSize:"14px",fontWeight:900,fontFamily:void 0,color:void 0}},subtitle:{text:void 0,align:"left",margin:5,offsetX:0,offsetY:30,floating:!1,style:{fontSize:"12px",fontWeight:400,fontFamily:void 0,color:void 0}},stroke:{show:!0,curve:"smooth",lineCap:"butt",width:2,colors:void 0,dashArray:0,fill:{type:"solid",colors:void 0,opacity:.85,gradient:{shade:"dark",type:"horizontal",shadeIntensity:.5,gradientToColors:void 0,inverseColors:!0,opacityFrom:1,opacityTo:1,stops:[0,50,100],colorStops:[]}}},tooltip:{enabled:!0,enabledOnSeries:void 0,shared:!0,hideEmptySeries:!1,followCursor:!1,intersect:!1,inverseOrder:!1,arrow:!0,compact:!1,custom:void 0,fillSeriesColor:!1,theme:"light",cssClass:"",style:{fontSize:"12px",fontFamily:void 0,background:void 0},onDatasetHover:{highlightDataSeries:!1},x:{show:!0,format:"dd MMM",formatter:void 0},y:{formatter:void 0,title:{formatter:t=>t?t+": ":""}},z:{formatter:void 0,title:"Size: "},marker:{show:!0,fillColors:void 0},items:{display:"flex"},fixed:{enabled:!1,position:"topRight",offsetX:0,offsetY:0}},xaxis:{type:"category",categories:[],convertedCatToNumeric:!1,offsetX:0,offsetY:0,overwriteCategories:void 0,labels:{show:!0,rotate:-45,rotateAlways:!1,hideOverlappingLabels:!0,trim:!1,minHeight:void 0,maxHeight:120,showDuplicates:!0,style:{colors:[],fontSize:"12px",fontWeight:400,fontFamily:void 0,cssClass:""},offsetX:0,offsetY:0,format:void 0,formatter:void 0,datetimeUTC:!0,datetimeFormatter:{year:"yyyy",month:"MMM",day:"dd MMM",hour:"HH:mm",minute:"HH:mm",second:"HH:mm:ss"}},group:{groups:[],style:{colors:[],fontSize:"12px",fontWeight:400,fontFamily:void 0,cssClass:""}},axisBorder:{show:!0,color:"#e0e0e0",width:"100%",height:1,offsetX:0,offsetY:0},axisTicks:{show:!0,color:"#e0e0e0",height:6,offsetX:0,offsetY:0},stepSize:void 0,tickAmount:void 0,tickPlacement:"on",min:void 0,max:void 0,range:void 0,floating:!1,decimalsInFloat:void 0,position:"bottom",title:{text:void 0,offsetX:0,offsetY:0,style:{color:void 0,fontSize:"12px",fontWeight:900,fontFamily:void 0,cssClass:""}},crosshairs:{show:!0,width:1,position:"back",opacity:.9,stroke:{color:"#b6b6b6",width:1,dashArray:3},fill:{type:"solid",color:"#B1B9C4",gradient:{colorFrom:"#D8E3F0",colorTo:"#BED1E6",stops:[0,100],opacityFrom:.4,opacityTo:.5}},dropShadow:{enabled:!1,left:0,top:0,blur:1,opacity:.8}},tooltip:{enabled:!1,offsetY:0,formatter:void 0,style:{fontSize:"12px",fontFamily:void 0}}},yaxis:this.yAxis,theme:{mode:"",palette:"palette1",tokens:!0,follow:!1,name:"",monochrome:{enabled:!1,color:"#008FFB",shadeTo:"light",shadeIntensity:.65},accessibility:{colorBlindMode:""}}}}}const _={funnel:"bar",pyramid:"bar",gauge:"radialBar",waffle:"unit",histogram:"bar",waterfall:"rangeBar",dumbbell:"rangeBar",streamgraph:"rangeArea",raincloud:"violin"},M="_apexOwnedByType",D=(t,e)=>(e[M]=t,e),L=["tooltip.custom","tooltip.shared","tooltip.intersect","tooltip.followCursor","dataLabels.enabled","dataLabels.formatter","plotOptions.bar.dataLabels.position","markers.size","plotOptions.violin.side","plotOptions.violin.box.show","plotOptions.violin.box.whiskers","plotOptions.violin.points.position","states.hover.filter.type","states.active.filter.type","xaxis.crosshairs.width","xaxis.tickPlacement","xaxis.tooltip.enabled","chart.zoom.enabled","chart.animations.dynamicAnimation.enabled"],P=(t,e)=>{let i=t;for(const t of e.split(".")){if(null==i||"object"!=typeof i)return;i=i[t]}return i},F=(t,e,i)=>{const s=e.split("."),a=s.pop();let r=t;for(const t of s)null!=r[t]&&"object"==typeof r[t]||(r[t]={}),r=r[t];void 0===i?delete r[a]:r[a]=i},E=(t,e)=>{var i,s;const a=_[t];return{chart:{type:a||t,requestedType:a?t:void 0,stacked:null==(i=e.chart)?void 0:i.stacked},plotOptions:{bar:{isFunnel:"funnel"===t||"pyramid"===t},histogram:null==(s=e.plotOptions)?void 0:s.histogram},series:e.series,yaxis:[{title:{},labels:{},axisBorder:{},axisTicks:{}}]}},T=(t,e)=>{if("function"==typeof t)return!!Array.isArray(t[M])||"function"==typeof e&&String(t)===String(e);if("function"==typeof e)return void 0===t;if(t===e)return!0;try{return JSON.stringify(t)===JSON.stringify(e)}catch(t){return!1}},I=({isTimeline:t,seriesIndex:e,dataPointIndex:i,y1:s,y2:a,w:r})=>{var n;let o=r.rangeData.seriesRangeStart[e][i],l=r.rangeData.seriesRangeEnd[e][i],h=r.labelData.labels[i],c=r.config.series[e].name?r.config.series[e].name:"";const d=r.formatters.ttKeyFormatter,p=r.config.tooltip.y.title.formatter,u={w:r,seriesIndex:e,dataPointIndex:i,start:o,end:l};if("function"==typeof p&&(c=p(c,u)),(null==(n=r.config.series[e].data[i])?void 0:n.x)&&(h=r.config.series[e].data[i].x),!t&&"datetime"===r.config.xaxis.type){h=new S(r).xLabelFormat(r.formatters.ttKeyFormatter,h,h,{i:void 0,dateFormatter:new A(r).formatDate,w:r})}"function"==typeof d&&(h=d(h,u)),Number.isFinite(s)&&Number.isFinite(a)&&(o=s,l=a);let g="",f="";const x=r.globals.colors[e];if(void 0===r.config.tooltip.x.formatter)if("datetime"===r.config.xaxis.type){const t=new A(r);g=t.formatDate(t.getDate(o),r.config.tooltip.x.format),f=t.formatDate(t.getDate(l),r.config.tooltip.x.format)}else g=o,f=l;else g=r.config.tooltip.x.formatter(o),f=r.config.tooltip.x.formatter(l);return{start:o,end:l,startVal:g,endVal:f,ylabel:h,color:x,seriesName:c}},R=t=>{let{color:e,seriesName:i,ylabel:s,start:a,end:r,seriesIndex:n,dataPointIndex:o}=t;const l=t.w.globals.tooltip.tooltipLabels.getFormatters(n);a=l.yLbFormatter(a),r=l.yLbFormatter(r);const h=l.yLbFormatter(t.w.seriesData.series[n][o]);let c="";const d=`\n ${a}\n - \n ${r}\n `;return c=t.w.globals.comboCharts?"rangeArea"===t.w.config.series[n].type||"rangeBar"===t.w.config.series[n].type?d:`${h}`:d,'
'+(i||"")+'
'+s+": "+c+"
"};class z{constructor(t){this.opts=t}static forType(t){var e,i;const s=new z(t),a=t.chart.requestedType;let r;return r="funnel"===a||"pyramid"===a?s[a]():"gauge"===a?s.gauge():"histogram"===a?s.histogram():"waterfall"===a?s.waterfall():"dumbbell"===a?s.dumbbell():"streamgraph"===a?s.streamgraph():"raincloud"===a?s.raincloud():-1!==["line","area","bar","candlestick","boxPlot","violin","rangeBar","rangeArea","bubble","scatter","heatmap","treemap","unit","sunburst","pie","polarArea","donut","radar","radialBar"].indexOf(t.chart.type)?s[t.chart.type]():s.line(),(null==(i=null==(e=t.plotOptions)?void 0:e.bar)?void 0:i.isFunnel)&&(r=s.funnel()),t.chart.stacked&&"bar"===t.chart.type&&(r=s.stackedBars()),r}static handOverTypeDefaults(t,e,i){const s=t.chart.requestedType||t.chart.type;if(!e||e===s)return;const a=(new k).init(),r=v.extend(a,z.forType(E(e,t))),n=v.extend(a,z.forType(E(s,t)));for(const e of L){if(i&&void 0!==P(i,e))continue;const s=P(r,e),a=P(n,e);void 0===s&&void 0===a||T(P(t,e),s)&&F(t,e,a)}}hideYAxis(){this.opts.yaxis[0].show=!1,this.opts.yaxis[0].title.text="",this.opts.yaxis[0].axisBorder.show=!1,this.opts.yaxis[0].axisTicks.show=!1,this.opts.yaxis[0].floating=!0}line(){return{dataLabels:{enabled:!1},stroke:{width:5,curve:"straight"},markers:{size:0,hover:{sizeOffset:6}},xaxis:{crosshairs:{width:1}}}}sparkline(t){this.hideYAxis();return v.extend(t,{grid:{show:!1,padding:{left:0,right:0,top:0,bottom:0}},legend:{show:!1},xaxis:{labels:{show:!1},tooltip:{enabled:!1},axisBorder:{show:!1},axisTicks:{show:!1}},chart:{toolbar:{show:!1},zoom:{enabled:!1}},dataLabels:{enabled:!1}})}slope(){return this.hideYAxis(),{chart:{toolbar:{show:!1},zoom:{enabled:!1}},dataLabels:{enabled:!0,formatter(t,e){const i=e.w.config.series[e.seriesIndex].name;return null!==t?i+": "+t:""},background:{enabled:!1},offsetX:-5},grid:{xaxis:{lines:{show:!0}},yaxis:{lines:{show:!1}}},xaxis:{position:"top",labels:{style:{fontSize:14,fontWeight:900}},tooltip:{enabled:!1},crosshairs:{show:!1}},markers:{size:8,hover:{sizeOffset:1}},legend:{show:!1},tooltip:{shared:!1,intersect:!0,followCursor:!0},stroke:{width:5,curve:"straight"}}}bar(){return{chart:{stacked:!1},plotOptions:{bar:{dataLabels:{position:"center"}}},dataLabels:{style:{colors:["#fff"]},background:{enabled:!1}},stroke:{width:0,lineCap:"square"},fill:{opacity:.85},legend:{markers:{shape:"square"}},tooltip:{shared:!1,intersect:!0},xaxis:{tooltip:{enabled:!1},tickPlacement:"between",crosshairs:{width:"barWidth",position:"back",fill:{type:"gradient"},dropShadow:{enabled:!1},stroke:{width:0}}}}}funnel(){return this.hideYAxis(),l(o({},this.bar()),{chart:{animations:{speed:800,animateGradually:{enabled:!1}}},plotOptions:{bar:{horizontal:!0,borderRadiusApplication:"around",borderRadius:0,dataLabels:{position:"center"}}},grid:{show:!1,padding:{left:0,right:0}},xaxis:{labels:{show:!1},tooltip:{enabled:!1},axisBorder:{show:!1},axisTicks:{show:!1}}})}pyramid(){return this.funnel()}gauge(){const t=this.radialBar();return l(o({},t),{plotOptions:{radialBar:{startAngle:-135,endAngle:135,hollow:{margin:0,size:"60%"},track:{background:"#e7e7e7",strokeWidth:"100%",margin:5},dataLabels:{name:{show:!1},value:{show:!0,fontSize:"32px",fontWeight:600,offsetY:8}}}}})}waterfall(){const t=this.rangeBar();return l(o({},t),{chart:{stacked:!1,zoom:{enabled:!1},animations:{animateGradually:{enabled:!0}}},plotOptions:l(o({},t.plotOptions),{bar:l(o({},t.plotOptions.bar),{columnWidth:"60%",barHeight:"60%"})}),dataLabels:l(o({},t.dataLabels),{enabled:!0,background:{enabled:!0,backgroundColor:"#fff",foreColor:"#373d3f",borderColor:"#e3e8ee",opacity:.92}}),legend:{show:!1},tooltip:{shared:!1,intersect:!0,followCursor:!1}})}histogram(){var t,e,i,s;const a=Array.isArray(null==(t=this.opts)?void 0:t.series)&&this.opts.series.length>1&&!1!==(null==(s=null==(i=null==(e=this.opts)?void 0:e.plotOptions)?void 0:i.histogram)?void 0:s.overlap);return l(o({},this.bar()),{chart:{stacked:!1,zoom:{enabled:!1},animations:{animateGradually:{enabled:!1}}},plotOptions:{bar:{columnWidth:"100%",borderRadius:0,dataLabels:{position:"top"}}},dataLabels:{enabled:!1},fill:a?{opacity:.65}:{},stroke:a?{show:!1}:{show:!0,width:1,colors:["#fff"]},xaxis:{type:"numeric",tooltip:{enabled:!1}},tooltip:{shared:a,intersect:!1,x:{formatter:(t,e)=>{var i,s;const a=null==(s=null==(i=null==e?void 0:e.w)?void 0:i.histogramData)?void 0:s.edges,r=null==e?void 0:e.dataPointIndex;if(!Array.isArray(a)||"number"!=typeof r||r<0)return String(t);const n=a[r],o=a[r+1];if(void 0===n||void 0===o)return String(t);const l=t=>Number.isInteger(t)?String(t):t.toFixed(2);return`${l(n)} to ${l(o)}`}}}})}candlestick(){return{stroke:{width:1},fill:{opacity:1},dataLabels:{enabled:!1},tooltip:{shared:!0,custom:D(["candlestick"],({seriesIndex:t,dataPointIndex:e,w:i})=>this._getBoxTooltip(i,t,e,["Open","High","","Low","Close"],"candlestick"))},states:{active:{filter:{type:"none"}}},xaxis:{crosshairs:{width:1}}}}boxPlot(){return{chart:{animations:{dynamicAnimation:{enabled:!1}}},stroke:{width:1,colors:["#24292e"]},dataLabels:{enabled:!1},tooltip:{shared:!0,custom:D(["boxPlot"],({seriesIndex:t,dataPointIndex:e,w:i})=>this._getBoxTooltip(i,t,e,["Minimum","Q1","Median","Q3","Maximum"],"boxPlot"))},markers:{size:7,strokeWidth:1,strokeColors:"#111"},xaxis:{crosshairs:{width:1}}}}violin(){return{chart:{zoom:{enabled:!1},animations:{dynamicAnimation:{enabled:!1}}},stroke:{width:1,colors:["#24292e"]},fill:{opacity:.7},dataLabels:{enabled:!1},tooltip:{shared:!0,custom:D(["violin"],({seriesIndex:t,dataPointIndex:e,w:i})=>this._getViolinTooltip(i,t,e))},states:{active:{filter:{type:"none"}}},xaxis:{crosshairs:{width:1}}}}raincloud(){var t,e,i;const s=this.violin(),a=!0===(null==(i=null==(e=null==(t=this.opts)?void 0:t.plotOptions)?void 0:e.bar)?void 0:i.horizontal);return l(o({},s),{plotOptions:{violin:{side:a?"top":"right",box:{show:!0,whiskers:"tukey"},points:{position:a?"bottom":"left",jitter:.85}}},tooltip:l(o({},s.tooltip),{custom:D(["raincloud"],({seriesIndex:t,dataPointIndex:e,w:i})=>this._getRaincloudTooltip(i,t,e))})})}rangeBar(){return{chart:{animations:{animateGradually:!1}},stroke:{width:0,lineCap:"square"},plotOptions:{bar:{borderRadius:0,dataLabels:{position:"center"}}},dataLabels:{enabled:!1,formatter(t,{seriesIndex:e,dataPointIndex:i,w:s}){const a=()=>{const t=s.rangeData.seriesRangeStart[e][i];return s.rangeData.seriesRangeEnd[e][i]-t};return s.globals.comboCharts?"rangeBar"===s.config.series[e].type||"rangeArea"===s.config.series[e].type?a():t:a()},background:{enabled:!1},style:{colors:["#fff"]}},markers:{size:10},tooltip:{shared:!1,followCursor:!0,custom:D(["rangeBar"],t=>t.w.config.plotOptions&&t.w.config.plotOptions.bar&&t.w.config.plotOptions.bar.horizontal?(t=>{const{color:e,seriesName:i,ylabel:s,startVal:a,endVal:r}=I(l(o({},t),{isTimeline:!0}));return R(l(o({},t),{color:e,seriesName:i,ylabel:s,start:a,end:r}))})(t):(t=>{const{color:e,seriesName:i,ylabel:s,start:a,end:r}=I(t);return R(l(o({},t),{color:e,seriesName:i,ylabel:s,start:a,end:r}))})(t))},xaxis:{tickPlacement:"between",tooltip:{enabled:!1},crosshairs:{stroke:{width:0}}}}}dumbbell(){const t=this.rangeBar(),e=(t,e,i)=>'
'+t+' '+i+"
";return l(o({},t),{chart:{stacked:!1,zoom:{enabled:!1}},plotOptions:l(o({},t.plotOptions),{bar:l(o({},t.plotOptions.bar),{barHeight:6,columnWidth:6,dumbbell:{dataLabels:{enabled:!0}}})}),dataLabels:l(o({},t.dataLabels),{enabled:!1}),legend:{show:!0,position:"bottom",horizontalAlign:"left",markers:{shape:"circle"}},tooltip:{shared:!1,intersect:!0,followCursor:!1,custom:D(["rangeBar"],t=>{var i;const{w:s,dataPointIndex:a,seriesIndex:r}=t,n=s.dumbbellData;if(!n||"series"!==n.form){const{color:e,seriesName:i,ylabel:s,start:a,end:r}=I(t);return R(l(o({},t),{color:e,seriesName:i,ylabel:s,start:a,end:r}))}const h=n.values[a]||[],c=s.globals.tooltip.tooltipLabels.getFormatters(r),d=null!=(i=s.labelData.labels[a])?i:"";let p="";const u=[];for(let t=0;t
'+d+"
"+p+(2===u.length?'
'+s.config.plotOptions.bar.dumbbell.tooltip.differenceLabel+': '+c.yLbFormatter(Math.abs(u[1]-u[0]))+"
":"")+""})}})}dumbbellSizing(t){var e,i;return(null==(e=t.plotOptions.bar)?void 0:e.barHeight)||(t.plotOptions.bar.barHeight=2),(null==(i=t.plotOptions.bar)?void 0:i.columnWidth)||(t.plotOptions.bar.columnWidth=2),t}area(){return{stroke:{width:4,fill:{type:"solid",gradient:{inverseColors:!1,shade:"light",type:"vertical",opacityFrom:.65,opacityTo:.5,stops:[0,100,100]}}},fill:{type:"gradient",gradient:{inverseColors:!1,shade:"light",type:"vertical",opacityFrom:.65,opacityTo:.5,stops:[0,100,100]}},markers:{size:0,hover:{sizeOffset:6}},tooltip:{followCursor:!1}}}rangeArea(){return{stroke:{curve:"straight",width:0},fill:{type:"solid",opacity:.6},markers:{size:0},states:{hover:{filter:{type:"none"}},active:{filter:{type:"none"}}},tooltip:{intersect:!1,shared:!0,followCursor:!0,custom:D(["rangeArea"],t=>(t=>{const{color:e,seriesName:i,ylabel:s,start:a,end:r}=I(t);return R(l(o({},t),{color:e,seriesName:i,ylabel:s,start:a,end:r}))})(t))}}}streamgraph(){const t=this.rangeArea();return l(o({},t),{chart:{stacked:!1},stroke:{curve:"monotoneCubic",width:0},fill:{type:"solid",opacity:1},dataLabels:{enabled:!1},grid:{yaxis:{lines:{show:!1}}},markers:{size:0,hover:{size:0,sizeOffset:0}},tooltip:{intersect:!1,shared:!1,followCursor:!0,custom:D(["streamgraph"],t=>(t=>{var e;const{w:i,dataPointIndex:s,seriesIndex:a}=t,r=i.streamgraphData;if(!r||!Array.isArray(r.order)){const{color:e,seriesName:i,ylabel:s,start:a,end:r}=I(t);return R(l(o({},t),{color:e,seriesName:i,ylabel:s,start:a,end:r}))}const{ylabel:n}=I(t),h=(()=>{const t=i.streamgraphData,e=i.dom.baseEl&&i.dom.baseEl.querySelector(".apexcharts-svg"),r=i.interact&&i.interact.clientY,n=i.globals.maxY-i.globals.minY;if(!e||null==r||!n||!isFinite(n))return a;const o=e.getBoundingClientRect(),l=i.globals.svgWidth?o.width/i.globals.svgWidth:1,h=(r-o.top)/(l||1)-i.layout.translateY,c=i.layout.gridHeight,d=t=>{var e;const s=(t-i.globals.minY)/n;return(null==(e=i.config.yaxis[0])?void 0:e.reversed)?s*c:c-s*c};let p=a,u=1/0;for(let e=0;e=l&&h<=c)return i;const g=h{if(c){const s=i.globals.tooltip.tooltipLabels.getFormatters(t);if("function"==typeof s.yLbFormatter)return s.yLbFormatter(e)}return Number.isInteger(e)?String(e):String(Number(e.toFixed(6)))};let p="",u=0;for(let t=r.order.length-1;t>=0;t--){const a=r.order[t],n=null==(e=r.values[a])?void 0:e[s];null!=n&&isFinite(n)&&(u+=n,p+='
'+r.names[a]+' '+d(a,n)+"
")}return'
'+n+"
"+p+("expand"===r.offset?"":'
Total '+d(a,u)+"
")+"
"})(t))},legend:{show:!0,position:"top",horizontalAlign:"center"}})}brush(t){return v.extend(t,{chart:{toolbar:{autoSelected:"selection",show:!1},zoom:{enabled:!1}},dataLabels:{enabled:!1},stroke:{width:1},tooltip:{enabled:!1},xaxis:{tooltip:{enabled:!1}}})}stacked100(t){t.dataLabels=t.dataLabels||{},t.dataLabels.formatter=t.dataLabels.formatter||void 0;const e=t.dataLabels.formatter;t.yaxis.forEach((e,i)=>{t.yaxis[i].min=0,t.yaxis[i].max=100});return"bar"===t.chart.type&&(t.dataLabels.formatter=e||function(t){return"number"==typeof t&&t?t.toFixed(0)+"%":t}),t}stackedBars(){const t=this.bar();return l(o({},t),{plotOptions:l(o({},t.plotOptions),{bar:l(o({},t.plotOptions.bar),{borderRadiusApplication:"end"})})})}convertCatToNumeric(t){return t.xaxis.convertedCatToNumeric=!0,t}convertCatToNumericXaxis(t,e){t.xaxis.type="numeric",t.xaxis.labels=t.xaxis.labels||{},t.xaxis.labels.formatter=t.xaxis.labels.formatter||function(t){return v.isNumber(t)?Math.floor(t):t};const i=t.xaxis.labels.formatter;let s=t.xaxis.categories&&t.xaxis.categories.length?t.xaxis.categories:t.labels;return e&&e.length&&(s=e.map(t=>Array.isArray(t)?t:String(t))),s&&s.length&&(t.xaxis.labels.formatter=function(t){return v.isNumber(t)?i(s[Math.floor(t)-1]):i(t)}),t.xaxis.categories=[],t.labels=[],t.xaxis.tickAmount=t.xaxis.tickAmount||"dataPoints",t}bubble(){return{dataLabels:{style:{colors:["#fff"]}},tooltip:{shared:!1,intersect:!0},xaxis:{crosshairs:{width:0}},fill:{type:"solid",gradient:{shade:"light",inverse:!0,shadeIntensity:.55,opacityFrom:.4,opacityTo:.8}}}}scatter(){return{dataLabels:{enabled:!1},tooltip:{shared:!1,intersect:!0},markers:{size:6,strokeWidth:1,hover:{sizeOffset:2}}}}heatmap(){return{chart:{stacked:!1,zoom:{enabled:!1}},fill:{opacity:1},dataLabels:{style:{colors:["#fff"]}},stroke:{colors:["#fff"]},tooltip:{followCursor:!1,marker:{show:!1},x:{show:!1}},legend:{position:"top",markers:{shape:"square"}},grid:{padding:{right:20}}}}treemap(){return{chart:{zoom:{enabled:!1}},dataLabels:{style:{fontSize:14,fontWeight:600,colors:["#fff"]}},stroke:{show:!0,width:2,colors:["#fff"]},legend:{show:!1},fill:{opacity:1,gradient:{stops:[0,100]}},tooltip:{followCursor:!0,x:{show:!1}},grid:{padding:{left:0,right:0}},xaxis:{crosshairs:{show:!1},tooltip:{enabled:!1},axisTicks:{show:!1}}}}unit(){return{chart:{toolbar:{show:!1}},dataLabels:{enabled:!1},stroke:{show:!1,width:0},fill:{opacity:1},tooltip:{followCursor:!0,x:{show:!1}},legend:{show:!0,position:"bottom"},grid:{padding:{left:0,right:0,top:0,bottom:0}}}}sunburst(){return{chart:{toolbar:{show:!1}},dataLabels:{style:{colors:["#fff"]},dropShadow:{enabled:!0}},stroke:{colors:["#fff"]},fill:{opacity:1},legend:{position:"right"},grid:{padding:{left:0,right:0,top:0,bottom:0}}}}pie(){return{chart:{toolbar:{show:!1}},plotOptions:{pie:{donut:{labels:{show:!1}}}},dataLabels:{formatter:t=>"number"==typeof t?t.toFixed(1)+"%":t,style:{colors:["#fff"]},background:{enabled:!1},dropShadow:{enabled:!0}},stroke:{colors:["#fff"]},fill:{opacity:1,gradient:{shade:"light",stops:[0,100]}},tooltip:{theme:"dark",fillSeriesColor:!0},legend:{position:"right"},grid:{padding:{left:0,right:0,top:0,bottom:0}}}}donut(){return{chart:{toolbar:{show:!1}},dataLabels:{formatter:t=>"number"==typeof t?t.toFixed(1)+"%":t,style:{colors:["#fff"]},background:{enabled:!1},dropShadow:{enabled:!0}},stroke:{colors:["#fff"]},fill:{opacity:1,gradient:{shade:"light",shadeIntensity:.35,stops:[80,100],opacityFrom:1,opacityTo:1}},tooltip:{theme:"dark",fillSeriesColor:!0},legend:{position:"right"},grid:{padding:{left:0,right:0,top:0,bottom:0}}}}polarArea(){return{chart:{toolbar:{show:!1}},dataLabels:{formatter:t=>"number"==typeof t?t.toFixed(1)+"%":t,enabled:!1},stroke:{show:!0,width:2},fill:{opacity:.7},tooltip:{theme:"dark",fillSeriesColor:!0},legend:{position:"right"},grid:{padding:{left:0,right:0,top:0,bottom:0}}}}radar(){return this.opts.yaxis[0].labels.offsetY=this.opts.yaxis[0].labels.offsetY?this.opts.yaxis[0].labels.offsetY:6,{dataLabels:{enabled:!1,style:{fontSize:"11px"}},stroke:{width:2},markers:{size:5,strokeWidth:1,strokeOpacity:1},fill:{opacity:.2},tooltip:{shared:!1,intersect:!0,followCursor:!0},grid:{show:!1,padding:{left:0,right:0,top:0,bottom:0}},xaxis:{labels:{formatter:t=>t,style:{colors:["#a8a8a8"],fontSize:"11px"}},tooltip:{enabled:!1},crosshairs:{show:!1}}}}radialBar(){return{chart:{animations:{dynamicAnimation:{enabled:!0,speed:800}},toolbar:{show:!1}},stroke:{lineCap:"butt"},fill:{gradient:{shade:"dark",shadeIntensity:.4,inverseColors:!1,type:"diagonal2",opacityFrom:1,opacityTo:1,stops:[70,98,100]}},legend:{show:!1,position:"right"},tooltip:{enabled:!1,fillSeriesColor:!0},grid:{padding:{left:0,right:0,top:0,bottom:0}}}}_getBoxTooltip(t,e,i,s,a){const r=t.candleData.seriesCandleO[e][i],n=t.candleData.seriesCandleH[e][i],o=t.candleData.seriesCandleM[e][i],l=t.candleData.seriesCandleL[e][i],h=t.candleData.seriesCandleC[e][i],c=t.config.series[e];return c.type&&c.type!==a?`
\n ${c.name?c.name:"series-"+(e+1)}: ${t.seriesData.series[e][i]}\n
`:`
${s[0]}: `+r+`
${s[1]}: `+n+"
"+(o?`
${s[2]}: `+o+"
":"")+`
${s[3]}: `+l+`
${s[4]}: `+h+"
"}_getViolinTooltip(t,e,i){var s,a,r;const n=null==(s=t.violinData.seriesViolinMin[e])?void 0:s[i],o=null==(a=t.violinData.seriesViolinMax[e])?void 0:a[i],l=(null==(r=t.violinData.seriesViolinPoints[e])?void 0:r[i])||[],h=t.config.series[e].name||"series-"+(e+1);return`
${h}
Min: ${n}
Max: ${o}
Observations: ${l.length}
`}_getRaincloudTooltip(t,e,i){var s,a;const r=null==(s=t.violinData.seriesViolinSummary[e])?void 0:s[i];if(!r)return this._getViolinTooltip(t,e,i);const n=(null==(a=t.violinData.seriesViolinPoints[e])?void 0:a[i])||[],o=t.config.series[e].name||"series-"+(e+1),l=t=>{if(!isFinite(t))return String(t);const e=Math.round(t);return Math.abs(t-e)<1e-6?String(e):String(Number(t.toFixed(2)))},[h,c,d,p,u]=r;return`
${o}
Whisker high: ${l(u)}
Q3: ${l(p)}
Median: ${l(d)}
Q1: ${l(c)}
Whisker low: ${l(h)}
Observations: ${n.length}
`}}class X{constructor(t){this.opts=t}init({responsiveOverride:t}){var e,i,s,a,r,n,o,l;let h=this.opts;const c=new k,p=new z(h);h=this.normalizeAliasedChartType(h),this.chartType=h.chart.type,h=this.extendYAxis(h),h=this.extendAnnotations(h);let u=c.init(),g={};if(h&&"object"==typeof h){let c=z.forType(h);(null==(e=h.chart.brush)?void 0:e.enabled)&&(c=p.brush(c)),(null==(s=null==(i=h.plotOptions)?void 0:i.line)?void 0:s.isSlopeChart)&&(c=p.slope()),h.chart.stacked&&"100%"===h.chart.stackType&&(h=p.stacked100(h)),(null==(r=null==(a=h.plotOptions)?void 0:a.bar)?void 0:r.isDumbbell)&&"dumbbell"!==h.chart.requestedType&&(h=p.dumbbellSizing(h)),this.checkForDarkTheme(d.getApex()),this.checkForDarkTheme(h),h.xaxis=h.xaxis||d.getApex().xaxis||{},t||(h.xaxis.convertedCatToNumeric=!1),h=this.checkForCatToNumericXAxis(this.chartType,c,h),((null==(n=h.chart.sparkline)?void 0:n.enabled)||(null==(l=null==(o=d.getApex().chart)?void 0:o.sparkline)?void 0:l.enabled))&&(c=p.sparkline(c)),g=v.extend(u,c)}const f=v.extend(g,d.getApex());return u=v.extend(f,h),u=this.handleUserInputErrors(u),u}normalizeAliasedChartType(t){if(!t||!t.chart)return t;const e=t.chart.type;return e&&_[e]?(t.chart.requestedType=e,"waffle"===e?(t.plotOptions=t.plotOptions||{},t.plotOptions.unit=t.plotOptions.unit||{},null==t.plotOptions.unit.layout&&(t.plotOptions.unit.layout="grid"),null==t.plotOptions.unit.shape&&(t.plotOptions.unit.shape="square"),t.chart.type="unit"):"funnel"===e||"pyramid"===e?(t.plotOptions=t.plotOptions||{},t.plotOptions.bar=t.plotOptions.bar||{},t.plotOptions.bar.isFunnel=!0,t.plotOptions.bar.horizontal=!0,t.chart.type="bar",t.plotOptions.bar.isPyramid="pyramid"===e):"gauge"===e?t.chart.type="radialBar":"waterfall"===e?(t.chart.stacked=!1,t.chart.type="rangeBar"):"dumbbell"===e?(t.plotOptions=t.plotOptions||{},t.plotOptions.bar=t.plotOptions.bar||{},t.plotOptions.bar.isDumbbell=!0,null==t.plotOptions.bar.horizontal&&(t.plotOptions.bar.horizontal=!0),t.chart.stacked=!1,t.chart.type="rangeBar"):"streamgraph"===e?(t.chart.stacked=!1,t.yaxis=t.yaxis||{},Array.isArray(t.yaxis)||null!=t.yaxis.show||(t.yaxis.show=!1),t.chart.type="rangeArea"):"histogram"===e?(t.xaxis=t.xaxis||{},null==t.xaxis.type&&(t.xaxis.type="numeric"),t.chart.type="bar"):"raincloud"===e&&(t.chart.type="violin"),t):t}checkForCatToNumericXAxis(t,e,i){var s,a,r,n,o;const l=new z(i),h=("bar"===t||"boxPlot"===t||"violin"===t)&&(null==(a=null==(s=i.plotOptions)?void 0:s.bar)?void 0:a.horizontal),c="pie"===t||"polarArea"===t||"donut"===t||"radar"===t||"radialBar"===t||"heatmap"===t||"unit"===t||"sunburst"===t,d="datetime"!==i.xaxis.type&&"numeric"!==i.xaxis.type,p=("scatter"===t||"bubble"===t)&&(null==(o=null==(n=null==(r=i.plotOptions)?void 0:r.scatter)?void 0:n.jitter)?void 0:o.enabled),u=i.xaxis.tickPlacement?i.xaxis.tickPlacement:e.xaxis&&e.xaxis.tickPlacement;return h||c||p||!d||"between"===u||(i=l.convertCatToNumeric(i)),i}extendYAxis(t,e){const i=new k;(void 0===t.yaxis||!t.yaxis||Array.isArray(t.yaxis)&&0===t.yaxis.length)&&(t.yaxis={});const s=d.getApex();t.yaxis.constructor!==Array&&s.yaxis&&s.yaxis.constructor!==Array&&(t.yaxis=v.extend(t.yaxis,s.yaxis)),t.yaxis.constructor!==Array?t.yaxis=[v.extend(i.yAxis,t.yaxis)]:t.yaxis=v.extendArray(t.yaxis,i.yAxis);let a=!1;t.yaxis.forEach(t=>{t.logarithmic&&(a=!0)});let r=t.series;return e&&!r&&(r=e.config.series),a&&r.length!==t.yaxis.length&&r.length&&(t.yaxis=r.map((e,s)=>{if(e.name||(r[s].name=`series-${s+1}`),t.yaxis[s])return t.yaxis[s].seriesName=r[s].name,t.yaxis[s];{const e=v.extend(i.yAxis,t.yaxis[0]);return e.show=!1,e}})),a&&r.length>1&&(r.length,t.yaxis.length),t}extendAnnotations(t){return void 0===t.annotations&&(t.annotations={},t.annotations.yaxis=[],t.annotations.xaxis=[],t.annotations.points=[]),t=this.extendYAxisAnnotations(t),t=this.extendXAxisAnnotations(t),t=this.extendPointAnnotations(t)}extendYAxisAnnotations(t){const e=new k;return t.annotations.yaxis=v.extendArray(void 0!==t.annotations.yaxis?t.annotations.yaxis:[],e.yAxisAnnotation),t}extendXAxisAnnotations(t){const e=new k;return t.annotations.xaxis=v.extendArray(void 0!==t.annotations.xaxis?t.annotations.xaxis:[],e.xAxisAnnotation),t}extendPointAnnotations(t){const e=new k;return t.annotations.points=v.extendArray(void 0!==t.annotations.points?t.annotations.points:[],e.pointAnnotation),t}checkForDarkTheme(t){t.theme&&"dark"===t.theme.mode&&(t.tooltip||(t.tooltip={}),"light"!==t.tooltip.theme&&(t.tooltip.theme="dark"),t.chart.foreColor||(t.chart.foreColor="#f6f7f8"),t.theme.palette||(t.theme.palette="palette4"))}handleUserInputErrors(t){const e=t;if(e.tooltip.shared&&e.tooltip.intersect)throw new Error("tooltip.shared cannot be enabled when tooltip.intersect is true. Turn off any other option by setting it to false.");if("bar"===e.chart.type&&e.plotOptions.bar.horizontal){if(e.yaxis.length>1)throw new Error("Multiple Y Axis for bars are not supported. Switch to column chart by setting plotOptions.bar.horizontal=false");e.yaxis[0].reversed&&(e.yaxis[0].opposite=!0),e.xaxis.tooltip.enabled=!1,e.yaxis[0].tooltip.enabled=!1,e.chart.zoom.enabled=!1}return"bar"!==e.chart.type&&"rangeBar"!==e.chart.type||e.tooltip.shared&&"barWidth"===e.xaxis.crosshairs.width&&e.series.length>1&&(e.xaxis.crosshairs.width="tickWidth"),"candlestick"!==e.chart.type&&"boxPlot"!==e.chart.type||e.yaxis[0].reversed&&(e.yaxis[0].reversed=!1),e}}const B=1.618,N=[[1,1,2,5,5,5,10,10,10,10,10],[1,1,2,5,5,5,10,10,10,10,10]],O=[1,2,4,4,6,6,6,6,6,6,6,6,6,6,6,6,6,6,12,12,12,12,12,12,12,12,12,24];class Y{initGlobalVars(t){t.series=[],t.seriesCandleO=[],t.seriesCandleH=[],t.seriesCandleM=[],t.seriesCandleL=[],t.seriesCandleC=[],t.seriesRangeStart=[],t.seriesRangeEnd=[],t.seriesRange=[],t.seriesPercent=[],t.seriesGoals=[],t.seriesX=[],t.seriesZ=[],t.seriesNames=[],t.seriesTotals=[],t.seriesLog=[],t.seriesColors=[],t.stackedSeriesTotals=[],t.seriesXvalues=[],t.seriesYvalues=[],t.dataWasParsed=!1,t.originalSeries=null,t.maxValsInArrayIndex=0,t.yValueDecimal=0,t.allSeriesHasEqualX=!0,t.hasNullValues=!1,t.invalidLogScale=!1,t.seriesRangeName={},t.labels=[],t.hasXaxisGroups=!1,t.groups=[],t.barGroups=[],t.lineGroups=[],t.areaGroups=[],t.hasSeriesGroups=!1,t.seriesGroups=[],t.categoryLabels=[],t.timescaleLabels=[],t.noLabelsProvided=!1,t.isXNumeric=!1,t.skipLastTimelinelabel=!1,t.skipFirstTimelinelabel=!1,t.isDataXYZ=!1,t.isMultiLineX=!1,t.isMultipleYAxis=!1,t.maxY=-Number.MAX_VALUE,t.minY=Number.MIN_VALUE,t.minYArr=[],t.maxYArr=[],t.maxX=-Number.MAX_VALUE,t.minX=Number.MAX_VALUE,t.initialMaxX=-Number.MAX_VALUE,t.initialMinX=Number.MAX_VALUE,t.maxDate=0,t.minDate=Number.MAX_VALUE,t.minZ=Number.MAX_VALUE,t.maxZ=-Number.MAX_VALUE,t.minXDiff=Number.MAX_VALUE,t.yAxisScale=[],t.xAxisScale=null,t.xAxisTicksPositions=[],t.xRange=0,t.yRange=[],t.zRange=0,t.dataPoints=0,t.xTickAmount=0,t.multiAxisTickAmount=0,t.disableZoomIn=!1,t.disableZoomOut=!1,t.yLabelsCoords=[],t.yTitleCoords=[],t.barPadForNumericAxis=0,t.padHorizontal=0,t.rotateXLabels=!1,t.overlappingXLabels=!1,t.radialSize=0,t.barHeight=0,t.barWidth=0,t.animationEnded=!1,t.isDestroyed=!1,t.bulkRevealScheduled=!1,t.resizeTimer=null,t.selectionResizeTimer=null,t.delayedElements=[],t.pointsArray=[],t.barCanvasCoords=null,t.activeRenderer=null,t.dataLabelsRects=[],t.lastDrawnDataLabelsIndexes=[],t.textRectsCache=new Map,t.domCache=new Map,t.dimensionCache={},t.cachedSelectors={},t.seriesNS||this._attachNamespaces(t)}_attachNamespaces(t){const e=(e,i,s=i)=>{Object.defineProperty(e,s,{get:()=>t[i],set(e){t[i]=e},enumerable:!0,configurable:!0})},i={};e(i,"series","data");for(const t of["seriesNames","seriesX","seriesZ","seriesXvalues","seriesYvalues","seriesGoals","seriesLog","seriesColors","seriesPercent","seriesTotals","stackedSeriesTotals","seriesCandleO","seriesCandleH","seriesCandleM","seriesCandleL","seriesCandleC","seriesRangeStart","seriesRangeEnd","seriesRange","seriesYAxisMap","seriesYAxisReverseMap","seriesGroups","barGroups","lineGroups","areaGroups","originalSeries","collapsedSeries","collapsedSeriesIndices","ancillaryCollapsedSeries","ancillaryCollapsedSeriesIndices","collapsingSeriesIndices","allSeriesCollapsed","risingSeries","previousPaths","ignoreYAxisIndexes","labels","categoryLabels","timescaleLabels","groups"])e(i,t);Object.defineProperty(t,"seriesNS",{value:i,writable:!1,enumerable:!1,configurable:!0});const s={};for(const t of["minX","maxX","initialMinX","initialMaxX","minY","maxY","minYArr","maxYArr","minZ","maxZ","minDate","maxDate","minXDiff","xRange","yRange","zRange","xAxisScale","yAxisScale","xAxisTicksPositions","xTickAmount","multiAxisTickAmount","dataPoints","maxValsInArrayIndex","isXNumeric","isMultipleYAxis","isMultiLineX","isDataXYZ","dataFormatXNumeric","allSeriesHasEqualX","hasNullValues","dataWasParsed","hasXaxisGroups","hasSeriesGroups","skipFirstTimelinelabel","skipLastTimelinelabel","yValueDecimal","invalidLogScale","noLabelsProvided"])e(s,t);Object.defineProperty(t,"axes",{value:s,writable:!1,enumerable:!1,configurable:!0});const a={};for(const t of["svgWidth","svgHeight","gridWidth","gridHeight","translateX","translateY","translateXAxisX","translateXAxisY","translateYAxisX","xAxisLabelsHeight","xAxisGroupLabelsHeight","xAxisLabelsWidth","yAxisLabelsWidth","yAxisWidths","yLabelsCoords","yTitleCoords","padHorizontal","barPadForNumericAxis","rotateXLabels","scaleX","scaleY","radialSize","defaultLabels","overlappingXLabels"])e(a,t);Object.defineProperty(t,"layout",{value:a,writable:!1,enumerable:!1,configurable:!0});const r={};for(const t of["domCache","dimensionCache","cachedSelectors","textRectsCache","pointsArray","dataLabelsRects","lastDrawnDataLabelsIndexes","delayedElements","resizeTimer","selectionResizeTimer","resizeObserver"])e(r,t);Object.defineProperty(t,"cache",{value:r,writable:!1,enumerable:!1,configurable:!0})}globalVars(t){return{chartID:null,cuid:null,events:{beforeMount:[],mounted:[],updated:[],clicked:[],selection:[],dataPointSelection:[],zoomed:[],scrolled:[]},colors:[],fill:{colors:[]},radialNeedleRAF:null,unitGatherRAF:null,unitExitRAF:null,stroke:{colors:[]},dataLabels:{style:{colors:[]}},radarPolygons:{fill:{colors:[]}},markers:{colors:[],size:t.markers.size,largestSize:0,batched:!1},LINE_HEIGHT_RATIO:B,axisCharts:!0,isSlopeChart:t.plotOptions.line.isSlopeChart,comboCharts:!1,initialConfig:null,initialSeries:[],tokenSurface:void 0,lastXAxis:[],lastYAxis:[],allSeriesCollapsed:!1,collapsedSeries:[],collapsedSeriesIndices:[],ancillaryCollapsedSeries:[],ancillaryCollapsedSeriesIndices:[],collapsingSeriesIndices:[],risingSeries:[],ignoreYAxisIndexes:[],isDirty:!1,isExecCalled:!1,dataChanged:!1,resized:!1,columnSeries:null,yaxis:null,total:0,shouldAnimate:!0,previousPaths:[],prevPolarAngles:null,prevStreamFrame:null,streamScrolled:!1,prevChromeFrame:null,svgWidth:0,svgHeight:0,lastResizeSignature:null,defaultLabels:!1,yAxisLabelsWidth:0,scaleX:1,scaleY:1,translateYAxisX:[],yAxisWidths:[],tooltip:null,resizeObserver:null,locale:{},memory:{methodsToExec:[]},niceScaleAllowedMagMsd:N,niceScaleDefaultTicks:O,seriesYAxisMap:[],seriesYAxisReverseMap:[],noData:!1}}defineLazyInitialSeries(t){let e=[],i=null;Object.defineProperty(t,"initialSeries",{configurable:!0,enumerable:!0,get:()=>(null===i&&(i=v.clone(e)),i),set(s){e=v.copySeriesShallow(s),i=null,t._initialSeriesPeek=e}}),t._initialSeriesPeek=e}init(t){const e=this.globalVars(t);this.initGlobalVars(e),this.defineLazyInitialSeries(e);const i=v.extend({},t);return i.series=v.copySeriesShallow(t.series),e.initialConfig=i,e.initialSeries=t.series,e.lastXAxis=v.clone(e.initialConfig.xaxis),e.lastYAxis=v.clone(e.initialConfig.yaxis),e}}class W{constructor(t){this.opts=t}init(){const t=new X(this.opts).init({responsiveOverride:!1}),e=(new Y).init(t),i={config:t,globals:e,dom:{},interact:{zoomEnabled:"zoom"===t.chart.toolbar.autoSelected&&t.chart.toolbar.tools.zoom&&t.chart.zoom.enabled,panEnabled:"pan"===t.chart.toolbar.autoSelected&&t.chart.toolbar.tools.pan,selectionEnabled:"selection"===t.chart.toolbar.autoSelected&&t.chart.toolbar.tools.selection,measureEnabled:"measure"===t.chart.toolbar.autoSelected&&!!t.chart.toolbar.tools.measure&&!(!t.chart.measure||!t.chart.measure.enabled),zoomed:!1,selection:void 0,visibleXRange:void 0,selectedDataPoints:[],mousedown:!1,clientX:null,clientY:null,lastClientPosition:{},capturedSeriesIndex:-1,capturedDataPointIndex:-1,disableZoomIn:!1,disableZoomOut:!1,isTouchDevice:!!d.isBrowser()&&("ontouchstart"in window||navigator.maxTouchPoints>0)},formatters:{xLabelFormatter:void 0,yLabelFormatters:[],xaxisTooltipFormatter:void 0,ttKeyFormatter:void 0,ttVal:void 0,ttZFormatter:void 0,legendFormatter:void 0},candleData:{seriesCandleO:[],seriesCandleH:[],seriesCandleM:[],seriesCandleL:[],seriesCandleC:[],seriesBoxPoints:[]},rangeData:{seriesRangeStart:[],seriesRangeEnd:[],seriesRange:[]},violinData:{seriesViolinDensity:[],seriesViolinPoints:[],seriesViolinSummary:[],seriesViolinMin:[],seriesViolinMax:[]},histogramData:{edges:[],binWidth:0,counts:[],rule:"",capped:!1},waterfallData:{values:[],cumulative:[],kinds:[],geometry:null},dumbbellData:null,streamgraphData:null,labelData:{labels:[],categoryLabels:[],timescaleLabels:[],hasXaxisGroups:!1,groups:[],seriesGroups:[]},axisFlags:{isXNumeric:!1,dataFormatXNumeric:!1,isDataXYZ:!1,isRangeData:!1,isRangeBar:!1,isMultiLineX:!1,noLabelsProvided:!1,dataWasParsed:!1},seriesData:{series:[],seriesNames:[],seriesX:[],seriesZ:[],seriesColors:[],seriesGoals:[],stackedSeriesTotals:[],stackedSeriesTotalsByGroups:[],unitData:[]},layout:{gridHeight:0,gridWidth:0,translateX:0,translateY:0,translateXAxisX:0,translateXAxisY:0,rotateXLabels:!1,xAxisHeight:0,xAxisLabelsHeight:0,xAxisGroupLabelsHeight:0,xAxisLabelsWidth:0,yLabelsCoords:[],yTitleCoords:[],gridPad:{top:0,right:0,bottom:0,left:0}}};Object.defineProperty(e,"dom",{get:()=>i.dom,set(t){i.dom=t},enumerable:!1,configurable:!0});for(const t of["xLabelFormatter","yLabelFormatters","xaxisTooltipFormatter","ttKeyFormatter","ttVal","ttZFormatter","legendFormatter"])Object.defineProperty(e,t,{get:()=>i.formatters[t],set(e){i.formatters[t]=e},enumerable:!1,configurable:!0});for(const t of["zoomEnabled","panEnabled","selectionEnabled","zoomed","selection","visibleXRange","selectedDataPoints","mousedown","clientX","clientY","lastClientPosition","capturedSeriesIndex","capturedDataPointIndex","disableZoomIn","disableZoomOut","isTouchDevice"])Object.defineProperty(e,t,{get:()=>i.interact[t],set(e){i.interact[t]=e},enumerable:!1,configurable:!0});for(const t of["gridHeight","gridWidth","translateX","translateY","translateXAxisX","translateXAxisY","rotateXLabels","xAxisHeight","xAxisLabelsHeight","xAxisGroupLabelsHeight","xAxisLabelsWidth","yLabelsCoords","yTitleCoords","gridPad"])Object.defineProperty(e,t,{get:()=>i.layout[t],set(e){i.layout[t]=e},enumerable:!1,configurable:!0});for(const t of["series","seriesNames","seriesX","seriesZ","seriesColors","seriesGoals","stackedSeriesTotals","stackedSeriesTotalsByGroups"])Object.defineProperty(e,t,{get:()=>i.seriesData[t],set(e){i.seriesData[t]=e},enumerable:!1,configurable:!0});for(const t of["isXNumeric","dataFormatXNumeric","isDataXYZ","isRangeData","isRangeBar","isMultiLineX","noLabelsProvided","dataWasParsed"])Object.defineProperty(e,t,{get:()=>i.axisFlags[t],set(e){i.axisFlags[t]=e},enumerable:!1,configurable:!0});for(const t of["labels","categoryLabels","timescaleLabels","hasXaxisGroups","groups","seriesGroups"])Object.defineProperty(e,t,{get:()=>i.labelData[t],set(e){i.labelData[t]=e},enumerable:!1,configurable:!0});for(const t of["seriesRangeStart","seriesRangeEnd","seriesRange"])Object.defineProperty(e,t,{get:()=>i.rangeData[t],set(e){i.rangeData[t]=e},enumerable:!1,configurable:!0});for(const t of["seriesCandleO","seriesCandleH","seriesCandleM","seriesCandleL","seriesCandleC"])Object.defineProperty(e,t,{get:()=>i.candleData[t],set(e){i.candleData[t]=e},enumerable:!1,configurable:!0});for(const t of["seriesViolinDensity","seriesViolinPoints","seriesViolinMin","seriesViolinMax"])Object.defineProperty(e,t,{get:()=>i.violinData[t],set(e){i.violinData[t]=e},enumerable:!1,configurable:!0});return i}}class H{constructor(t){this.w=t}static checkComboSeries(t,e){let i=!1,s=0,a=0;return void 0===e&&(e="line"),t.length&&void 0!==t[0].type&&t.forEach(t=>{"bar"!==t.type&&"column"!==t.type&&"candlestick"!==t.type&&"boxPlot"!==t.type&&"violin"!==t.type||s++,void 0!==t.type&&t.type!==e&&a++}),a>0&&(i=!0),{comboBarCount:s,comboCharts:i}}getStackedSeriesTotals(t=[]){const e=this.w,i=[];if(0===e.seriesData.series.length)return i;for(let s=0;st+e,0);{const e=this.w.seriesData.series[t];return Array.isArray(e)?e.reduce((t,e)=>t+e,0):null!=e?e:0}}getStackedSeriesTotalsByGroups(){const t=this.w,e=[];return t.labelData.seriesGroups.forEach(i=>{const s=[];t.config.series.forEach((e,a)=>{i.indexOf(t.seriesData.seriesNames[a])>-1&&s.push(a)});const a=t.seriesData.series.map((t,e)=>-1===s.indexOf(e)?e:-1).filter(t=>-1!==t);e.push(this.getStackedSeriesTotals(a))}),e}setSeriesYAxisMappings(){const t=this.w.globals,e=this.w.config;let i=[];const s=[],a=[],r=this.w.seriesData.series.length>e.yaxis.length||e.yaxis.some(t=>Array.isArray(t.seriesName));e.series.forEach((t,e)=>{a.push(e),s.push(null)}),e.yaxis.forEach((t,e)=>{i[e]=[]});const n=[];e.yaxis.forEach((t,s)=>{let o=!1;if(t.seriesName){let n=[];Array.isArray(t.seriesName)?n=t.seriesName:n.push(t.seriesName),n.forEach(t=>{e.series.forEach((e,n)=>{if(e.name===t){let t=n;s===n||r?(!r||a.indexOf(n)>-1)&&i[s].push([s,n]):(i[n].push([n,s]),t=s),o=!0,t=a.indexOf(t),-1!==t&&a.splice(t,1)}})})}o||n.push(s)}),i=i.map(t=>{const e=[];return t.forEach(t=>{s[t[1]]=t[0],e.push(t[1])}),e});let o=e.yaxis.length-1;for(let t=0;t{i[o].push(t),s[t]=o}),t.seriesYAxisMap=i.map(t=>t),t.seriesYAxisReverseMap=s.map(t=>t),t.seriesYAxisMap.forEach((t,i)=>{t.forEach(t=>{if(e.series[t]&&void 0===e.series[t].group){e.series[t].group="apexcharts-axis-".concat(i.toString())}})})}isSeriesNull(t=null){let e=[];const i=this.w.config.series;return e=null===t?i.filter(t=>null!==t):i[t]&&Array.isArray(i[t].data)?i[t].data.filter(t=>null!==t):null!==i[t]&&void 0!==i[t]?[i[t]]:[],0===e.length}seriesHaveSameValues(t){const e=this.w.seriesData.series[t];return!Array.isArray(e)||e.every((t,e,i)=>t===i[0])}getCategoryLabels(t){const e=this.w;let i=t.slice();return e.config.xaxis.convertedCatToNumeric&&(i=t.map(t=>e.config.xaxis.labels.formatter(t-e.globals.minX+1))),i}getLargestSeries(){const t=this.w;t.globals.maxValsInArrayIndex=t.seriesData.series.map(t=>t.length).indexOf(Math.max.apply(Math,t.seriesData.series.map(t=>t.length)))}getLargestMarkerSize(){const t=this.w;let e=0;return t.globals.markers.size.forEach(t=>{e=Math.max(e,t)}),t.config.markers.discrete&&t.config.markers.discrete.length&&t.config.markers.discrete.forEach(t=>{e=Math.max(e,t.size)}),e>0&&(t.config.markers.hover.size>0?e=t.config.markers.hover.size:e+=t.config.markers.hover.sizeOffset),t.globals.markers.largestSize=e,e}getSeriesTotals(){const t=this.w;t.globals.seriesTotals=t.seriesData.series.map(t=>{let e=0;if(Array.isArray(t))for(let i=0;i{let r=0;for(let n=0;nt&&i.seriesData.seriesX[a][n]{const i=[];if(Array.isArray(e))for(let s=0;st+e,0);i.push(s)}return i})}getCalculatedRatios(){const t=this.w,e=t.globals,i=[];let s=0,a=0,r=0,n=0,o=[],l=.1,h=0;if(e.yRange=[],e.isMultipleYAxis)for(let t=0;t0){const r=(e,s)=>{const a=t.config.yaxis[t.globals.seriesYAxisReverseMap[s]];if(!a)return 0;if(a.logarithmic)return 0;return-(e<0?-1:1)*(e=Math.abs(e))/i[s]};if(e.isMultipleYAxis){o=[];for(let t=0;t{const s=e.globals.seriesYAxisReverseMap[i];return e.config.yaxis[s]&&e.config.yaxis[s].logarithmic?t.map(t=>null===t?null:this.getLogVal(e.config.yaxis[s].logBase,t,i)):t}),e.globals.invalidLogScale?t:e.globals.seriesLog}getLogValAtSeriesIndex(t,e){if(null===t)return null;const i=this.w,s=i.globals.seriesYAxisReverseMap[e];return i.config.yaxis[s]&&i.config.yaxis[s].logarithmic?this.getLogVal(i.config.yaxis[s].logBase,t,e):t}getBaseLog(t,e){return Math.log(e)/Math.log(t)}getLogVal(t,e,i){if(e<=0)return 0;const s=this.w,a=0===s.globals.minYArr[i]?-1:this.getBaseLog(t,s.globals.minYArr[i]),r=(0===s.globals.maxYArr[i]?0:this.getBaseLog(t,s.globals.maxYArr[i]))-a;return(this.getBaseLog(t,e)-a)/r}getLogYRatios(t){const e=this.w,i=this.w.globals,s=i;return s.yLogRatio=t.slice(),s.logYRange=i.yRange.map((t,a)=>{const r=e.globals.seriesYAxisReverseMap[a];if(e.config.yaxis[r]&&this.w.config.yaxis[r].logarithmic){const t=1;return s.yLogRatio[a]=t/this.w.layout.gridHeight,t}return i.yRange[a]}),s.invalidLogScale?t.slice():s.yLogRatio}static extendArrayProps(t,e,i){var s,a;return(null==e?void 0:e.yaxis)&&(e=t.extendYAxis(e,i)),(null==e?void 0:e.annotations)&&(e.annotations.yaxis&&(e=t.extendYAxisAnnotations(e)),(null==(s=null==e?void 0:e.annotations)?void 0:s.xaxis)&&(e=t.extendXAxisAnnotations(e)),(null==(a=null==e?void 0:e.annotations)?void 0:a.points)&&(e=t.extendPointAnnotations(e))),e}drawSeriesByGroup(t,e,i,s){const a=this.w,r=[];return t.series.length>0&&e.forEach(e=>{const n=[],o=[];t.i.forEach((i,s)=>{a.config.series[i].group===e&&(n.push(t.series[s]),o.push(i))}),n.length>0&&r.push(s.draw(n,i,o))}),r}}const $="http://www.w3.org/2000/svg";class G{constructor(t,e){"object"==typeof t?(this.x=t.x,this.y=t.y):(this.x=t||0,this.y=e||0)}transform(t){return t.apply(this)}clone(){return new G(this.x,this.y)}}class j{constructor(t,e,i,s,a,r){this.a=null!=t?t:1,this.b=null!=e?e:0,this.c=null!=i?i:0,this.d=null!=s?s:1,this.e=null!=a?a:0,this.f=null!=r?r:0}rotate(t){const e=t*Math.PI/180,i=Math.cos(e),s=Math.sin(e);return this.multiply(new j(i,s,-s,i,0,0))}scale(t,e){return this.multiply(new j(t,0,0,null!=e?e:t,0,0))}multiply(t){return new j(this.a*t.a+this.c*t.b,this.b*t.a+this.d*t.b,this.a*t.c+this.c*t.d,this.b*t.c+this.d*t.d,this.a*t.e+this.c*t.f+this.e,this.b*t.e+this.d*t.f+this.f)}apply(t){return new G(this.a*t.x+this.c*t.y+this.e,this.b*t.x+this.d*t.y+this.f)}}class V{constructor(t,e,i,s){this.x=t,this.y=e,this.w=i,this.h=s,this.width=i,this.height=s,this.x2=t+i,this.y2=e+s}}function U(t){if(!t||"string"!=typeof t)return[["M",0,0]];const e=[],i=/([MmLlHhVvCcSsQqTtAaZz])\s*/g,s=/[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?/gi;let a;const r=[],n=[];for(;null!==(a=i.exec(t));)r.push(a[1]),n.push(a.index);for(let i=0;i{for(let r=1;rs&&(s=n),oa&&(a=o))}}),e===1/0?{x:0,y:0,width:0,height:0}:{x:e,y:i,width:s-e,height:a-i}}function Z(t){return t.map(t=>t.join(" ")).join(" ")}function K(t){switch(t[0]){case"z":case"Z":t[0]="L",t[1]=this.start[0],t[2]=this.start[1];break;case"H":t[0]="L",t[2]=this.pos[1];break;case"V":t[0]="L",t[2]=t[1],t[1]=this.pos[0];break;case"T":t[0]="Q",t[3]=t[1],t[4]=t[2],t[1]=this.reflection[1],t[2]=this.reflection[0];break;case"S":t[0]="C",t[6]=t[4],t[5]=t[3],t[4]=t[2],t[3]=t[1],t[2]=this.reflection[1],t[1]=this.reflection[0]}return t}function J(t){var e=t.length;return this.pos=[t[e-2],t[e-1]],-1!="SCQT".indexOf(t[0])&&(this.reflection=[2*this.pos[0]-t[e-4],2*this.pos[1]-t[e-3]]),t}function Q(t){var e,i=[t];switch(t[0]){case"M":return this.pos=this.start=[t[1],t[2]],i;case"L":t[5]=t[3]=t[1],t[6]=t[4]=t[2],t[1]=this.pos[0],t[2]=this.pos[1];break;case"Q":t[6]=t[4],t[5]=t[3],t[4]=1*t[4]/3+2*t[2]/3,t[3]=1*t[3]/3+2*t[1]/3,t[2]=1*this.pos[1]/3+2*t[2]/3,t[1]=1*this.pos[0]/3+2*t[1]/3;break;case"A":i=function(t,e){var i,s,a,r,n,o,l,h,c,d,p,u,g,f,x,m,b,y,w,v,A,S,C,k,_,M,D=Math.abs(e[1]),L=Math.abs(e[2]),P=e[3]%360,F=e[4],E=e[5],T=e[6],I=e[7],R=new G(t[0],t[1]),z=new G(T,I),X=[];if(0===D||0===L||R.x===z.x&&R.y===z.y)return[["C",R.x,R.y,z.x,z.y,z.x,z.y]];i=new G((R.x-z.x)/2,(R.y-z.y)/2).transform((new j).rotate(P)),(s=i.x*i.x/(D*D)+i.y*i.y/(L*L))>1&&(D*=s=Math.sqrt(s),L*=s);a=(new j).rotate(P).scale(1/D,1/L).rotate(-P),R=R.transform(a),z=z.transform(a),r=[z.x-R.x,z.y-R.y],o=r[0]*r[0]+r[1]*r[1],n=Math.sqrt(o),r[0]/=n,r[1]/=n,l=o<4?Math.sqrt(1-o/4):0,F===E&&(l*=-1);h=new G((z.x+R.x)/2+l*-r[1],(z.y+R.y)/2+l*r[0]),c=new G(R.x-h.x,R.y-h.y),d=new G(z.x-h.x,z.y-h.y),p=Math.acos(c.x/Math.sqrt(c.x*c.x+c.y*c.y)),c.y<0&&(p*=-1);u=Math.acos(d.x/Math.sqrt(d.x*d.x+d.y*d.y)),d.y<0&&(u*=-1);E&&p>u&&(u+=2*Math.PI);!E&&p>16&255,i>>8&255,255&i,1]}const e=t.match(/rgba?\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*(?:,\s*([\d.]+))?\s*\)/);return e?[+e[1],+e[2],+e[3],void 0!==e[4]?+e[4]:1]:null}function ht(t,e,i){return`rgba(${Math.round(t[0]+(e[0]-t[0])*i)},${Math.round(t[1]+(e[1]-t[1])*i)},${Math.round(t[2]+(e[2]-t[2])*i)},${t[3]+(e[3]-t[3])*i})`}class ct{constructor(t,e,i){this.el=t,this.duration=null!=e?e:300,this.delay=i||0,this._attrTarget=null,this._plotTarget=null,this._plotSnap=null,this._plotAlgorithm="commands",this._afterCb=null,this._duringCb=null,this._easing=null,this._next=null,this._root=null,this._scheduled=!1}ease(t){return"function"==typeof t&&(this._easing=t),this._schedule(),this}attr(t){return this._attrTarget=t,this._schedule(),this}plot(t,e,i){return this._plotTarget=t,e&&(this._plotAlgorithm=e),this._plotSnap=i||null,this._schedule(),this}after(t){return this._afterCb=t,this._schedule(),this}during(t){return this._duringCb=t,this._schedule(),this}animate(t,e){const i=new ct(this.el,t,e);return this._next=i,i._root=this._root||this,i}_schedule(){const t=this._root||this;t._scheduled||(t._scheduled=!0,queueMicrotask(()=>t._executeChain()))}_executeChain(){const t=[];let e=this;for(;e;)t.push(e),e=e._next;let i=0;t.forEach(t=>{i+=t.delay,t._execute(i),i+=t.duration})}_execute(t){const e=this.el,i=this.duration;if(i<=1){const i=()=>{this._attrTarget&&e.attr(this._attrTarget),this._plotTarget&&e.plot(this._plotSnap||this._plotTarget),this._afterCb&&this._afterCb.call(e)};return void(t>0?setTimeout(i,t):i())}const s=()=>{const t={},s={},a={};if(this._attrTarget)for(const i of Object.keys(this._attrTarget)){const r=e.attr(i);t[i]=r;const n=lt(r),o=lt(String(this._attrTarget[i]));n&&o&&(s[i]=n,a[i]=o)}let r=null;if(this._plotTarget){const t=e.attr("d")||"";try{r="polygons"===this._plotAlgorithm?function(t,e,i=96){const s=rt(t,i),a=rt(e,i);let r=0,n=1/0;for(let t=0;t=n)break}e{const c=h-n,d=Math.min(c/i,1),p=o(d);if(this._attrTarget)if(d>=1)e.attr(this._attrTarget);else{const i={};for(const e of Object.keys(this._attrTarget))if(s[e]&&a[e])i[e]=ht(s[e],a[e],p);else{const s=parseFloat(t[e]),a=parseFloat(this._attrTarget[e]);isNaN(s)||isNaN(a)||(i[e]=s+(a-s)*p)}e.attr(i)}r&&d<1&&e.attr("d",r(p)),this._duringCb&&this._duringCb(p),d<1?b.requestAnimationFrame(l):(this._plotTarget&&e.attr("d",this._plotSnap||this._plotTarget),this._afterCb&&this._afterCb.call(e))};b.requestAnimationFrame(l)};t>0?setTimeout(s,t):s()}}function dt(t){t.prototype.animate=function(t,e){return new ct(this,t,e)}}function pt(t){return-Math.cos(t*Math.PI)/2+.5}function ut(t,e,i,s){t=Math.min(Math.max(t,0),1),i=Math.min(Math.max(i,0),1);const a=3*t,r=3*(i-t)-a,n=1-a-r,o=3*e,l=3*(s-e)-o,h=1-o-l,c=t=>((n*t+r)*t+a)*t;return t=>t<=0?0:t>=1?1:(t=>((h*t+l)*t+o)*t)((t=>{let e=0,i=1,s=t;if(si)return i;for(;ea?e=s:i=s,s=(e+i)/2}return s})(t))}const gt=new Map;function ft(t){return"function"==typeof t?xt(t):(e=t,Array.isArray(e)&&4===e.length&&e.every(t=>"number"==typeof t)?ut(t[0],t[1],t[2],t[3]):"string"==typeof t&>.has(t)?xt(gt.get(t)):pt);var e}function xt(t){return e=>{const i=t(e);return"number"==typeof i&&isFinite(i)?i:e}}gt.set("linear",t=>t),gt.set("easeInOutSine",pt),gt.set("easeInSine",t=>1-Math.cos(t*Math.PI/2)),gt.set("easeOutSine",t=>Math.sin(t*Math.PI/2)),gt.set("easeInQuad",t=>t*t),gt.set("easeOutQuad",t=>1-(1-t)*(1-t)),gt.set("easeInOutQuad",t=>t<.5?2*t*t:1-Math.pow(-2*t+2,2)/2),gt.set("easeInCubic",t=>t*t*t),gt.set("easeOutCubic",t=>1-Math.pow(1-t,3)),gt.set("easeInOutCubic",t=>t<.5?4*t*t*t:1-Math.pow(-2*t+2,3)/2),gt.set("easeOutBack",t=>{const e=1.70158;return 1+2.70158*Math.pow(t-1,3)+e*Math.pow(t-1,2)}),gt.set("easeInOutBack",t=>{const e=2.5949095;return t<.5?Math.pow(2*t,2)*(7.189819*t-e)/2:(Math.pow(2*t-2,2)*((e+1)*(2*t-2)+e)+2)/2});const mt="http://www.w3.org/2000/svg";function bt(t){return 1-Math.pow(1-t,3)}let yt=null;function wt(){if(!d.isBrowser())return!1;try{return yt||(yt=window.matchMedia("(prefers-reduced-motion: reduce)")),!!yt.matches}catch(t){return!1}}function vt(t,e,i){if(!d.isBrowser())return!1;if(i.globals.dataChanged||i.globals.resized)return!1;const s=i.config.chart.animations;if(!s||!1===s.enabled)return!1;const a=i.config.chart.type;if("line"!==a&&"area"!==a&&"rangeArea"!==a)return!1;if(!(i.layout.gridWidth>0))return!1;const r=2*(s.speed||800),n=Math.max(0,Math.min(1,e/i.layout.gridWidth)),o=(1-Math.cbrt(1-n))*r,l=t.node.style;l.opacity="0";let h=null;const c=t=>{null===h&&(h=t),t-h>=o?l.opacity="":b.requestAnimationFrame(c)};return b.requestAnimationFrame(c),!0}function At(t){const e=t.config.chart.animations;var i;e&&(!1!==e.respectReducedMotion&&wt()&&(e.enabled=!1,e.dynamicAnimation&&(e.dynamicAnimation.enabled=!1)),i=ft(e.easing),ot="function"==typeof i?i:nt)}function St(t){const e=t.style,i=t.index||0,s="number"==typeof t.baseDelay?t.baseDelay:40,a=t.row||0,r=t.col||0,n=t.groupIndex||0,o=t.perGroup||1,l=t.centerDistance||0;switch(e){case"none":return 0;case"diagonal":return(a+r)*s;case"group":return n*s+i%o*(s/4);case"centroid":return l*s*(i+1);default:return i*s}}class Ct{constructor(t,e){this.w=t,this.ctx=e}animateLine(t,e,i,s){t.attr(e).animate(s).attr(i)}animateMarker(t,e,i,s){t.attr({opacity:0}).animate(e).attr({opacity:1}).after(()=>{s()})}animatePop(t,{speed:e,delay:i=0,onComplete:s}){const a=this.w;if(!d.isBrowser()||!a.globals.shouldAnimate||e<1)return void(s&&s());const r=t.node.style;r.transformBox="fill-box",r.transformOrigin="center",r.transform="scale(0)",r.opacity="0";const n=performance.now()+i,o=t=>{if(a.globals.isDestroyed)return;const i=Math.max(0,Math.min(1,(t-n)/e));r.transform=`scale(${function(t){const e=1.70158;return 1+2.70158*Math.pow(t-1,3)+e*Math.pow(t-1,2)}(i)})`,r.opacity=String(Math.min(1,2*i)),i<1?b.requestAnimationFrame(o):(r.transform="",r.transformOrigin="",r.transformBox="",r.opacity="",s&&s())};b.requestAnimationFrame(o)}animateRect(t,e,i,s,a,r=0){t.attr(e).animate(s,r).attr(i).after(()=>a())}animatePathsGradually(t){const{el:e,realIndex:i,j:s,fill:a,pathFrom:r,pathTo:n,pathToInterp:o,speed:l,delay:h,scrollMorph:c}=t,d=this.w;let p=0;d.config.chart.animations.animateGradually.enabled&&(p=d.config.chart.animations.animateGradually.delay),d.config.chart.animations.dynamicAnimation.enabled&&d.globals.dataChanged&&"bar"!==d.config.chart.type&&(p=0),this.morphSVG(e,i,s,"line"!==d.config.chart.type||d.globals.comboCharts?a:"stroke",r,n,l,h*p,c,o)}revealBulk(t){const e=this.w;t.node.classList.add("apexcharts-element-hidden"),e.globals.delayedElements.push({el:t.node}),d.isBrowser()&&e.globals.shouldAnimate?e.globals.bulkRevealScheduled||(e.globals.bulkRevealScheduled=!0,b.requestAnimationFrame(()=>{e.globals.isDestroyed||(e.globals.bulkRevealScheduled=!1,this.animationCompleted(t))})):this.animationCompleted(t)}showDelayedElements(){this.w.globals.delayedElements.forEach(t=>{if(t.holdUntilComplete&&!this.w.globals.animationEnded)return;const e=t.el;e.classList.remove("apexcharts-element-hidden"),e.classList.add("apexcharts-hidden-element-shown")})}animationCompleted(t){const e=this.w;e.globals.animationEnded||(e.globals.animationEnded=!0,this.showDelayedElements(),"function"==typeof e.config.chart.events.animationEnd&&e.config.chart.events.animationEnd(this.ctx,{el:t,w:e}))}animateDraw(t,{realIndex:e,j:i,isFill:s,isLast:a,speed:r,delay:n,mask:o}){const l=this.w,h=this,c=()=>{a&&l.globals.shouldAnimate&&h.animationCompleted(t),h.showDelayedElements()};if(!d.isBrowser()||!l.globals.shouldAnimate||r<1)return void c();const p=t.node,u=()=>{const t=o&&"radial"===o.type,a=l.layout.gridWidth+8,h=o&&o.cx||0,d=o&&o.cy||0,u=(o&&o.r||l.layout.gridWidth/2)+4,g=`apexDrawMask${l.globals.cuid}-${e}-${null!=i?i:0}-${s?"f":"s"}`,f=b.createElementNS(mt,"mask");let x;if(f.setAttribute("id",g),f.setAttribute("maskUnits","userSpaceOnUse"),t){const t=u;f.setAttribute("x",String(h-t)),f.setAttribute("y",String(d-t)),f.setAttribute("width",String(2*t)),f.setAttribute("height",String(2*t)),x=b.createElementNS(mt,"circle"),x.setAttribute("cx",String(h)),x.setAttribute("cy",String(d)),x.setAttribute("r","0"),x.setAttribute("fill","#fff")}else f.setAttribute("x",String(-4)),f.setAttribute("y",String(-4)),f.setAttribute("width",String(a)),f.setAttribute("height",String(l.layout.gridHeight+8)),x=b.createElementNS(mt,"rect"),x.setAttribute("x",String(-4)),x.setAttribute("y",String(-4)),x.setAttribute("width","0"),x.setAttribute("height",String(l.layout.gridHeight+8)),x.setAttribute("fill","#fff");f.appendChild(x),l.dom.elDefs.node.appendChild(f),p.setAttribute("mask",`url(#${g})`);const m=performance.now()+(n||0),y=e=>{if(l.globals.isDestroyed)return;const i=Math.max(0,Math.min(1,(e-m)/r)),s=bt(i);t?x.setAttribute("r",String(s*u)):x.setAttribute("width",String(s*a)),i<1?b.requestAnimationFrame(y):(p.removeAttribute("mask"),f.parentNode&&f.parentNode.removeChild(f),c())};b.requestAnimationFrame(y)};b.requestAnimationFrame(()=>{if(l.globals.isDestroyed)return;if(s)return void u();const t=p.getAttribute("stroke-dasharray");if(!!t&&"0"!==t&&""!==t)return void u();let e=0;try{"function"==typeof p.getTotalLength&&(e=p.getTotalLength())}catch(t){e=0}e?(t=>{p.setAttribute("stroke-dasharray",String(t)),p.setAttribute("stroke-dashoffset",String(t));const e=performance.now()+(n||0),i=s=>{if(l.globals.isDestroyed)return;const a=Math.max(0,Math.min(1,(s-e)/r));p.setAttribute("stroke-dashoffset",String(t*(1-bt(a)))),a<1?b.requestAnimationFrame(i):(p.removeAttribute("stroke-dasharray"),p.removeAttribute("stroke-dashoffset"),c())};b.requestAnimationFrame(i)})(e):c()})}morphSVG(t,e,i,s,a,r,n,o,l,h){var c,d;const p=this.w;a||(a=t.attr("pathFrom")),r||(r=t.attr("pathTo"));const u=()=>("radar"===p.config.chart.type&&(n=1),`M 0 ${p.layout.gridHeight}`);(!a||a.indexOf("undefined")>-1||a.indexOf("NaN")>-1)&&(a=u()),(!r.trim()||r.indexOf("undefined")>-1||r.indexOf("NaN")>-1)&&(r=u(),h=void 0),h&&(!h.trim()||h.indexOf("undefined")>-1||h.indexOf("NaN")>-1)&&(h=void 0),p.globals.shouldAnimate||(n=1);const g=!0===(null==(d=null==(c=this.ctx)?void 0:c.morphTypeChange)?void 0:d.isActive())?"polygons":"commands";let f=null;if(p.globals.dataChanged){const t=p.config.chart.animations.dynamicAnimation.easing;null!=t?f=ft(t):l&&(f=ft("linear"))}const x=t.plot(a).animate(n,o);f&&x.ease(f),x.plot(h||r,g,h?r:void 0).after(()=>{if(v.isNumber(i)){const e=p.seriesData.series[p.globals.maxValsInArrayIndex];e&&i===e.length-2&&p.globals.shouldAnimate&&this.animationCompleted(t)}else"none"!==s&&p.globals.shouldAnimate&&(!p.globals.comboCharts&&e===p.seriesData.series.length-1||p.globals.comboCharts)&&this.animationCompleted(t);this.showDelayedElements()})}}const kt=.15,_t=.35;class Mt{constructor(t){this.w=t}static isSliceChart(t){const e=t.config.chart.type;return"pie"===e||"donut"===e||"polarArea"===e}static hoverOutlineOwnsHoverState(t){var e;return Mt.isSliceChart(t)&&"none"!==t.config.states.hover.filter.type&&!0===(null==(e=t.config.plotOptions.pie.hoverOutline)?void 0:e.show)}static sliceOffsetOwnsActiveState(t){return Mt.isSliceChart(t)&&"polarArea"!==t.config.chart.type&&!0===t.config.plotOptions.pie.expandOnClick&&t.config.plotOptions.pie.expandOffset>0&&!Mt.drilldownBlocksSliceOffset(t)}static drilldownBlocksSliceOffset(t){var e;return Mt.isSliceChart(t)&&!0===(null==(e=t.config.drilldown)?void 0:e.enabled)}getDefaultFilter(t,e){const i=this.w;t.unfilter&&t.unfilter(!0),i.config.chart.dropShadow.enabled&&this.dropShadow(t,i.config.chart.dropShadow,e)}applyFilter(t,e,i,s){var a,r,n;const o=this.w;if(t.unfilter&&t.unfilter(!0),"none"===i)return void this.getDefaultFilter(t,e);const l=o.config.chart.dropShadow,h="lighten"===i?kt:_t,c=Math.max(0,Math.min(1,"number"==typeof s?s:h)),d=1-c,p="lighten"===i?c:0;t.filterWith&&(t.filterWith(t=>{t.colorMatrix({type:"matrix",values:`\n ${d} 0 0 0 ${p}\n 0 ${d} 0 0 ${p}\n 0 0 ${d} 0 ${p}\n 0 0 0 1 0\n `,in:"SourceGraphic",result:"brightness"}),l.enabled&&this.addShadow(t,e,l,"brightness")}),l.noUserSpaceOnUse||null==(r=null==(a=t.filterer())?void 0:a.node)||r.setAttribute("filterUnits","userSpaceOnUse"),this._scaleFilterSize(null==(n=t.filterer())?void 0:n.node))}addShadow(t,e,i,s){var a;const r=this.w;let{blur:n,top:o,left:l,color:h,opacity:c}=i;if(h=Array.isArray(h)?h[e]:h,(null==(a=r.config.chart.dropShadow.enabledOnSeries)?void 0:a.length)>0&&-1===r.config.chart.dropShadow.enabledOnSeries.indexOf(e))return t;t.offset({in:s,dx:l,dy:o,result:"offset"}),t.gaussianBlur({in:"offset",stdDeviation:n,result:"blur"}),t.flood({"flood-color":h,"flood-opacity":c,result:"flood"}),t.composite({in:"flood",in2:"blur",operator:"in",result:"shadow"}),t.merge(["shadow",s])}dropShadow(t,e,i=0){var s,a,r,n,o;const l=this.w;return t.unfilter&&t.unfilter(!0),v.isMsEdge()&&"radialBar"===l.config.chart.type||(null==(s=l.config.chart.dropShadow.enabledOnSeries)?void 0:s.length)>0&&-1===(null==(a=l.config.chart.dropShadow.enabledOnSeries)?void 0:a.indexOf(i))||t.filterWith&&(t.filterWith(t=>{this.addShadow(t,i,e,"SourceGraphic")}),e.noUserSpaceOnUse||null==(n=null==(r=t.filterer())?void 0:r.node)||n.setAttribute("filterUnits","userSpaceOnUse"),this._scaleFilterSize(null==(o=t.filterer())?void 0:o.node)),t}setSelectionFilter(t,e,i){const s=this.w;if(void 0!==s.interact.selectedDataPoints[e]&&s.interact.selectedDataPoints[e].indexOf(i)>-1){if(t.node.setAttribute("selected",!0),Mt.sliceOffsetOwnsActiveState(s))return;const i=s.config.states.active.filter;"none"!==i.type&&this.applyFilter(t,e,i.type,i.value)}}_scaleFilterSize(t){if(!t)return;(e=>{for(const i in e)Object.prototype.hasOwnProperty.call(e,i)&&t.setAttribute(i,e[i])})({width:"200%",height:"200%",x:"-50%",y:"-50%"})}}class Dt{constructor(t,e=null){this.w=t,this.ctx=e}roundPathCorners(t,e){function i(t,e,i){var a=e.x-t.x,r=e.y-t.y,n=Math.sqrt(a*a+r*r);return n?s(t,e,Math.min(1,i/n)):{x:t.x,y:t.y}}function s(t,e,i){return{x:t.x+(e.x-t.x)*i,y:t.y+(e.y-t.y)*i}}function a(t,e){t.length>2&&(t[t.length-2]=e.x,t[t.length-1]=e.y)}function r(t){return{x:parseFloat(t[t.length-2]),y:parseFloat(t[t.length-1])}}t.indexOf("NaN")>-1&&(t="");var n=t.split(/[,\s]/).reduce(function(t,e){var i=e.match(/^([a-zA-Z])(.+)/);return i?(t.push(i[1]),t.push(i[2])):t.push(e),t},[]).reduce(function(t,e){return parseFloat(e)==e&&t.length?t[t.length-1].push(e):t.push([e]),t},[]),o=[];if(n.length>1){var l=r(n[0]),h=null;"Z"==n[n.length-1][0]&&n[0].length>2&&(h=["L",l.x,l.y],n[n.length-1]=h),o.push(n[0]);for(var c=1;c2&&"L"==p[0]&&u.length>2&&"L"==u[0]){var g,f,x=r(d),m=r(p),b=r(u);g=i(m,x,e),f=i(m,b,e),a(p,g),p.origPoint=m,o.push(p);var y=s(g,m,.5),w=s(m,f,.5),v=["C",y.x,y.y,w.x,w.y,f.x,f.y];v.origPoint=m,o.push(v)}else o.push(p)}if(h){var A=r(o[o.length-1]);o.push(["Z"]),a(o[0],A)}}else o=n;return o.reduce(function(t,e){return t+e.join(" ")+" "},"")}drawLine(t,e,i,s,a="#a8a8a8",r=0,n=null,o="butt"){return this.w.dom.Paper.line().attr({x1:t,y1:e,x2:i,y2:s,stroke:a,"stroke-dasharray":r,"stroke-width":n,"stroke-linecap":o})}drawRect(t=0,e=0,i=0,s=0,a=0,r="#fefefe",n=1,o=null,l=null,h=0){const c=this.w.dom.Paper.rect();return c.attr({x:t,y:e,width:i>0?i:0,height:s>0?s:0,rx:a,ry:a,opacity:n,"stroke-width":null!==o?o:0,stroke:null!==l?l:"none","stroke-dasharray":h}),c.node.setAttribute("fill",r),c}drawPolygon(t,e="#e1e1e1",i=1,s="none"){return this.w.dom.Paper.polygon(t).attr({fill:s,stroke:e,"stroke-width":i})}drawCircle(t,e=null){t<0&&(t=0);const i=this.w.dom.Paper.circle(2*t);return null!==e&&i.attr(e),i}drawPath({d:t="",stroke:e="#a8a8a8",strokeWidth:i=1,fill:s,fillOpacity:a=1,strokeOpacity:r=1,classes:n,strokeLinecap:o=null,strokeDashArray:l=0}){const h=this.w;null===o&&(o=h.config.stroke.lineCap),(t.indexOf("undefined")>-1||t.indexOf("NaN")>-1)&&(t=`M 0 ${h.layout.gridHeight}`);return h.dom.Paper.path(t).attr({fill:s,"fill-opacity":a,stroke:e,"stroke-opacity":r,"stroke-linecap":o,"stroke-width":i,"stroke-dasharray":l,class:n})}group(t=null){const e=this.w.dom.Paper.group();return null!==t&&e.attr(t),e}move(t,e){return["M",t,e].join(" ")}line(t,e,i=null){return"H"===i?[" H",t].join(" "):"V"===i?[" V",e].join(" "):[" L",t,e].join(" ")}curve(t,e,i,s,a,r){return["C",t,e,i,s,a,r].join(" ")}quadraticCurve(t,e,i,s){return["Q",t,e,i,s].join(" ")}arc(t,e,i,s,a,r,n,o=!1){let l="A";o&&(l="a");return[l,t,e,i,s,a,r,n].join(" ")}renderPaths({j:t,realIndex:e,pathFrom:i,pathTo:s,pathToInterp:a,stroke:r,strokeWidth:n,strokeLinecap:h,fill:c,animationDelay:d,initialSpeed:p,dataChangeSpeed:u,className:g,chartType:f,shouldClipToGrid:x=!0,bindEventsOnPaths:m=!0,drawShadow:b=!0,drawMask:y=null,scrollMorph:w=!1}){var v,A,S,C;const k=this.w,_=new Mt(this.w),M=new Ct(this.w,null!=(v=this.ctx)?v:void 0),D=this.w.config.chart.animations.enabled,L=D&&this.w.config.chart.animations.dynamicAnimation.enabled;if(i&&i.startsWith("M 0 0 ")&&s){const t=s.match(/^M\s+[\d.-]+\s+[\d.-]+/);t&&(i=i.replace(/^M\s+0\s+0/,t[0]))}let P;const F=!0===(null==(S=null==(A=this.ctx)?void 0:A.morphTypeChange)?void 0:S.isActive()),E=!!(D&&!k.globals.resized||L&&k.globals.dataChanged&&k.globals.shouldAnimate||F&&D&&k.globals.shouldAnimate),T="string"==typeof g&&(g.indexOf("apexcharts-line")>-1||g.indexOf("apexcharts-area")>-1||g.indexOf("apexcharts-rangeArea")>-1||g.indexOf("apexcharts-radar")>-1),I=!(!D||k.globals.resized||k.globals.dataChanged||!T),R=null!=(C=k.config.chart.animations.largeDatasetThreshold)?C:0,z=!!(E&&!I&&R>0&&k.globals.dataPoints>R),X=!(!("candlestick"===f||"boxPlot"===f)||!E||I||!k.globals.dataChanged||F),B=z||X;!E||I||B?(P=s,E||(k.globals.animationEnded=!0)):P=i;const N=k.config.stroke.dashArray;let O=0;O=Array.isArray(N)?N[e]:k.config.stroke.dashArray;const Y=this.drawPath({d:P,stroke:r,strokeWidth:n,fill:c,fillOpacity:1,classes:g,strokeLinecap:h,strokeDashArray:O});Y.attr("index",e),x&&("bar"===f&&!k.globals.isBarHorizontal||k.globals.comboCharts?Y.attr({"clip-path":`url(#gridRectBarMask${k.globals.cuid})`}):Y.attr({"clip-path":`url(#gridRectMask${k.globals.cuid})`})),k.config.chart.dropShadow.enabled&&b&&_.dropShadow(Y,k.config.chart.dropShadow,e),m&&(Y.node.addEventListener("mouseenter",this.pathMouseEnter.bind(this,Y)),Y.node.addEventListener("mouseleave",this.pathMouseLeave.bind(this,Y)),Y.node.addEventListener("mousedown",this.pathMouseDown.bind(this,Y))),Y.attr({pathTo:s,pathFrom:i});const W={el:Y,j:t,realIndex:e,pathFrom:i,pathTo:s,pathToInterp:a,fill:c,strokeWidth:n,delay:d,scrollMorph:w};if(!D||k.globals.resized||k.globals.dataChanged)!k.globals.resized&&k.globals.dataChanged||B||M.showDelayedElements();else if(I){const i=2*p,s="none"===r||0===n,a=k.seriesData.series.length,o=!!k.globals.comboCharts||e===a-1;M.animateDraw(Y,{realIndex:e,j:t,isFill:s,isLast:o,speed:i,delay:0,mask:y})}else B||M.animatePathsGradually(l(o({},W),{speed:p}));return E&&!B&&(k.globals.dataChanged&&L||F)&&M.animatePathsGradually(l(o({},W),{speed:u})),B&&M.revealBulk(Y),Y}drawPattern(t,e,i,s="#a8a8a8",a=0){return this.w.dom.Paper.pattern(e,i,r=>{"horizontalLines"===t?r.line(0,0,i,0).stroke({color:s,width:a+1}):"verticalLines"===t?r.line(0,0,0,e).stroke({color:s,width:a+1}):"slantedLines"===t?r.line(0,0,e,i).stroke({color:s,width:a}):"squares"===t?r.rect(e,i).fill("none").stroke({color:s,width:a}):"circles"===t&&r.circle(e).fill("none").stroke({color:s,width:a})})}drawGradient(t,e,i,s,a,r=null,n=null,o=[],l=0,h=!1){const c=this.w;let d;e.length<9&&0===e.indexOf("#")&&(e=v.hexToRgba(e,s)),i.length<9&&0===i.indexOf("#")&&(i=v.hexToRgba(i,a));let p=0,u=1,g=1,f=null;null!==n&&(p=void 0!==n[0]?n[0]/100:0,u=void 0!==n[1]?n[1]/100:1,g=void 0!==n[2]?n[2]/100:1,f=void 0!==n[3]?n[3]/100:null);const x=!("donut"!==c.config.chart.type&&"pie"!==c.config.chart.type&&"polarArea"!==c.config.chart.type&&"bubble"!==c.config.chart.type);if(d=o&&0!==o.length?c.dom.Paper.gradient(x?"radial":"linear",t=>{(Array.isArray(o[l])?o[l]:Array.isArray(o[0])?o[0]||[]:o).forEach(e=>{t.stop(e.offset/100,e.color,e.opacity)})}):c.dom.Paper.gradient(x?"radial":"linear",t=>{t.stop(p,e,s),t.stop(u,i,a),t.stop(g,i,a),null!==f&&t.stop(f,e,s)}),x){const t=c.layout.gridWidth/2,e=c.layout.gridHeight/2;"bubble"!==c.config.chart.type?d.attr({gradientUnits:"userSpaceOnUse",cx:t,cy:e,r:r}):d.attr({cx:.5,cy:.5,r:.8,fx:.2,fy:.2})}else"vertical"===t?h?(d.attr({gradientUnits:"userSpaceOnUse"}),d.from(0,0).to(0,c.layout.gridHeight)):d.from(0,0).to(0,1):"diagonal"===t?d.from(0,0).to(1,1):"horizontal"===t?d.from(0,1).to(1,1):"diagonal2"===t&&d.from(1,0).to(0,1);return d}getTextBasedOnMaxWidth({text:t,maxWidth:e,fontSize:i,fontFamily:s}){const a=this.getTextRects(t,i,s,""),r=a.width/t.length,n=Math.floor(e/r);return e{for(let e=0;et.tspan(f))),m.attr({x:t,y:e,"text-anchor":s,"dominant-baseline":u,"font-size":a,"font-family":r,"font-weight":n,fill:l,class:"apexcharts-text "+d}),m.node.style.fontFamily=r,m.node.style.opacity=h,m}getMarkerPath(t,e,i,s){let a="";switch(i){case"cross":a=`M ${t-(s/=1.4)} ${e-s} L ${t+s} ${e+s} M ${t-s} ${e+s} L ${t+s} ${e-s}`;break;case"plus":a=`M ${t-(s/=1.12)} ${e} L ${t+s} ${e} M ${t} ${e-s} L ${t} ${e+s}`;break;case"star":case"sparkle":{let r=5;s*=1.15,"sparkle"===i&&(s/=1.1,r=4);const n=Math.PI/r;for(let i=0;i<=2*r;i++){const r=i*n,o=i%2==0?s:s/2;a+=(0===i?"M":"L")+(t+o*Math.sin(r))+","+(e-o*Math.cos(r))}a+="Z";break}case"triangle":a=`M ${t} ${e-s} \n L ${t+s} ${e+s} \n L ${t-s} ${e+s} \n Z`;break;case"square":case"rect":a=`M ${t-(s/=1.125)} ${e-s} \n L ${t+s} ${e-s} \n L ${t+s} ${e+s} \n L ${t-s} ${e+s} \n Z`;break;case"diamond":a=`M ${t} ${e-(s*=1.05)} \n L ${t+s} ${e} \n L ${t} ${e+s} \n L ${t-s} ${e} \n Z`;break;case"line":a=`M ${t-(s/=1.1)} ${e} \n L ${t+s} ${e}`;break;default:a=`M ${t}, ${e} \n m -${(s*=2)/2}, 0 \n a ${s/2},${s/2} 0 1,0 ${s},0 \n a ${s/2},${s/2} 0 1,0 -${s},0`}return a}drawMarkerShape(t,e,i,s,a){const r=this.drawPath({d:this.getMarkerPath(t,e,i,s),stroke:a.pointStrokeColor,strokeDashArray:a.pointStrokeDashArray,strokeWidth:a.pointStrokeWidth,fill:a.pointFillColor,fillOpacity:a.pointFillOpacity,strokeOpacity:a.pointStrokeOpacity});return r.attr({cx:t,cy:e,shape:a.shape,class:a.class?a.class:""}),r}drawMarker(t,e,i){t=t||0;let s=i.pSize||0;return v.isNumber(e)||(s=0,e=0),this.drawMarkerShape(t,e,null==i?void 0:i.shape,s,o(o({},i),"line"===i.shape||"plus"===i.shape||"cross"===i.shape?{pointStrokeColor:i.pointFillColor,pointStrokeOpacity:i.pointFillOpacity}:{}))}pathMouseEnter(t,e){var i,s;const a=this.w,r=new Mt(this.w),n=parseInt(null!=(i=t.node.getAttribute("index"))?i:"",10),o=parseInt(null!=(s=t.node.getAttribute("j"))?s:"",10);if(!(isNaN(n)||isNaN(o)||("function"==typeof a.config.chart.events.dataPointMouseEnter&&a.config.chart.events.dataPointMouseEnter(e,this.ctx,{seriesIndex:n,dataPointIndex:o,w:a}),Dt._fireEvent(a,"dataPointMouseEnter",[e,this.ctx,{seriesIndex:n,dataPointIndex:o,w:a}]),"none"!==a.config.states.active.filter.type&&"true"===t.node.getAttribute("selected")||Mt.hoverOutlineOwnsHoverState(a)||"none"===a.config.states.hover.filter.type||a.interact.isTouchDevice))){const e=a.config.states.hover.filter;r.applyFilter(t,n,e.type,e.value)}}pathMouseLeave(t,e){var i,s;const a=this.w,r=new Mt(this.w),n=parseInt(null!=(i=t.node.getAttribute("index"))?i:"",10),o=parseInt(null!=(s=t.node.getAttribute("j"))?s:"",10);isNaN(n)||isNaN(o)||("function"==typeof a.config.chart.events.dataPointMouseLeave&&a.config.chart.events.dataPointMouseLeave(e,this.ctx,{seriesIndex:n,dataPointIndex:o,w:a}),Dt._fireEvent(a,"dataPointMouseLeave",[e,this.ctx,{seriesIndex:n,dataPointIndex:o,w:a}]),"none"!==a.config.states.active.filter.type&&"true"===t.node.getAttribute("selected")||Mt.hoverOutlineOwnsHoverState(a)||"none"!==a.config.states.hover.filter.type&&r.getDefaultFilter(t,n))}_clearAllDataPointSelections(t,e){const i=this.w;i.interact.selectedDataPoints=[];const s=i.dom.Paper.find(".apexcharts-series path:not(.apexcharts-decoration-element)"),a=i.dom.Paper.find(".apexcharts-series circle:not(.apexcharts-decoration-element), .apexcharts-series rect:not(.apexcharts-decoration-element)"),r=i=>{Array.prototype.forEach.call(i,i=>{i.node.setAttribute("selected","false"),t.getDefaultFilter(i,e)})};r(s),r(a)}_togglePointSelection(t,e,i,s){const a=this.w;if("true"===t.node.getAttribute("selected")){t.node.setAttribute("selected","false");const e=a.interact.selectedDataPoints[i].indexOf(s);return e>-1&&a.interact.selectedDataPoints[i].splice(e,1),"false"}return!a.config.states.active.allowMultipleDataPointsSelection&&a.interact.selectedDataPoints.length>0&&this._clearAllDataPointSelections(e,i),t.node.setAttribute("selected","true"),void 0===a.interact.selectedDataPoints[i]&&(a.interact.selectedDataPoints[i]=[]),a.interact.selectedDataPoints[i].push(s),"true"}_applyPointSelectionFilter(t,e,i,s){const a=this.w;if(!Mt.sliceOffsetOwnsActiveState(a))if("true"===s){const s=a.config.states.active.filter;if("none"!==s)e.applyFilter(t,i,s.type,s.value);else if("none"!==a.config.states.hover.filter&&!a.interact.isTouchDevice){const s=a.config.states.hover.filter;e.applyFilter(t,i,s.type,s.value)}}else if("none"!==a.config.states.active.filter.type)if("none"===a.config.states.hover.filter.type||a.interact.isTouchDevice)e.getDefaultFilter(t,i);else{const s=a.config.states.hover.filter;e.applyFilter(t,i,s.type,s.value)}}pathMouseDown(t,e){var i,s;const a=this.w,r=new Mt(this.w),n=parseInt(null!=(i=t.node.getAttribute("index"))?i:"",10),o=parseInt(null!=(s=t.node.getAttribute("j"))?s:"",10);if(isNaN(n)||isNaN(o))return;const l=a.config.chart.link;if(!!(!l||"function"!=typeof l.dimension&&!l.enabled)){const e=this._togglePointSelection(t,r,n,o);this._applyPointSelectionFilter(t,r,n,e)}"function"==typeof a.config.chart.events.dataPointSelection&&a.config.chart.events.dataPointSelection(e,this.ctx,{selectedDataPoints:a.interact.selectedDataPoints,seriesIndex:n,dataPointIndex:o,w:a}),e&&Dt._fireEvent(a,"dataPointSelection",[e,this.ctx,{selectedDataPoints:a.interact.selectedDataPoints,seriesIndex:n,dataPointIndex:o,w:a}])}rotateAroundCenter(t){let e={};t&&"function"==typeof t.getBBox&&(e=t.getBBox());return{x:e.x+e.width/2,y:e.y+e.height/2}}setupEventDelegation(t,e){let i=null;t.node.addEventListener("mouseover",s=>{const a=Dt._findDelegateTarget(s.target,t.node,e);a&&a!==i&&(i&&i.instance&&this.pathMouseLeave(i.instance,s),i=a,a.instance&&this.pathMouseEnter(a.instance,s))}),t.node.addEventListener("mouseout",s=>{if(!i)return;(s.relatedTarget?Dt._findDelegateTarget(s.relatedTarget,t.node,e):null)!==i&&(i&&i.instance&&this.pathMouseLeave(i.instance,s),i=null)}),t.node.addEventListener("mousedown",i=>{const s=Dt._findDelegateTarget(i.target,t.node,e);s&&s.instance&&this.pathMouseDown(s.instance,i)})}static _fireEvent(t,e,i){const s=t.globals.events;if(!s||!Object.prototype.hasOwnProperty.call(s,e))return;const a=s[e];for(let t=0;t0&&t.getComputedTextLength()>=i/1.1)){for(let s=e.length-3;s>0;s-=3)if(t.getSubStringLength(0,s)<=i/1.1)return void(t.textContent=e.substring(0,s)+"...");t.textContent="."}}}class Lt{constructor(t){this.w=t,this.opts=null,this.seriesIndex=0,this.patternIDs=[]}clippedImgArea(t){const e=this.w,i=e.config,s=parseInt(String(e.layout.gridWidth),10),a=parseInt(String(e.layout.gridHeight),10),r=s>a?s:a,n=t.image;let o=0,l=0;void 0===t.width&&void 0===t.height?void 0!==i.fill.image.width&&void 0!==i.fill.image.height?(o=i.fill.image.width+1,l=i.fill.image.height):(o=r+1,l=r):(o=t.width,l=t.height);const h=b.createElementNS($,"pattern");Dt.setAttrs(h,{id:t.patternID,patternUnits:t.patternUnits?t.patternUnits:"userSpaceOnUse",width:o+"px",height:l+"px"});const c=b.createElementNS($,"image");h.appendChild(c);const p=d.isBrowser()?window.SVG:global.SVG;c.setAttributeNS(p.xlink,"href",n),Dt.setAttrs(c,{x:0,y:0,preserveAspectRatio:"none",width:o+"px",height:l+"px"}),c.style.opacity=t.opacity,e.dom.elDefs.node.appendChild(h)}getSeriesIndex(t){const e=this.w,i=e.config.chart.type;return("bar"===i||"rangeBar"===i)&&e.config.plotOptions.bar.distributed||"heatmap"===i||"treemap"===i?this.seriesIndex=t.seriesNumber:this.seriesIndex=t.seriesNumber%e.seriesData.series.length,this.seriesIndex}getSeriesAxisRange(t){var e,i,s;const a=this.w,r=null!=(i=null==(e=a.globals.seriesYAxisReverseMap)?void 0:e[t])?i:0;return{minY:v.isNumber(a.globals.minYArr[t])?a.globals.minYArr[t]:a.globals.minY,maxY:v.isNumber(a.globals.maxYArr[t])?a.globals.maxYArr[t]:a.globals.maxY,reversed:!!(null==(s=a.config.yaxis[r])?void 0:s.reversed)}}computeColorStops(t,e){const i=this.w,{threshold:s,colorAboveThreshold:a,colorBelowThreshold:r}=e,{minY:n,maxY:o}=t,l=o-n;let h=0===l?s>o?0:100:(o-s)/l*100;t.reversed&&(h=100-h),h=Math.max(0,Math.min(h,100));const c=Array.isArray(i.config.fill.opacity)?i.config.fill.opacity[this.seriesIndex]:i.config.fill.opacity,d={offset:h,color:a,opacity:c},p={offset:h,color:r,opacity:c};return t.reversed?[p,d]:[d,p]}fillPath(t){var e,i,s,a,r,n,o;const l=this.w;this.opts=t;const h=this.w.config;let c,d,p;this.seriesIndex=this.getSeriesIndex(t);const u=h.plotOptions.line.colors.colorAboveThreshold&&h.plotOptions.line.colors.colorBelowThreshold;let g=this.getFillColors()[this.seriesIndex];void 0!==l.seriesData.seriesColors[this.seriesIndex]&&(g=l.seriesData.seriesColors[this.seriesIndex]),"function"==typeof g&&(g=g({seriesIndex:this.seriesIndex,dataPointIndex:t.dataPointIndex,value:t.value,w:l}));const f=t.fillType?t.fillType:this.getFillType(this.seriesIndex);let x=Array.isArray(h.fill.opacity)?h.fill.opacity[this.seriesIndex]:h.fill.opacity;const m="gradient"===f||u;t.color&&(g=t.color);const b=l.config.series[this.seriesIndex];(null==(i=null==(e=null==b?void 0:b.data)?void 0:e[t.dataPointIndex])?void 0:i.fillColor)&&(g=null==(a=null==(s=null==b?void 0:b.data)?void 0:s[t.dataPointIndex])?void 0:a.fillColor),g||(g="#fff"),void 0!==t.opacity&&null!==t.opacity&&(x=t.opacity);let y=g;v.isCSSVariable(g)?y=v.applyOpacityToColor(g,x):-1===g.indexOf("rgb")?-1===g.indexOf("#")?y=g:g.length<9&&(y=v.hexToRgba(g,x)):g.indexOf("rgba")>-1?x=v.getOpacityFromRGBA(g):y=v.hexToRgba(v.rgb2hex(g),x);const w=v.isCSSVariable(g)?v.getThemeColor(g):g;if("pattern"===f&&(d=this.handlePatternFill({fillConfig:t.fillConfig,patternFill:d,fillColor:w,defaultColor:y})),m){const e=h.fill.gradient.colorStops?[...h.fill.gradient.colorStops]:[];let i=null!=(o=null==(n=null==(r=t.fillConfig)?void 0:r.gradient)?void 0:n.type)?o:h.fill.gradient.type;u&&(e[this.seriesIndex]=this.computeColorStops(this.getSeriesAxisRange(this.seriesIndex),h.plotOptions.line.colors),i="vertical"),p=this.handleGradientFill({type:i,fillConfig:t.fillConfig,fillColor:w,fillOpacity:x,colorStops:e,i:this.seriesIndex,verticalUserSpace:u})}if("image"===f){const e=h.fill.image.src,i=t.patternID?t.patternID:"",s=`pattern${l.globals.cuid}${t.seriesNumber+1}${i}`;-1===this.patternIDs.indexOf(s)&&(this.clippedImgArea({opacity:x,image:Array.isArray(e)?t.seriesNumber-1&&(g=v.getOpacityFromRGBA(u));let f=void 0===l.gradient.opacityTo?i:Array.isArray(l.gradient.opacityTo)?l.gradient.opacityTo[r]:l.gradient.opacityTo;if(void 0===l.gradient.gradientToColors||0===l.gradient.gradientToColors.length)p="dark"===l.gradient.shade?d.shadeColor(-1*parseFloat(l.gradient.shadeIntensity),e.indexOf("rgb")>-1?v.rgb2hex(e):e):d.shadeColor(parseFloat(l.gradient.shadeIntensity),e.indexOf("rgb")>-1?v.rgb2hex(e):e);else if(l.gradient.gradientToColors[h.seriesNumber]){const t=l.gradient.gradientToColors[h.seriesNumber];p=t,t.indexOf("rgba")>-1&&(f=v.getOpacityFromRGBA(t))}else p=e;if(l.gradient.gradientFrom&&(u=l.gradient.gradientFrom),l.gradient.gradientTo&&(p=l.gradient.gradientTo),l.gradient.inverseColors){const t=u;u=p,p=t}return u.indexOf("rgb")>-1&&(u=v.rgb2hex(u)),p.indexOf("rgb")>-1&&(p=v.rgb2hex(p)),c.drawGradient(t,u,p,g,f,h.size,l.gradient.stops,a,r,n)}}const Pt=["none","lighten","darken"];function Ft(t,e){const i=t&&t.renderer;return i&&i.kind&&"svg"!==i.kind?i:e}function Et(t){var e,i,s,a;const r=t.config.fill&&t.config.fill.type,n=t=>"pattern"===t||"image"===t||"gradient"===t;if(Array.isArray(r)?r.some(n):n(r))return!0;const o=null==(i=null==(e=t.config.plotOptions)?void 0:e.line)?void 0:i.colors;if(o&&o.colorAboveThreshold&&o.colorBelowThreshold)return!0;if("heatmap"===t.config.chart.type&&"rect"!==((null==(a=null==(s=t.config.plotOptions)?void 0:s.heatmap)?void 0:a.shape)||"rect"))return!0;const l=t.config.states||{},h=l.hover&&l.hover.filter&&l.hover.filter.type,c=l.active&&l.active.filter&&l.active.filter.type;return!(!h||Pt.includes(h))||!(!c||Pt.includes(c))}class Tt{constructor(t,e){this.w=t,this.ctx=e,this._filters=new Mt(this.w),this._graphics=new Dt(this.w,this.ctx),this._seriesWrap=null,this._seriesWrapIndex=-1,this._batch=null}resetSeriesWrapCache(){this._seriesWrap=null,this._seriesWrapIndex=-1,this._batch=null}static markersAreInert(t){const e=t.config.chart.type;return!("line"!==e&&"area"!==e||t.globals.comboCharts||t.config.tooltip.intersect)}_shouldBatch(){var t,e,i,s,a;const r=this.w,n=r.config.markers,o=null!=(t=n.largeDatasetThreshold)?t:0;if(o<=0)return!1;if("canvas"===(null==(i=null==(e=this.ctx)?void 0:e.renderer)?void 0:i.kind))return!1;if(!Tt.markersAreInert(r))return!1;if(n.discrete&&n.discrete.length)return!1;if(n.onClick||n.onDblClick)return!1;if(null==(s=r.config.chart.events)?void 0:s.dataPointSelection)return!1;const l=r.seriesData.series;if(!Array.isArray(l)||!l.length)return!1;let h=!1;for(let t=0;t0||e&&n.showNullDataPoints)&&(l[t].length>o&&(h=!0))}return h}setGlobalMarkerSize(){const t=this.w;if(t.globals.markers.size=Array.isArray(t.config.markers.size)?t.config.markers.size:[t.config.markers.size],t.globals.markers.size.length>0){if(t.globals.markers.size.lengtht.config.markers.size);t.globals.markers.batched=this._shouldBatch()}plotChartMarkers({pointsPos:t,seriesIndex:e,j:i,pSize:s,alwaysDrawMarker:a=!1,isVirtualPoint:r=!1}){const n=this.w,o=e,l=t;let h=null;const c=new Dt(this.w),d=Ft(this.ctx,c),p=n.config.markers.discrete&&n.config.markers.discrete.length;if(Array.isArray(l.x))for(let t=0;t0:n.config.markers.size>0;if(n.globals.markers.batched&&(m||a)&&!p&&!r)this._batchPoint(e,g,l.x[t],l.y[t],{invalid:f,graphics:c,pSize:a?s:void 0,trackPoint:!a});else if(m||a||p){"canvas"===d.kind&&(void 0===n.globals.pointsArray[e]&&(n.globals.pointsArray[e]=[]),n.globals.pointsArray[e][g]=[l.x[t],l.y[t]]),f||(x+=` w${v.randomId()}`);const i=this.getMarkerConfig({cssClass:x,seriesIndex:e,dataPointIndex:g}),r=n.config.series[o];if(r.data[g]&&(r.data[g].fillColor&&(i.pointFillColor=r.data[g].fillColor),r.data[g].strokeColor&&(i.pointStrokeColor=r.data[g].strokeColor)),void 0!==s&&(i.pSize=s),(l.x[t]<-n.globals.markers.largestSize||l.x[t]>n.layout.gridWidth+n.globals.markers.largestSize||l.y[t]<-n.globals.markers.largestSize||l.y[t]>n.layout.gridHeight+n.globals.markers.largestSize)&&(i.pSize=0),!f){if((n.globals.markers.size[e]>0||a||p)&&!h){const t=!a&&!p;t&&this._seriesWrap&&this._seriesWrapIndex===e?h=this._seriesWrap:(h=d.group({class:t?"apexcharts-series-markers":""}),h.attr("clip-path",`url(#gridRectMarkerMask${n.globals.cuid})`),this.setupMarkerDelegation(h),t&&(this._seriesWrap=h,this._seriesWrapIndex=e))}u=d.drawMarker(l.x[t],l.y[t],i),u.attr("rel",g),u.attr("j",g),u.attr("index",e),u.node.setAttribute("default-marker-size",i.pSize),vt(u,l.x[t],n),this._filters.setSelectionFilter(u,e,g),h&&h.add(u)}}else void 0===n.globals.pointsArray[e]&&(n.globals.pointsArray[e]=[]),n.globals.pointsArray[e].push([l.x[t],l.y[t]])}return h}_batchPoint(t,e,i,s,{invalid:a,graphics:r,pSize:n,trackPoint:o}){const l=this.w;if(o&&(void 0===l.globals.pointsArray[t]&&(l.globals.pointsArray[t]=[]),l.globals.pointsArray[t][e]=[i,s]),a)return;this._batch&&this._batch.seriesIndex===t||(this._batch={seriesIndex:t,opts:this.getMarkerConfig({cssClass:"",seriesIndex:t}),sizes:new Map});const h=void 0===n?this._batch.opts.pSize:n;if(!(h>0))return;const c=l.globals.markers.largestSize;if(i<-c||i>l.layout.gridWidth+c||s<-c||s>l.layout.gridHeight+c)return;let d=this._batch.sizes.get(h);d||(d=[],this._batch.sizes.set(h,d)),d.push(r.getMarkerPath(i,s,this._batch.opts.shape,h))}flushBatch(t,e){const i=this._batch;if(this._batch=null,!i||i.seriesIndex!==e||!i.sizes.size)return[];const s=this.w,a=new Dt(this.w),r=i.opts,n="line"===r.shape||"plus"===r.shape||"cross"===r.shape,o=n?r.pointFillColor:r.pointStrokeColor,l=n?r.pointFillOpacity:r.pointStrokeOpacity,h=[];return i.sizes.forEach((i,n)=>{if(!i.length)return;const c=a.drawPath({d:i.join(" "),fill:r.pointFillColor,fillOpacity:r.pointFillOpacity,stroke:o,strokeOpacity:l,strokeWidth:r.pointStrokeWidth,strokeDashArray:r.pointStrokeDashArray});c.attr({class:"apexcharts-marker-batch"+(Tt.markersAreInert(s)?" no-pointer-events":""),"clip-path":`url(#gridRectMarkerMask${s.globals.cuid})`,shape:r.shape,index:e,"default-marker-size":n}),t.add(c),h.push(c)}),h}getMarkerConfig({cssClass:t,seriesIndex:e,dataPointIndex:i=null,radius:s=null,size:a=null,strokeWidth:r=null}){const n=this.w,o=this.getMarkerStyle(e);let l=null===a?n.globals.markers.size[e]:a;const h=n.config.markers;return null!==i&&h.discrete.length&&h.discrete.map(t=>{t.seriesIndex===e&&t.dataPointIndex===i&&(void 0!==t.strokeColor&&(o.pointStrokeColor=t.strokeColor),void 0!==t.fillColor&&(o.pointFillColor=t.fillColor),void 0!==t.size&&(l=t.size),void 0!==t.shape&&(o.pointShape=t.shape))}),{pSize:null===s?l:s,pRadius:null!==s?s:h.radius,pointStrokeWidth:null!==r?r:Array.isArray(h.strokeWidth)?h.strokeWidth[e]:h.strokeWidth,pointStrokeColor:o.pointStrokeColor,pointFillColor:o.pointFillColor,shape:o.pointShape||(Array.isArray(h.shape)?h.shape[e]:h.shape),class:t,pointStrokeOpacity:Array.isArray(h.strokeOpacity)?h.strokeOpacity[e]:h.strokeOpacity,pointStrokeDashArray:Array.isArray(h.strokeDashArray)?h.strokeDashArray[e]:h.strokeDashArray,pointFillOpacity:Array.isArray(h.fillOpacity)?h.fillOpacity[e]:h.fillOpacity,seriesIndex:e}}setupMarkerDelegation(t){const e=this.w,i=".apexcharts-marker";this._graphics.setupEventDelegation(t,i),t.node.addEventListener("click",s=>{if(e.config.markers.onClick){Dt._findDelegateTarget(s.target,t.node,i)&&e.config.markers.onClick(s)}}),t.node.addEventListener("dblclick",s=>{if(e.config.markers.onDblClick){Dt._findDelegateTarget(s.target,t.node,i)&&e.config.markers.onDblClick(s)}}),t.node.addEventListener("touchstart",e=>{const s=Dt._findDelegateTarget(e.target,t.node,i);s&&s.instance&&this._graphics.pathMouseDown(s.instance,e)},{passive:!0})}getMarkerStyle(t){const e=this.w,i=e.globals.markers.colors,s=e.config.markers.strokeColor||e.config.markers.strokeColors;return{pointStrokeColor:Array.isArray(s)?s[t]:s,pointFillColor:Array.isArray(i)?i[t]:i}}}class It{constructor(t,e){this.ctx=e,this.w=t,this.initialAnim=this.w.config.chart.animations.enabled,this.anim=new Ct(this.w),this.filters=new Mt(this.w),this.fill=new Lt(this.w),this.markers=new Tt(this.w,this.ctx),this.graphics=new Dt(this.w),this._elPointsWrap=null,this._elPointsWrapParent=null,this._perSeries=null}draw(t,e,i){const s=this.w,a=this.graphics,r=Ft(this.ctx,a),n=i.realIndex,o=i.pointsPos,l=i.zRatio,h=i.elParent;let c=this._elPointsWrap;if(c&&this._elPointsWrapParent===h||(c=r.group({class:`apexcharts-series-markers apexcharts-series-${s.config.chart.type}`}),c.attr("clip-path",`url(#gridRectMarkerMask${s.globals.cuid})`),this.markers.setupMarkerDelegation(c),h.add(c),this._elPointsWrap=c,this._elPointsWrapParent=h,this._perSeries=this._buildPerSeriesCache(n,r)),Array.isArray(o.x))for(let t=0;tt.maxBubbleRadius&&(h=t.maxBubbleRadius)}const d=o.x[t],p=o.y[t];if(h=h||0,null!==p&&void 0!==s.seriesData.series[n][i]||(a=!1),a){const t=this.drawPoint(d,p,h,n,i,e);c.add(t),"canvas"===r.kind&&(void 0===s.globals.pointsArray[n]&&(s.globals.pointsArray[n]=[]),s.globals.pointsArray[n][i]=[d,p])}}}_buildPerSeriesCache(t,e){var i;const s=this.w;return{realIndex:t,emit:e,isBubble:"bubble"===s.config.chart.type||s.globals.comboCharts&&s.config.series[t]&&"bubble"===s.config.series[t].type,canCacheConfig:!s.config.markers.discrete.length,markerConfig:null,fillCacheable:void 0,fillCircle:void 0,dropShadowEnabled:s.config.chart.dropShadow.enabled,doInitialAnim:this.initialAnim&&!s.globals.dataChanged&&!s.globals.resized,jitter:null==(i=s.config.plotOptions.scatter)?void 0:i.jitter,anim:null}}drawPoint(t,e,i,s,a,r){var n;const o=this.w,l=s,h=this.anim,c=this.filters,d=this.fill,p=this.markers;let u=this._perSeries;u&&u.realIndex===s||(u=this._perSeries=this._buildPerSeriesCache(s,Ft(this.ctx,this.graphics)));const g=u.emit;let f;u.canCacheConfig?(u.markerConfig||(u.markerConfig=p.getMarkerConfig({cssClass:"apexcharts-marker",seriesIndex:l,dataPointIndex:a,radius:u.isBubble?i:null})),f=u.markerConfig,u.isBubble&&(f.pSize=i,f.pRadius=i)):f=p.getMarkerConfig({cssClass:"apexcharts-marker",seriesIndex:l,dataPointIndex:a,radius:u.isBubble?i:null});const x=o.config.series[l].data[a];let m;void 0!==u.fillCircle?m=u.fillCircle:(m=d.fillPath({seriesNumber:s,dataPointIndex:a,color:f.pointFillColor,patternUnits:"objectBoundingBox",value:o.seriesData.series[s][r]}),void 0===u.fillCacheable&&(u.fillCacheable=u.canCacheConfig&&"solid"===d.getFillType(s)&&"string"==typeof f.pointFillColor&&!!f.pointFillColor),u.fillCacheable&&!(null==x?void 0:x.fillColor)&&(u.fillCircle=m));const b=g.drawMarker(t,e,f);(null==x?void 0:x.fillColor)&&(m=x.fillColor);const y=u.jitter;if((null==y?void 0:y.enabled)&&y.distributed&&o.globals.colors.length){const t=Math.round(null==(n=o.seriesData.seriesX[s])?void 0:n[a]);isNaN(t)||(m=o.globals.colors[t%o.globals.colors.length])}if(b.attr({fill:m}),u.dropShadowEnabled){const t=o.config.chart.dropShadow;c.dropShadow(b,t,s)}if(u.doInitialAnim){if(!u.anim){const t=o.config.chart.animations,e=o.globals.dataPoints||1,i=t.animateGradually,s=i&&!1!==i.enabled;u.anim={popSpeed:t.speed,baseDelay:s?Math.min(20,.5*t.speed/Math.max(1,e)):0}}const t=St({style:u.anim.baseDelay>0?"sequential":"none",index:a,baseDelay:u.anim.baseDelay});h.animatePop(b,{speed:u.anim.popSpeed,delay:t,onComplete:()=>h.animationCompleted(b)})}else o.globals.animationEnded=!0;return b.attr({rel:a,j:a,index:s,"default-marker-size":f.pSize}),c.setSelectionFilter(b,s,a),b}centerTextInBubble(t){const e=this.w;return{y:t+=parseInt(e.config.dataLabels.style.fontSize,10)/4}}}const Rt=(t,e,i,s)=>{if("function"!=typeof t)return t;const a=t({series:e.seriesData.series,seriesIndex:i,dataPointIndex:s,w:e});return Number.isFinite(a)?a:0};class zt{constructor(t,e=null){this.w=t,this.ctx=e}dataLabelsCorrection(t,e,i,s,a,r,n){const o=this.w;let l=!1;const h=new Dt(this.w).getTextRects(i,n),c=h.width,d=h.height;e<0&&(e=0),e>o.layout.gridHeight+d&&(e=o.layout.gridHeight+d/2),void 0===o.globals.dataLabelsRects[s]&&(o.globals.dataLabelsRects[s]=[]),o.globals.dataLabelsRects[s].push({x:t,y:e,width:c,height:d});const p=o.globals.dataLabelsRects[s].length-2,u=void 0!==o.globals.lastDrawnDataLabelsIndexes[s]?o.globals.lastDrawnDataLabelsIndexes[s][o.globals.lastDrawnDataLabelsIndexes[s].length-1]:0;if(void 0!==o.globals.dataLabelsRects[s][p]){const i=o.globals.dataLabelsRects[s][u];(t>i.x+i.width||e>i.y+i.height||e+dn.config.dataLabels.formatter(t,{seriesIndex:i,dataPointIndex:d,w:n});if("bubble"===n.config.chart.type){s=n.seriesData.seriesZ[i][d],r=l(s),c=e.y[o];c=new It(this.w,this.ctx).centerTextInBubble(c).y}else void 0!==s&&(r=l(s));let u=n.config.dataLabels.textAnchor;n.globals.isSlopeChart&&(u=0===d?"end":d===n.config.series[i].data.length-1?"start":"middle"),this.plotDataLabelsText({x:h,y:c,text:r,i:i,j:d,parent:p,offsetCorrection:!0,dataLabelsConfig:n.config.dataLabels,textAnchor:u})}return p}plotDataLabelsText(t){const e=this.w,i=new Dt(this.w);let{x:s,y:a,i:r,j:n,text:o,textAnchor:l,fontSize:h,parent:c,dataLabelsConfig:d,color:p,alwaysDrawDataLabel:u,offsetCorrection:g,className:f,seriesIndex:x=r,dataPointIndex:m=n}=t,b=null;if(Array.isArray(e.config.dataLabels.enabledOnSeries)&&e.config.dataLabels.enabledOnSeries.indexOf(r)<0)return b;let y={x:s,y:a,drawnextLabel:!0,textRects:null};if(g&&(y=this.dataLabelsCorrection(s,a,o,r,n,u,parseInt(d.style.fontSize,10).toString())),e.interact.zoomed||(s=y.x,a=y.y),y.textRects){const t=e.globals.barPadForNumericAxis||0;(s<-(t+20)-y.textRects.width||s>e.layout.gridWidth+y.textRects.width+t+30)&&(o="")}let w=e.globals.dataLabels.style.colors[r];(("bar"===e.config.chart.type||"rangeBar"===e.config.chart.type)&&e.config.plotOptions.bar.distributed||e.config.dataLabels.distributed)&&(w=e.globals.dataLabels.style.colors[n]),"function"==typeof w&&(w=w({series:e.seriesData.series,seriesIndex:r,dataPointIndex:n,w:e})),p&&(w=p);const v="bar"===e.config.chart.type||"rangeBar"===e.config.chart.type,A=v?0:Rt(d.offsetX,e,x,m);let S=A;const C=v?0:Rt(d.offsetY,e,x,m);if(e.globals.isSlopeChart&&(0!==n&&(S=-2*A+5),0!==n&&n!==e.config.series[r].data.length-1&&(S=0)),y.drawnextLabel){if("middle"===l&&s===e.layout.gridWidth&&(l="end"),b=i.drawText({x:s+S,y:a+C,foreColor:w,textAnchor:l||d.textAnchor,text:o,fontSize:h||d.style.fontSize,fontFamily:d.style.fontFamily,fontWeight:d.style.fontWeight||"normal"}),b.attr({class:f||"apexcharts-datalabel",cx:s,cy:a}),d.dropShadow.enabled){const t=d.dropShadow;new Mt(this.w).dropShadow(b,t)}c.add(b),vt(b,s,e),void 0===e.globals.lastDrawnDataLabelsIndexes[r]&&(e.globals.lastDrawnDataLabelsIndexes[r]=[]),e.globals.lastDrawnDataLabelsIndexes[r].push(n)}return b}addBackgroundToDataLabel(t,e){const i=this.w,s=i.config.dataLabels.background,a=s.padding,r=s.padding/2,n=e.width,o=e.height,l=new Dt(this.w).drawRect(e.x-a,e.y-r/2,n+2*a,o+r,s.borderRadius,"transparent"!==i.config.chart.background&&i.config.chart.background?i.config.chart.background:"#fff",s.opacity,s.borderWidth,s.borderColor);if(s.dropShadow.enabled){new Mt(this.w).dropShadow(l,s.dropShadow)}return l}dataLabelsBackground(){var t;const e=this.w;if("bubble"===e.config.chart.type)return;const i=e.dom.baseEl.querySelectorAll(".apexcharts-datalabels text");for(let s=0;s0?(i=e[s].position,h=e[s].value):"datetime"===o.config.xaxis.type&&void 0===d&&(h=""),void 0===h&&(h=""),h=Array.isArray(h)?h:h.toString();const g=new Dt(this.w);let f={};f=o.layout.rotateXLabels&&n?g.getTextRects(h,parseInt(r,10).toString(),null,`rotate(${o.config.xaxis.labels.rotate} 0 0)`,!1):g.getTextRects(h,parseInt(r,10).toString());const x=!o.config.xaxis.labels.showDuplicates&&this.timeScale;return!Array.isArray(h)&&("NaN"===String(h)||a.indexOf(h)>=0&&x)&&(h=""),{x:i,text:h,textRect:f}}checkLabelBasedOnTickamount(t,e,i){const s=this.w;let a=s.config.xaxis.tickAmount;if("dataPoints"===a&&(a=Math.round(s.layout.gridWidth/120)),a>i)return e;return t%Math.round(i/(a+1))===0||(e.text=""),e}checkForOverflowingLabels(t,e,i,s,a){const r=this.w;if(0===t&&r.globals.skipFirstTimelinelabel&&(e.text=""),t===i-1&&r.globals.skipLastTimelinelabel&&(e.text=""),r.config.xaxis.labels.hideOverlappingLabels&&s.length>0){const t=a[a.length-1];if(r.config.xaxis.labels.trim&&"datetime"!==r.config.xaxis.type)return e;e.x-1===e.collapsedSeriesIndices.indexOf(t))}translateYAxisIndex(t){const e=this.w,i=e.globals,s=e.config.yaxis;return e.seriesData.series.length>s.length||s.some(t=>Array.isArray(t.seriesName))?t:i.seriesYAxisReverseMap[t]}isYAxisHidden(t){const e=this.w,i=e.config.yaxis[t];if(!i.show||this.yAxisAllSeriesCollapsed(t))return!0;if(!i.showForNullSeries){const i=e.globals.seriesYAxisMap[t],s=new H(this.w);return i.every(t=>s.isSeriesNull(t))}return!1}getYAxisForeColor(t,e){var i;const s=this.w;return Array.isArray(t)&&s.globals.yAxisScale[e]&&(null==(i=this.theme)||i.pushExtraColors(t,s.globals.yAxisScale[e].result.length,!1)),t}drawYAxisTicks(t,e,i,s,a,r,n){const o=this.w,l=new Dt(this.w);let h=o.layout.translateY+o.config.yaxis[a].labels.offsetY;if(o.globals.isBarHorizontal?h=0:"heatmap"===o.config.chart.type&&(h+=r/2),s.show&&e>0){!0===o.config.yaxis[a].opposite&&(t+=s.width);for(let a=e;a>=0;a--){const e=l.drawLine(t+i.offsetX-s.width+s.offsetX,h+s.offsetY,t+i.offsetX+s.offsetX,h+s.offsetY,s.color);n.add(e),h+=r}}}}class Nt{constructor(t,e,i){this.w=t,this.ctx=e,this.elgrid=i,this.axesUtils=new Bt(t,{theme:e.theme,timeScale:e.timeScale}),this.xaxisLabels=t.labelData.labels.slice(),t.labelData.timescaleLabels.length>0&&!t.globals.isBarHorizontal&&(this.xaxisLabels=t.labelData.timescaleLabels.slice()),t.config.xaxis.overwriteCategories&&(this.xaxisLabels=t.config.xaxis.overwriteCategories),this.drawnLabels=[],this.drawnLabelsRects=[],"top"===t.config.xaxis.position?this.offY=0:this.offY=t.layout.gridHeight,this.offY=this.offY+t.config.xaxis.axisBorder.offsetY,this.isCategoryBarHorizontal="bar"===t.config.chart.type&&t.config.plotOptions.bar.horizontal,this.xaxisFontSize=t.config.xaxis.labels.style.fontSize,this.xaxisFontFamily=t.config.xaxis.labels.style.fontFamily,this.xaxisForeColors=t.config.xaxis.labels.style.colors,this.xaxisBorderWidth=t.config.xaxis.axisBorder.width,this.isCategoryBarHorizontal&&(this.xaxisBorderWidth=t.config.yaxis[0].axisBorder.width.toString()),String(this.xaxisBorderWidth).indexOf("%")>-1?this.xaxisBorderWidth=t.layout.gridWidth*parseInt(this.xaxisBorderWidth,10)/100:this.xaxisBorderWidth=parseInt(this.xaxisBorderWidth,10),this.xaxisBorderHeight=t.config.xaxis.axisBorder.height,this.yaxis=t.config.yaxis[0]}drawXaxis(){const t=this.w,e=new Dt(this.w),i=e.group({class:"apexcharts-xaxis",transform:`translate(${t.config.xaxis.offsetX}, ${t.config.xaxis.offsetY})`}),s=e.group({class:"apexcharts-xaxis-texts-g",transform:`translate(${t.layout.translateXAxisX}, ${t.layout.translateXAxisY})`});i.add(s);let a=[];for(let t=0;te),t.labelData.hasXaxisGroups){const i=t.labelData.groups;a=[];for(let t=0;ti[t].cols*e,r)}if(void 0!==t.config.xaxis.title.text){const s=e.group({class:"apexcharts-xaxis-title"}),a=e.drawText({x:t.layout.gridWidth/2+t.config.xaxis.title.offsetX,y:this.offY+parseFloat(this.xaxisFontSize)+("bottom"===t.config.xaxis.position?t.layout.xAxisLabelsHeight:-t.layout.xAxisLabelsHeight-10)+t.config.xaxis.title.offsetY,text:t.config.xaxis.title.text,textAnchor:"middle",fontSize:t.config.xaxis.title.style.fontSize,fontFamily:t.config.xaxis.title.style.fontFamily,fontWeight:t.config.xaxis.title.style.fontWeight,foreColor:t.config.xaxis.title.style.color,cssClass:"apexcharts-xaxis-title-text "+t.config.xaxis.title.style.cssClass});s.add(a),i.add(s)}if(t.config.xaxis.axisBorder.show){const s=t.globals.barPadForNumericAxis,a=e.drawLine(t.globals.padHorizontal+t.config.xaxis.axisBorder.offsetX-s,this.offY,this.xaxisBorderWidth+s,this.offY,t.config.xaxis.axisBorder.color,0,this.xaxisBorderHeight);this.elgrid&&this.elgrid.elGridBorders&&t.config.grid.show?this.elgrid.elGridBorders.add(a):i.add(a)}return i}drawXAxisLabelAndGroup(t,e,i,s,a,r,n={}){var o,l;const h=[],c=[],d=this.w,p=n.xaxisFontSize||this.xaxisFontSize,u=n.xaxisFontFamily||this.xaxisFontFamily,g=n.xaxisForeColors||this.xaxisForeColors,f=n.fontWeight||d.config.xaxis.labels.style.fontWeight,x=n.cssClass||d.config.xaxis.labels.style.cssClass;let m,y=d.globals.padHorizontal;const w=s.length;let v="category"===d.config.xaxis.type?d.globals.dataPoints:w;if(0===v&&w>v&&(v=w),a){const t=Math.max(Number(d.config.xaxis.tickAmount)||1,v>1?v-1:v);m=d.layout.gridWidth/Math.min(t,w-1),y=y+r(0,m)/2+d.config.xaxis.labels.offsetX}else m=d.layout.gridWidth/v,y=y+r(0,m)+d.config.xaxis.labels.offsetX;for(let a=0;a<=w-1;a++){let n=y-r(a,m)/2+d.config.xaxis.labels.offsetX;0===a&&1===w&&m/2===y&&1===v&&(n=d.layout.gridWidth/2);let A=this.axesUtils.getLabel(s,d.labelData.timescaleLabels,n,a,h,p,t),S=28;d.layout.rotateXLabels&&t&&(S=22),d.config.xaxis.title.text&&"top"===d.config.xaxis.position&&(S+=parseFloat(d.config.xaxis.title.style.fontSize)+2),t||(S=S+parseFloat(p)+(d.layout.xAxisLabelsHeight-d.layout.xAxisGroupLabelsHeight)+(d.layout.rotateXLabels?10:0));A=void 0!==d.config.xaxis.tickAmount&&"dataPoints"!==d.config.xaxis.tickAmount&&"datetime"!==d.config.xaxis.type?this.axesUtils.checkLabelBasedOnTickamount(a,A,w):this.axesUtils.checkForOverflowingLabels(a,A,w,h,c);const C=()=>t&&d.config.xaxis.convertedCatToNumeric?g[d.globals.minX+a-1]:g[a],k=(null!=(l=null==(o=A.textRect)?void 0:o.width)?l:0)/2,_=A.x+k<0;if(d.config.xaxis.labels.show&&!_){const s=e.drawText({x:A.x,y:this.offY+d.config.xaxis.labels.offsetY+S-("top"===d.config.xaxis.position?d.layout.xAxisHeight+d.config.xaxis.axisTicks.height-2:0),text:A.text,textAnchor:"middle",fontWeight:f,fontSize:p,fontFamily:u,foreColor:Array.isArray(g)?C():g,isPlainText:!1,cssClass:(t?"apexcharts-xaxis-label ":"apexcharts-xaxis-group-label ")+x});if(i.add(s),s.on("click",t=>{if("function"==typeof d.config.chart.events.xAxisLabelClick){const e=Object.assign({},d,{labelIndex:a});d.config.chart.events.xAxisLabelClick(t,this.ctx,e)}}),t){const t=b.createElementNS($,"title");t.textContent=Array.isArray(A.text)?A.text.join(" "):A.text,s.node.appendChild(t),""!==A.text&&(h.push(A.text),c.push(A))}}aArray.isArray(d)?d[s]:d;let u=0;Array.isArray(a)&&(u=a.length/2*parseInt(c.style.fontSize,10));let g=c.offsetX-15,f="end";this.yaxis.opposite&&(f="start"),"left"===e.config.yaxis[0].labels.align?(g=c.offsetX,f="start"):"center"===e.config.yaxis[0].labels.align?(g=c.offsetX,f="middle"):"right"===e.config.yaxis[0].labels.align&&(f="end");const x=i.drawText({x:g,y:l+o+c.offsetY-u,text:a,textAnchor:f,foreColor:p(),fontSize:c.style.fontSize,fontFamily:c.style.fontFamily,fontWeight:c.style.fontWeight,isPlainText:!1,cssClass:"apexcharts-yaxis-label "+c.style.cssClass,maxWidth:c.maxWidth});r.add(x),x.on("click",t=>{if("function"==typeof e.config.chart.events.xAxisLabelClick){const i=Object.assign({},e,{labelIndex:s});e.config.chart.events.xAxisLabelClick(t,this.ctx,i)}});const m=b.createElementNS($,"title");if(m.textContent=Array.isArray(a)?a.join(" "):a,x.node.appendChild(m),0!==e.config.yaxis[t].labels.rotate){const s=i.rotateAroundCenter(x.node);x.node.setAttribute("transform",`rotate(${e.config.yaxis[t].labels.rotate} 0 ${s.y})`)}l+=o}if(void 0!==e.config.yaxis[0].title.text){const t=i.group({class:"apexcharts-yaxis-title apexcharts-xaxis-title-inversed",transform:"translate("+s+", 0)"}),r=i.drawText({x:e.config.yaxis[0].title.offsetX,y:e.layout.gridHeight/2+e.config.yaxis[0].title.offsetY,text:e.config.yaxis[0].title.text,textAnchor:"middle",foreColor:e.config.yaxis[0].title.style.color,fontSize:e.config.yaxis[0].title.style.fontSize,fontWeight:e.config.yaxis[0].title.style.fontWeight,fontFamily:e.config.yaxis[0].title.style.fontFamily,cssClass:"apexcharts-yaxis-title-text "+e.config.yaxis[0].title.style.cssClass});t.add(r),a.add(t)}let d=0;this.isCategoryBarHorizontal&&e.config.yaxis[0].opposite&&(d=e.layout.gridWidth);const p=e.config.xaxis.axisBorder;if(p.show){const t=i.drawLine(e.globals.padHorizontal+p.offsetX+d,1+p.offsetY,e.globals.padHorizontal+p.offsetX+d,e.layout.gridHeight+p.offsetY,p.color,0);this.elgrid&&this.elgrid.elGridBorders&&e.config.grid.show?this.elgrid.elGridBorders.add(t):a.add(t)}return e.config.yaxis[0].axisTicks.show&&this.axesUtils.drawYAxisTicks(d,n.length,e.config.yaxis[0].axisBorder,e.config.yaxis[0].axisTicks,0,o,a),a}drawXaxisTicks(t,e,i){const s=this.w,a=t;if(t<0||t-2>s.layout.gridWidth)return;const r=this.offY+s.config.xaxis.axisTicks.offsetY;if(e=e+r+s.config.xaxis.axisTicks.height,"top"===s.config.xaxis.position&&(e=r-s.config.xaxis.axisTicks.height),s.config.xaxis.axisTicks.show){const n=new Dt(this.w).drawLine(t+s.config.xaxis.axisTicks.offsetX,r+s.config.xaxis.offsetY,a+s.config.xaxis.axisTicks.offsetX,e+s.config.xaxis.offsetY,s.config.xaxis.axisTicks.color);i.add(n),n.node.classList.add("apexcharts-xaxis-tick")}}getXAxisTicksPositions(){const t=this.w,e=[],i=this.xaxisLabels.length;let s=t.globals.padHorizontal;if(t.labelData.timescaleLabels.length>0)for(let t=0;t{a.placeTextWithEllipsis(t,t.textContent,s.layout.xAxisLabelsHeight-("bottom"===s.config.legend.position?20:10))})}else{const t=s.layout.gridWidth/(s.labelData.labels.length+1);for(let e=0;e{a.placeTextWithEllipsis(e,e.textContent,t)})}}if(o.length>0){const r=o[o.length-1].getBBox(),n=o[0].getBBox();r.x<-20&&(null==(t=o[o.length-1].parentNode)||t.removeChild(o[o.length-1])),n.x+n.width>s.layout.gridWidth&&!s.globals.isBarHorizontal&&(null==(e=o[0].parentNode)||e.removeChild(o[0]));for(let t=0;t0&&(this.xaxisLabels=t.labelData.timescaleLabels.slice())}drawGridArea(t=null){const e=this.w,i=new Dt(this.w);t||(t=i.group({class:"apexcharts-grid"}));const s=i.drawLine(e.globals.padHorizontal,1,e.globals.padHorizontal,e.layout.gridHeight,"transparent"),a=i.drawLine(e.globals.padHorizontal,e.layout.gridHeight,e.layout.gridWidth,e.layout.gridHeight,"transparent");return t.add(a),t.add(s),t}drawGrid(){if(this.w.globals.axisCharts){const t=this.renderGrid();return this.drawGridArea(t.el),t}return null}createGridMask(){const t=this.w,e=t.globals,i=new Dt(this.w),s=Array.isArray(t.config.stroke.width)?Math.max(...t.config.stroke.width):t.config.stroke.width,a=t=>{const e=b.createElementNS($,"clipPath");return e.setAttribute("id",t),e};t.dom.elGridRectMask=a(`gridRectMask${e.cuid}`),t.dom.elGridRectBarMask=a(`gridRectBarMask${e.cuid}`),t.dom.elGridRectMarkerMask=a(`gridRectMarkerMask${e.cuid}`),t.dom.elForecastMask=a(`forecastMask${e.cuid}`),t.dom.elNonForecastMask=a(`nonForecastMask${e.cuid}`);let r=0,n=0;(["bar","rangeBar","candlestick","boxPlot","violin"].includes(t.config.chart.type)||t.globals.comboBarCount>0)&&t.axisFlags.isXNumeric&&!t.globals.isBarHorizontal&&(r=Math.max(t.layout.gridPad.left,e.barPadForNumericAxis),n=Math.max(t.layout.gridPad.right,e.barPadForNumericAxis)),t.dom.elGridRect=i.drawRect(-s/2-2,-s/2-2,t.layout.gridWidth+s+4,t.layout.gridHeight+s+4,0,"#fff"),t.dom.elGridRectBar=i.drawRect(-s/2-r-2,-s/2-2,t.layout.gridWidth+s+n+r+4,t.layout.gridHeight+s+4,0,"#fff");const o=t.globals.markers.largestSize;t.dom.elGridRectMarker=i.drawRect(Math.min(-s/2-r-2,-o),-o,t.layout.gridWidth+Math.max(s+n+r+4,2*o),t.layout.gridHeight+2*o,0,"#fff"),t.dom.elGridRectMask.appendChild(t.dom.elGridRect.node),t.dom.elGridRectBarMask.appendChild(t.dom.elGridRectBar.node),t.dom.elGridRectMarkerMask.appendChild(t.dom.elGridRectMarker.node);const l=t.dom.elDefs.node;l.appendChild(t.dom.elGridRectMask),l.appendChild(t.dom.elGridRectBarMask),l.appendChild(t.dom.elGridRectMarkerMask),l.appendChild(t.dom.elForecastMask),l.appendChild(t.dom.elNonForecastMask)}_drawGridLines({i:t,x1:e,y1:i,x2:s,y2:a,xCount:r,parent:n}){const o=this.w;if(!(0===t&&o.globals.skipFirstTimelinelabel||t===r-1&&o.globals.skipLastTimelinelabel&&!o.config.xaxis.labels.formatter||"radar"===o.config.chart.type)){o.config.grid.xaxis.lines.show&&this._drawGridLine({i:t,x1:e,y1:i,x2:s,y2:a,xCount:r,parent:n});let l=0;if(o.labelData.hasXaxisGroups&&"between"===o.config.xaxis.tickPlacement){const e=o.labelData.groups;if(e){let i=0;for(let s=0;i{for(let o=0;os.layout.gridWidth||this._drawGridLines({i:o,x1:i,y1:a,x2:r,y2:n,xCount:t,parent:this.elgridLinesV})},r=({xC:e,x1:i,y1:a,x2:r,y2:n})=>{for(let o=0;o0&&"datetime"!==s.config.xaxis.type&&(o=a.yAxisScale[n].result.length-1)),this._drawXYLines({xCount:o,tickAmount:l})):(o=l,l=a.xTickAmount,this._drawInvertedXYLines({xCount:o,tickAmount:l})),this.drawGridBands(o,l),{el:this.elg,elGridBorders:this.elGridBorders,xAxisTickWidth:s.layout.gridWidth/o}}drawGridBands(t,e){var i,s,a,r,n;const o=this.w,l=(t,i,s,a,r,n)=>{for(let l=0,h=0;l=o.config.grid[t].colors.length&&(h=0),this._drawGridBandRect({c:h,x1:s,y1:a,x2:r,y2:n,type:t}),a+=o.layout.gridHeight/e};if((null==(i=o.config.grid.row.colors)?void 0:i.length)>0&&l("row",e,0,0,o.layout.gridWidth,o.layout.gridHeight/e),(null==(s=o.config.grid.column.colors)?void 0:s.length)>0){let e=o.globals.isBarHorizontal||"on"!==o.config.xaxis.tickPlacement||"category"!==o.config.xaxis.type&&!o.config.xaxis.convertedCatToNumeric?t:t-1;o.axisFlags.isXNumeric&&(e=(null!=(r=null==(a=o.globals.xAxisScale)?void 0:a.result.length)?r:1)-1);let i=o.globals.padHorizontal;const s=0;let l=o.globals.padHorizontal+o.layout.gridWidth/e;const h=o.layout.gridHeight;for(let a=0,r=0;a=o.config.grid.column.colors.length&&(r=0),"datetime"===o.config.xaxis.type&&(i=this.xaxisLabels[a].position,l=((null==(n=this.xaxisLabels[a+1])?void 0:n.position)||o.layout.gridWidth)-this.xaxisLabels[a].position),this._drawGridBandRect({c:r,x1:i,y1:s,x2:l,y2:h,type:"column"}),i+=o.layout.gridWidth/e}}}class Yt{constructor(t){this.w=t,this.coreUtils=new H(this.w)}niceScale(t,e,i=0){const s=1e-11,a=this.w,r=a.globals;let n,o,l,h;r.isBarHorizontal?(n=a.config.xaxis,o=Math.max((r.svgWidth-100)/25,2)):(n=a.config.yaxis[i],o=Math.max((r.svgHeight-100)/15,2)),v.isNumber(o)||(o=10),l=void 0!==n.min&&null!==n.min,h=void 0!==n.max&&null!==n.max;let c=void 0!==n.stepSize&&null!==n.stepSize,d=void 0!==n.tickAmount&&null!==n.tickAmount,p=d?n.tickAmount:O[Math.min(Math.round(o/2),O.length-1)];if(r.isMultipleYAxis&&!d&&r.multiAxisTickAmount>0&&(p=r.multiAxisTickAmount,d=!0),p="dataPoints"===p?r.dataPoints-1:Math.abs(Math.round(p)),(t===Number.MIN_VALUE&&0===e||!v.isNumber(t)&&!v.isNumber(e)||t===Number.MIN_VALUE&&e===-Number.MAX_VALUE)&&(t=v.isNumber(n.min)?n.min:0,e=v.isNumber(n.max)?n.max:t+p,r.allSeriesCollapsed=!1),t>e){const i=e;e=t,t=i}else t===e&&(t=0===t?0:t-1,e=0===e?2:e+1);const u=[];p<1&&(p=1);let g=p,f=Math.abs(e-t);!l&&t>0&&t/f<.15&&(t=0,l=!0),!h&&e<0&&-e/f<.15&&(e=0,h=!0),f=Math.abs(e-t);let x=f/g,m=x;const b=Math.floor(Math.log10(m)),y=Math.pow(10,b);let w=Math.ceil(m/y);if(w=N[0===r.yValueDecimal?0:1][w],m=w*y,x=m,r.isBarHorizontal&&n.stepSize&&"datetime"!==n.type?(x=n.stepSize,c=!0):c&&(x=n.stepSize),c&&n.forceNiceScale){const t=Math.floor(Math.log10(x));x*=Math.pow(10,b-t)}if(l&&h){let t=f/g;if(d)if(c)if(0!=v.mod(f,x)){const e=v.getGCD(x,t);x=t/e<10?e:t}else 0==v.mod(x,t)?x=t:(t=x,d=!1);else x=t;else if(c)0==v.mod(f,x)?t=x:x=t;else if(0==v.mod(f,x))t=x;else{g=Math.ceil(f/x),t=f/g;const e=v.getGCD(f,x);f/eo&&(t=e-x*p,t+=x*Math.floor((i-t)/x))}else if(l)if(d)e=t+x*g;else{const i=e;e=x*Math.ceil(e/x),Math.abs(e-t)/v.getGCD(f,x)>o&&(e=t+x*p,e+=x*Math.ceil((i-e)/x))}}else if(r.isMultipleYAxis&&d){const i=x*Math.floor(t/x);let s=i+x*g;s0&&t16&&v.getPrimeFactors(g).length<2&&g++),!d&&n.forceNiceScale&&0===r.yValueDecimal&&g>f&&(g=f,x=Math.round(f/g)),g>o&&(!d&&!c||n.forceNiceScale)){const t=v.getPrimeFactors(g),e=t.length-1;let i=g;t:for(var A=0;A_);return{result:u,niceMin:u[0],niceMax:u[u.length-1]}}linearScale(t,e,i=10,s=0,a=void 0){const r=Math.abs(e-t);let n=[];if(t===e)return n=[t],{result:n,niceMin:n[0],niceMax:n[n.length-1]};"dataPoints"===(i=this._adjustTicksForSmallRange(i,s,r))&&(i=this.w.globals.dataPoints-1);const o=i;a||(a=r/o);if(0!==a&&isFinite(a)){const t=Math.floor(Math.log10(Math.abs(a))),e=Math.max(2,2-t),i=Math.pow(10,e);a=Math.round((a+Number.EPSILON)*i)/i}let l=i===Number.MAX_VALUE?5:o;i===Number.MAX_VALUE&&(a=1);let h=t;for(;l>=0;)n.push(h),h=v.preciseAddition(h,a),l-=1;return{result:n,niceMin:n[0],niceMax:n[n.length-1]}}_resolveLogTickAmount(t){let e=t.tickAmount;return"dataPoints"===e&&(e=this.w.globals.dataPoints-1),v.isNumber(e)&&e>=1?Number(e):null}_thinToTickAmount(t,e){if(null===e||!v.isNumber(e)||e<1)return t;const i=e+1;if(t.length<=i)return t;const s=t.length-1;let a=null;for(let t=1;t<=s;t++){if(s%t!==0)continue;const e=s/t+1;e>i||(null===a||e>a.count)&&(a={stride:t,count:e})}if(!a)return[t[0],t[t.length-1]];const r=[];for(let e=0;e=1,l=r.logarithmic&&(o||n>5);if(r.logarithmic&&!l&&(s.invalidLogScale=!0),l){s.allSeriesCollapsed=!1;const a=this._resolveLogTickAmount(r);s.yAxisScale[t]=r.forceNiceScale?this.logarithmicScaleNice(e,i,r.logBase,a):this.logarithmicScale(e,i,r.logBase,a)}else i!==-Number.MAX_VALUE&&v.isNumber(i)&&e!==Number.MAX_VALUE&&v.isNumber(e)?(s.allSeriesCollapsed=!1,s.yAxisScale[t]=this.niceScale(e,i,t)):s.yAxisScale[t]=this.niceScale(Number.MIN_VALUE,0,t)}setXScale(t,e){const i=this.w,s=i.globals;if(e!==-Number.MAX_VALUE&&v.isNumber(e)){const a=s.xTickAmount;s.xAxisScale=this.linearScale(t,e,a,0,void 0===i.config.xaxis.max?i.config.xaxis.stepSize:void 0)}else s.xAxisScale=this.linearScale(0,10,10);return s.xAxisScale}scaleMultipleYAxes(){const t=this.w.config,e=this.w.globals;this.coreUtils.setSeriesYAxisMappings();const i=e.seriesYAxisMap,s=e.minYArr,a=e.maxYArr,r=[],n=!e.isBarHorizontal;if(e.allSeriesCollapsed=!0,e.barGroups=[],i.forEach((i,o)=>{const l=[];if(i.forEach(e=>{var i;const s=null==(i=t.series[e])?void 0:i.group;l.indexOf(s)<0&&l.push(s)}),i.length>0){let h,c,d=Number.MAX_VALUE,p=-Number.MAX_VALUE,u=d,g=p;if(t.chart.stacked){const s=new Array(e.dataPoints).fill(0),a=[],r=[],n=[];l.forEach(()=>{a.push(s.map(()=>Number.MIN_VALUE)),r.push(s.map(()=>Number.MIN_VALUE)),n.push(s.map(()=>Number.MIN_VALUE))});for(let s=0;s{if(t.series[d].group===e)for(let t=0;t=0?r[i][t]+=e:n[i][t]+=e,a[i][t]+=e,u=Math.min(u,e),g=Math.max(g,e)}})),"bar"!==h&&"column"!==h||e.barGroups.push(c)}h||(h=t.chart.type),"bar"===h||"column"===h?l.forEach((t,e)=>{d=Math.min(d,Math.min.apply(null,n[e])),p=Math.max(p,Math.max.apply(null,r[e]))}):(l.forEach((t,e)=>{u=Math.min(u,Math.min.apply(null,a[e])),g=Math.max(g,Math.max.apply(null,a[e]))}),d=u,p=g),d===Number.MIN_VALUE&&p===Number.MIN_VALUE&&(p=-Number.MAX_VALUE)}else for(let t=0;ti.indexOf(t)===e);const f=t.yaxis[o];n&&!0===f.alignZero&&!f.logarithmic&&void 0===f.min&&void 0===f.max&&e.ignoreYAxisIndexes.indexOf(o)<0&&v.isNumber(d)&&v.isNumber(p)?r.push({ai:o,minY:d,maxY:p}):(this.setYScaleForIndex(o,d,p),i.forEach(t=>{s[t]=e.yAxisScale[o].niceMin,a[t]=e.yAxisScale[o].niceMax}))}else this.setYScaleForIndex(o,0,-Number.MAX_VALUE)}),r.length>=2){r.forEach(t=>{this.setYScaleForIndex(t.ai,t.minY,t.maxY),i[t.ai].forEach(i=>{s[i]=e.yAxisScale[t.ai].niceMin,a[i]=e.yAxisScale[t.ai].niceMax})});let t=0;r.forEach(i=>{const s=e.yAxisScale[i.ai],a=s.niceMax-s.niceMin;if(a>0){const e=-s.niceMin/a;e>t&&(t=e)}}),t>1&&(t=1),t<0&&(t=0);const n=t=>{if(t<=0)return 1;const e=Math.floor(Math.log10(t)),i=Math.pow(10,e),s=t/i;let a;return a=s<=1+1e-9?1:s<=2+1e-9?2:s<=2.5+1e-9?2.5:s<=5+1e-9?5:10,a*i};r.forEach(r=>{const o=e.yAxisScale[r.ai];if(!o.result||o.result.length<2)return;const l=o.niceMax-o.niceMin;if(l<=0)return;const h=-o.niceMin/l;if(Math.abs(h-t)<=1e-9)return;const c=ht&&t>1e-9;if(!c&&!d)return;const p=c?-t*o.niceMax/(1-t):o.niceMin,u=d?-o.niceMin*(1-t)/t:o.niceMax,g=u-p;if(g<=0)return;const f=Math.max(o.result.length,5),x=n(g/Math.max(f-1,1));if(x<=0)return;let m,b;if(c){m=Math.floor(p/x+1e-9)*x;const e=t>1e-9?m*(t-1)/t:o.niceMax,i=Math.max(e,o.niceMax);b=Math.ceil(i/x-1e-9)*x}else{b=Math.ceil(u/x-1e-9)*x;const e=t<1-1e-9?-t*b/(1-t):o.niceMin,i=Math.min(e,o.niceMin);m=Math.floor(i/x+1e-9)*x}o.result=[];for(let t=m;t<=b+1e-9*x;t=v.preciseAddition(t,x))o.result.push(v.stripNumber(t,7));o.niceMin=m,o.niceMax=b,i[r.ai].forEach(t=>{s[t]=o.niceMin,a[t]=o.niceMax})})}else if(1===r.length){const t=r[0];this.setYScaleForIndex(t.ai,t.minY,t.maxY),i[t.ai].forEach(i=>{s[i]=e.yAxisScale[t.ai].niceMin,a[i]=e.yAxisScale[t.ai].niceMax})}}}class Wt{constructor(t){this.w=t,this.scales=new Yt(this.w)}init(){this.setYRange(),this.setXRange(),this.setZRange()}_xPixelTolerance(t){const e=this.w.layout.gridWidth;if(!e||!t||!t.length)return 0;const i=this.w.config.xaxis,s="number"==typeof i.min?i.min:t[0],a="number"==typeof i.max?i.max:t[t.length-1];return a>s?(a-s)/e:0}_autoScaleYEnabled(){var t;const e=this.w.config,i=null==(t=this.w.globals.brushSource)?void 0:t.w.config.chart.brush;return!!(e.chart.zoom.enabled&&e.chart.zoom.autoScaleYaxis||(null==i?void 0:i.enabled)&&(null==i?void 0:i.autoScaleYaxis))}_autoScaleXBounds(t){const e=this.w.config.xaxis;if(!e.min&&!e.max)return null;const i=this._xPixelTolerance(this.w.seriesData.seriesX[t]);return{lo:e.min?e.min-i:-1/0,hi:e.max?e.max+i:1/0}}getMinYMaxY(t,e=Number.MAX_VALUE,i=-Number.MAX_VALUE,s=null){var a,r,n,o,l,h,c,d;const p=this.w.config,u=this.w.globals;let g=-Number.MAX_VALUE,f=Number.MIN_VALUE;null===s&&(s=t+1);const x=this.w.seriesData.series;let m=x,b=x;"candlestick"===p.chart.type?(m=this.w.candleData.seriesCandleL,b=this.w.candleData.seriesCandleH):"boxPlot"===p.chart.type?(m=this.w.candleData.seriesCandleO,b=this.w.candleData.seriesCandleC):"violin"===p.chart.type?(m=this.w.violinData.seriesViolinMin,b=this.w.violinData.seriesViolinMax):this.w.axisFlags.isRangeData&&(m=this.w.rangeData.seriesRangeStart,b=this.w.rangeData.seriesRangeEnd);let y=!1,w=!1;this.w.seriesData.seriesX.length>=s&&this._autoScaleYEnabled()&&!this._ignoreAutoScaleWindow&&(y=!0);for(let A=t;Avoid 0!==t).length),this.w.labelData.labels.length&&"datetime"!==p.xaxis.type&&0!==this.w.seriesData.series.reduce((t,e)=>t+e.length,0)&&(u.dataPoints=Math.max(u.dataPoints,this.w.labelData.labels.length));let s=0,S=x[A].length-1;if(y){const t=this.w.seriesData.seriesX[A],e=this._autoScaleXBounds(A);if(e&&p.xaxis.min)for(;ss&&t[S]>e.hi;S--);if(e&&t&&t.length){if(!(t[s]>=e.lo&&t[s]<=e.hi)){t[0]e.hi&&s>0?(S=s,s=S-1):(s=0,S=-1,w=!0)}}}if(m===x&&b===x&&"boxPlot"!==p.chart.type&&"candlestick"!==t&&"boxPlot"!==t&&"violin"!==t&&"rangeArea"!==t&&"rangeBar"!==t&&!(this.w.seriesData.seriesGoals[A]&&this.w.seriesData.seriesGoals[A].length)){const r=x[A],n=Math.min(S,r.length-1),o=null==(a=this.w.seriesData._parsedExtrema)?void 0:a[A];if(o&&o.ref===r&&o.len===r.length&&0===s&&n===r.length-1)o.maxY>g&&(g=o.maxY),o.lowestYu.yValueDecimal&&(u.yValueDecimal=o.yDec),o.hasNulls&&(u.hasNullValues=!0);else{let t=u.yValueDecimal,i=!1;for(let a=s;a<=n;a++){const s=r[a];if(null!==s&&"number"==typeof s&&s==s&&s!==1/0&&s!==-1/0){if(s>g&&(g=s),ss&&s<0&&(f=s),!Number.isInteger(s)){const e=s<0?-s:s;if(e>=1e-6&&e<1e21){const e=""+s,i=e.indexOf("."),a=-1===i?0:e.length-i-1;a>t&&(t=a)}else{const e=v.noExponents(s);v.isFloat(e)&&(t=Math.max(t,e.toString().split(".")[1].length))}}}else i=!0}u.yValueDecimal=t,i&&(u.hasNullValues=!0)}i=g,"bar"!==t&&"column"!==t||(f<0&&g<0&&(g=0,i=Math.max(i,0)),f===Number.MIN_VALUE&&(f=0,e=Math.min(e,0)));continue}for(let a=s;a<=S&&a{g=Math.max(g,t.value),e=Math.min(e,t.value)}),"boxPlot"===this.w.config.chart.type||"boxPlot"===t){const t=null==(h=null==(l=this.w.candleData.seriesBoxPoints)?void 0:l[A])?void 0:h[a];if(t)for(let i=0;i(null==(c=m[A])?void 0:c[a])&&(null==(d=m[A])?void 0:d[a])<0&&(f=m[A][a])}else u.hasNullValues=!0}"bar"!==t&&"column"!==t||(f<0&&g<0&&(g=0,i=Math.max(i,0)),f===Number.MIN_VALUE&&(f=0,e=Math.min(e,0)))}if("rangeBar"===p.chart.type&&this.w.rangeData.seriesRangeStart.length&&u.isBarHorizontal&&(f=e),"bar"===p.chart.type&&(f<0&&g<0&&(g=0),f===Number.MIN_VALUE&&(f=0)),w&&g===-Number.MAX_VALUE){this._ignoreAutoScaleWindow=!0;try{return this.getMinYMaxY(t,Number.MAX_VALUE,-Number.MAX_VALUE,s)}finally{this._ignoreAutoScaleWindow=!1}}return{minY:f,maxY:g,lowestY:e,highestY:i}}setYRange(){const t=this.w.globals,e=this.w.config;t.maxY=-Number.MAX_VALUE,t.minY=Number.MIN_VALUE;let i,s=Number.MAX_VALUE;if(t.isMultipleYAxis){s=Number.MAX_VALUE;for(let e=0;e{void 0!==e.max&&("number"==typeof e.max?t.maxYArr[i]=e.max:"function"==typeof e.max&&(t.maxYArr[i]=e.max(t.isMultipleYAxis?t.maxYArr[i]:t.maxY)),t.maxY=t.maxYArr[i]),void 0!==e.min&&("number"==typeof e.min?t.minYArr[i]=e.min:"function"==typeof e.min&&(t.minYArr[i]=e.min(t.isMultipleYAxis?t.minYArr[i]===Number.MIN_VALUE?0:t.minYArr[i]:t.minY)),t.minY=t.minYArr[i])}),t.isBarHorizontal){["min","max"].forEach(i=>{void 0!==e.xaxis[i]&&"number"==typeof e.xaxis[i]&&("min"===i?t.minY=e.xaxis[i]:t.maxY=e.xaxis[i])})}return t.isMultipleYAxis?(this.scales.scaleMultipleYAxes(),t.minY=s):(this.scales.setYScaleForIndex(0,t.minY,t.maxY),t.minY=t.yAxisScale[0].niceMin,t.maxY=t.yAxisScale[0].niceMax,t.minYArr[0]=t.minY,t.maxYArr[0]=t.maxY),t.barGroups=[],t.lineGroups=[],t.areaGroups=[],e.series.forEach(i=>{const s=i;switch(s.type||e.chart.type){case"bar":case"column":t.barGroups.push(s.group);break;case"line":t.lineGroups.push(s.group);break;case"area":t.areaGroups.push(s.group)}}),t.barGroups=t.barGroups.filter((t,e,i)=>i.indexOf(t)===e),t.lineGroups=t.lineGroups.filter((t,e,i)=>i.indexOf(t)===e),t.areaGroups=t.areaGroups.filter((t,e,i)=>i.indexOf(t)===e),{minY:t.minY,maxY:t.maxY,minYArr:t.minYArr,maxYArr:t.maxYArr,yAxisScale:t.yAxisScale}}setXRange(){const t=this.w.globals,e=this.w.config,i="numeric"===e.xaxis.type||"datetime"===e.xaxis.type||"category"===e.xaxis.type&&!this.w.axisFlags.noLabelsProvided||this.w.axisFlags.noLabelsProvided||this.w.axisFlags.isXNumeric,s=()=>{var e;let i=t.minX,s=t.maxX;for(let t=0;ts&&(s=r.maxX),r.minXs&&(s=e),et.dataPoints&&0!==t.dataPoints&&(s=t.dataPoints-1);else if("dataPoints"===e.xaxis.tickAmount){if(this.w.seriesData.series.length>1&&(s=this.w.seriesData.series[t.maxValsInArrayIndex].length-1),this.w.axisFlags.isXNumeric){const e=Math.round(t.maxX-t.minX);e<30&&(s=e)}}else s=e.xaxis.tickAmount;if(t.xTickAmount=s,void 0!==e.xaxis.max&&"number"==typeof e.xaxis.max&&(t.maxX=e.xaxis.max),void 0!==e.xaxis.min&&"number"==typeof e.xaxis.min&&(t.minX=e.xaxis.min),void 0!==e.xaxis.range&&(t.minX=t.maxX-e.xaxis.range),t.minX!==Number.MAX_VALUE&&t.maxX!==-Number.MAX_VALUE)if(e.xaxis.convertedCatToNumeric&&!this.w.axisFlags.dataFormatXNumeric){const e=[];for(let i=t.minX-1;i0&&(t.xAxisScale=this.scales.linearScale(1,this.w.labelData.labels.length,s-1,0,e.xaxis.stepSize),this.w.seriesData.seriesX=this.w.labelData.labels.slice());i&&(this.w.labelData.labels=t.xAxisScale.result.slice())}return t.isBarHorizontal&&this.w.labelData.labels.length&&(t.xTickAmount=this.w.labelData.labels.length),this._handleSingleDataPoint(),this._getMinXDiff(),{minX:t.minX,maxX:t.maxX}}setZRange(){var t;const e=this.w.globals;if(!this.w.axisFlags.isDataXYZ)return;for(let t=0;te.maxZ&&(e.maxZ=i.maxZ)}_handleSingleDataPoint(){const t=this.w.globals,e=this.w.config;if(t.minX===t.maxX){const i=new A(this.w);if("datetime"===e.xaxis.type){const s=i.getDate(t.minX);e.xaxis.labels.datetimeUTC?s.setUTCDate(s.getUTCDate()-2):s.setDate(s.getDate()-2),t.minX=new Date(s).getTime();const a=i.getDate(t.maxX);e.xaxis.labels.datetimeUTC?a.setUTCDate(a.getUTCDate()+2):a.setDate(a.getDate()+2),t.maxX=new Date(a).getTime()}else("numeric"===e.xaxis.type||"category"===e.xaxis.type&&!this.w.axisFlags.noLabelsProvided)&&(t.minX=t.minX-2,t.initialMinX=t.minX,t.maxX=t.maxX+2,t.initialMaxX=t.maxX)}}_getMinXDiff(){const t=this.w.globals;this.w.axisFlags.isXNumeric&&this.w.seriesData.seriesX.forEach((e,i)=>{var s;if(e.length){1===e.length&&e.push(this.w.seriesData.seriesX[t.maxValsInArrayIndex][this.w.seriesData.seriesX[t.maxValsInArrayIndex].length-1]);const a=null==(s=this.w.seriesData._parsedExtrema)?void 0:s[i];if(a&&a.xNumeric&&a.xSorted&&a.xref===e&&a.len===e.length)return a.minXDiff0)it-e),o.forEach((e,i)=>{if(i>0){const s=e-o[i-1];s>0&&(t.minXDiff=Math.min(s,t.minXDiff))}}),1!==t.dataPoints&&t.minXDiff!==Number.MAX_VALUE||(t.minXDiff=.5)}})}_setStackedMinMax(){const t=this.w.globals,e=this._autoScaleYEnabled();if(!this.w.seriesData.series.length)return;let i=this.w.labelData.seriesGroups;i.length||(i=[this.w.seriesData.seriesNames.map(t=>t)]);const s={},a={};i.forEach(i=>{s[i]=[],a[i]=[];this.w.config.series.map((t,e)=>i.indexOf(this.w.seriesData.seriesNames[e])>-1?e:null).filter(t=>null!==t).forEach(r=>{var n,o,l,h;const c=e?this._autoScaleXBounds(r):null,d=this.w.seriesData.seriesX[r],p=!!(c&&d&&d.length);for(let e=0;ec.hi))continue;void 0===s[i][e]&&(s[i][e]=0,a[i][e]=0);(this.w.config.chart.stacked&&!t.comboCharts||this.w.config.chart.stacked&&t.comboCharts&&(!this.w.config.chart.stackOnlyBar||"bar"===(null==(o=null==(n=this.w.config.series)?void 0:n[r])?void 0:o.type)||"column"===(null==(h=null==(l=this.w.config.series)?void 0:l[r])?void 0:h.type)))&&null!==this.w.seriesData.series[r][e]&&v.isNumber(this.w.seriesData.series[r][e])&&(this.w.seriesData.series[r][e]>0?s[i][e]+=parseFloat(String(this.w.seriesData.series[r][e]))+1e-4:a[i][e]+=parseFloat(String(this.w.seriesData.series[r][e])))}})}),Object.entries(s).forEach(([e])=>{s[e].forEach((i,r)=>{t.maxY=Math.max(t.maxY,s[e][r]),t.minY=Math.min(t.minY,a[e][r])})})}}function Ht(){return{palette1:["#008FFB","#00A86F","#CA8501","#FF4560","#846DD5"],palette2:["#6978CB","#039DE2","#49A84D","#B39105","#D68000"],palette3:["#209FCC","#648291","#D4526E","#0FA783","#A19285"],palette4:["#2FA59D","#73A20B","#099DE1","#FD5D5D","#648291"],palette5:["#2B908F","#F56566","#2EAB16","#FA4443","#1EA2BD"],palette6:["#449DD1","#F86624","#EA3A4A","#9C63D1","#899E2A"],palette7:["#DF475B","#1B998B","#7E75B7","#F46036","#B1911B"],palette8:["#9C63D1","#F86624","#B38F04","#EA3A4A","#2FA2B3"],palette9:["#98776F","#A19285","#A8705E","#BA6560","#A0927F"],palette10:["#C91EFF","#A94BFD","#6C6AFE","#2983FF","#009ED8"],cvdDeuteranopia:["#0072B2","#E69F00","#56B4E9","#009E73","#F0E442","#D55E00","#CC79A7"],cvdProtanopia:["#0077BB","#EE7733","#009988","#EE3377","#BBBBBB","#33BBEE","#CC3311"],cvdTritanopia:["#CC3311","#009988","#EE7733","#0077BB","#EE3377","#BBBBBB","#33BBEE"],highContrast:["#005A9C","#C00000","#007A33","#6C3483","#7B3F00","#0097A7","#4A235A"]}}class $t{constructor(t,{theme:e=null,timeScale:i=null}={},s){this.w=t,this.elgrid=s,this.xaxisFontSize=t.config.xaxis.labels.style.fontSize,this.axisFontFamily=t.config.xaxis.labels.style.fontFamily,this.xaxisForeColors=t.config.xaxis.labels.style.colors,this.isCategoryBarHorizontal="bar"===t.config.chart.type&&t.config.plotOptions.bar.horizontal,this.xAxisoffX="bottom"===t.config.xaxis.position?t.layout.gridHeight:0,this.drawnLabels=[],this.axesUtils=new Bt(t,{theme:e,timeScale:i})}drawYaxis(t){const e=this.w,i=new Dt(this.w),s=e.config.yaxis[t].labels.style,{fontSize:a,fontFamily:r,fontWeight:n}=s,o=i.group({class:"apexcharts-yaxis",rel:t,transform:`translate(${e.globals.translateYAxisX[t]}, 0)`});if(this.axesUtils.isYAxisHidden(t))return o;const l=i.group({class:"apexcharts-yaxis-texts-g"});o.add(l);const h=e.globals.yAxisScale[t].result.length-1,c=e.layout.gridHeight/h,d=e.formatters.yLabelFormatters[t],p=this.axesUtils.checkForReversedLabels(t,e.globals.yAxisScale[t].result.slice());let u=1;if("heatmap"===e.config.chart.type&&!e.config.yaxis[t].labels.formatter){const t=parseInt(a,10)||11,i=Math.max(1,Math.floor(e.layout.gridHeight/(1.4*t))),s=h+1;s>i&&(u=Math.ceil(s/i))}if(e.config.yaxis[t].labels.show){let o=e.layout.translateY+e.config.yaxis[t].labels.offsetY;e.globals.isBarHorizontal?o=0:"heatmap"===e.config.chart.type&&(o-=c/2),o+=parseInt(a,10)/3;let g=null;for(let f=h;f>=0;f--){const h=u>1&&f%u!==0?"":d(p[f],f,e);let x=e.config.yaxis[t].labels.padding;e.config.yaxis[t].opposite&&0!==e.config.yaxis.length&&(x*=-1);const m=this.getTextAnchor(e.config.yaxis[t].labels.align,e.config.yaxis[t].opposite),b=this.axesUtils.getYAxisForeColor(s.colors,t),y=Array.isArray(b)?b[f]:b,w=Array.from(e.dom.baseEl.querySelectorAll(`.apexcharts-yaxis[rel='${t}'] .apexcharts-yaxis-label tspan`)).map(t=>t.textContent),v=i.drawText({x:x,y:o,text:w.includes(h)&&!e.config.yaxis[t].labels.showDuplicates?"":h,textAnchor:m,fontSize:a,fontFamily:r,fontWeight:n,maxWidth:e.config.yaxis[t].labels.maxWidth,foreColor:y,isPlainText:!1,cssClass:`apexcharts-yaxis-label ${s.cssClass}`});l.add(v),this.addTooltip(v,h),null===g&&(g=v),0!==e.config.yaxis[t].labels.rotate&&this.rotateLabel(i,v,g,e.config.yaxis[t].labels.rotate),o+=c}}return this.addYAxisTitle(i,o,t),this.addAxisBorder(i,o,t,h,c),o}getTextAnchor(t,e){return"left"===t?"start":"center"===t?"middle":"right"===t?"end":e?"start":"end"}addTooltip(t,e){const i=b.createElementNS($,"title");i.textContent=Array.isArray(e)?e.join(" "):e,t.node.appendChild(i)}rotateLabel(t,e,i,s){const a=t.rotateAroundCenter(i.node),r=t.rotateAroundCenter(e.node);e.node.setAttribute("transform",`rotate(${s} ${a.x} ${r.y})`)}addYAxisTitle(t,e,i){const s=this.w;if(void 0!==s.config.yaxis[i].title.text){const a=t.group({class:"apexcharts-yaxis-title"}),r=s.config.yaxis[i].opposite?s.globals.translateYAxisX[i]:0,n=t.drawText({x:r,y:s.layout.gridHeight/2+s.layout.translateY+s.config.yaxis[i].title.offsetY,text:s.config.yaxis[i].title.text,textAnchor:"end",foreColor:s.config.yaxis[i].title.style.color,fontSize:s.config.yaxis[i].title.style.fontSize,fontWeight:s.config.yaxis[i].title.style.fontWeight,fontFamily:s.config.yaxis[i].title.style.fontFamily,cssClass:`apexcharts-yaxis-title-text ${s.config.yaxis[i].title.style.cssClass}`});a.add(n),e.add(a)}}addAxisBorder(t,e,i,s,a){const r=this.w,n=r.config.yaxis[i].axisBorder;let o=31+n.offsetX;if(r.config.yaxis[i].opposite&&(o=-31-n.offsetX),n.show){const i=t.drawLine(o,r.layout.translateY+n.offsetY-2,o,r.layout.gridHeight+r.layout.translateY+n.offsetY+2,n.color,0,n.width);e.add(i)}r.config.yaxis[i].axisTicks.show&&this.axesUtils.drawYAxisTicks(o,s,n,r.config.yaxis[i].axisTicks,i,a,e)}drawYaxisInversed(t){const e=this.w,i=new Dt(this.w),s=i.group({class:"apexcharts-xaxis apexcharts-yaxis-inversed"}),a=i.group({class:"apexcharts-xaxis-texts-g",transform:`translate(${e.layout.translateXAxisX}, ${e.layout.translateXAxisY})`});s.add(a);let r=e.globals.yAxisScale[t].result.length-1;const n=e.layout.gridWidth/r+.1;let o=n+e.config.xaxis.labels.offsetX;const l=e.formatters.xLabelFormatter;let h=this.axesUtils.checkForReversedLabels(t,e.globals.yAxisScale[t].result.slice());const c=e.labelData.timescaleLabels;if(c.length>0&&(this.xaxisLabels=c.slice(),h=c.slice(),r=h.length),e.config.xaxis.labels.show)for(let s=c.length?0:r;c.length?s=0;c.length?s++:s--){let r=null==l?void 0:l(h[s],s,e),d=e.layout.gridWidth+e.globals.padHorizontal-(o-n+e.config.xaxis.labels.offsetX);if(c.length){const t=this.axesUtils.getLabel(h,c,d,s,this.drawnLabels,this.xaxisFontSize);d=t.x,r=t.text,this.drawnLabels.push(t.text),0===s&&e.globals.skipFirstTimelinelabel&&(r=""),s===h.length-1&&e.globals.skipLastTimelinelabel&&(r="")}const p=i.drawText({x:d,y:this.xAxisoffX+e.config.xaxis.labels.offsetY+30-("top"===e.config.xaxis.position?e.layout.xAxisHeight+e.config.xaxis.axisTicks.height-2:0),text:r,textAnchor:"middle",foreColor:Array.isArray(this.xaxisForeColors)?this.xaxisForeColors[t]:this.xaxisForeColors,fontSize:this.xaxisFontSize,fontFamily:this.axisFontFamily,fontWeight:e.config.xaxis.labels.style.fontWeight,isPlainText:!1,cssClass:`apexcharts-xaxis-label ${e.config.xaxis.labels.style.cssClass}`});a.add(p),this.addTooltip(p,r),o+=n}return this.inversedYAxisTitleText(s),this.inversedYAxisBorder(s),s}inversedYAxisBorder(t){const e=this.w,i=new Dt(this.w),s=e.config.xaxis.axisBorder;if(s.show){let a=0;"bar"===e.config.chart.type&&e.axisFlags.isXNumeric&&(a-=15);const r=i.drawLine(e.globals.padHorizontal+a+s.offsetX,this.xAxisoffX,e.layout.gridWidth,this.xAxisoffX,s.color,0,s.height);this.elgrid&&this.elgrid.elGridBorders&&e.config.grid.show?this.elgrid.elGridBorders.add(r):t.add(r)}}inversedYAxisTitleText(t){const e=this.w,i=new Dt(this.w);if(void 0!==e.config.xaxis.title.text){const s=i.group({class:"apexcharts-xaxis-title apexcharts-yaxis-title-inversed"}),a=i.drawText({x:e.layout.gridWidth/2+e.config.xaxis.title.offsetX,y:this.xAxisoffX+parseFloat(this.xaxisFontSize)+parseFloat(e.config.xaxis.title.style.fontSize)+e.config.xaxis.title.offsetY+20,text:e.config.xaxis.title.text,textAnchor:"middle",fontSize:e.config.xaxis.title.style.fontSize,fontFamily:e.config.xaxis.title.style.fontFamily,fontWeight:e.config.xaxis.title.style.fontWeight,foreColor:e.config.xaxis.title.style.color,cssClass:`apexcharts-xaxis-title-text ${e.config.xaxis.title.style.cssClass}`});s.add(a),t.add(s)}}yAxisTitleRotate(t,e){const i=this.w,s=new Dt(this.w),a=i.dom.baseEl.querySelector(`.apexcharts-yaxis[rel='${t}'] .apexcharts-yaxis-texts-g`),r=a?a.getBoundingClientRect():{width:0,height:0},n=i.dom.baseEl.querySelector(`.apexcharts-yaxis[rel='${t}'] .apexcharts-yaxis-title text`),o=n?n.getBoundingClientRect():{width:0,height:0};if(n){const a=this.xPaddingForYAxisTitle(t,r,o,e);n.setAttribute("x",String(a.xPos-(e?10:0)));const l=s.rotateAroundCenter(n);n.setAttribute("transform",`rotate(${e?-1*i.config.yaxis[t].title.rotate:i.config.yaxis[t].title.rotate} ${l.x} ${l.y})`)}}xPaddingForYAxisTitle(t,e,i,s){const a=this.w;let r=0,n=10;return void 0===a.config.yaxis[t].title.text||t<0?{xPos:r,padd:0}:(s?r=e.width+a.config.yaxis[t].title.offsetX+i.width/2+n/2:(r=-1*e.width+a.config.yaxis[t].title.offsetX+n/2+i.width/2,a.globals.isBarHorizontal&&(n=25,r=-1*e.width-a.config.yaxis[t].title.offsetX-n)),{xPos:r,padd:n})}setYAxisXPosition(t,e){const i=this.w;let s=0,a=0,r=18,n=1;i.config.yaxis.length>1&&(this.multipleYs=!0),i.config.yaxis.forEach((o,l)=>{const h=i.globals.ignoreYAxisIndexes.includes(l)||!o.show||o.floating||0===t[l].width,c=t[l].width+e[l].width;o.opposite?i.globals.isBarHorizontal?(a=i.layout.gridWidth+i.layout.translateX-1,i.globals.translateYAxisX[l]=a-o.labels.offsetX):(a=i.layout.gridWidth+i.layout.translateX+n,h||(n+=c+20),i.globals.translateYAxisX[l]=a-o.labels.offsetX+20):(s=i.layout.translateX-r,h||(r+=c+20),i.globals.translateYAxisX[l]=s+o.labels.offsetX)})}setYAxisTextAlignments(){const t=this.w;Array.from(t.dom.baseEl.getElementsByClassName("apexcharts-yaxis")).forEach((e,i)=>{const s=t.config.yaxis[i];if(s&&!s.floating&&void 0!==s.labels.align){const e=t.dom.baseEl.querySelector(`.apexcharts-yaxis[rel='${i}'] .apexcharts-yaxis-texts-g`),a=Array.from(t.dom.baseEl.querySelectorAll(`.apexcharts-yaxis[rel='${i}'] .apexcharts-yaxis-label`)),r=e.getBoundingClientRect();a.forEach(t=>{t.setAttribute("text-anchor",s.labels.align)}),"left"!==s.labels.align||s.opposite?"center"===s.labels.align?e.setAttribute("transform",`translate(${r.width/2*(s.opposite?1:-1)}, 0)`):"right"===s.labels.align&&s.opposite&&e.setAttribute("transform",`translate(${r.width}, 0)`):e.setAttribute("transform",`translate(-${r.width}, 0)`)}})}}class Gt{constructor(t,e){this.w=t,this.ctx=e,this.documentEvent=this.documentEvent.bind(this)}addEventListener(t,e){const i=this.w;Object.prototype.hasOwnProperty.call(i.globals.events,t)?i.globals.events[t].push(e):i.globals.events[t]=[e]}removeEventListener(t,e){const i=this.w;if(!Object.prototype.hasOwnProperty.call(i.globals.events,t))return;const s=i.globals.events[t].indexOf(e);-1!==s&&i.globals.events[t].splice(s,1)}fireEvent(t,e){const i=this.w;if(!Object.prototype.hasOwnProperty.call(i.globals.events,t))return;e&&e.length||(e=[]);const s=i.globals.events[t],a=s.length;for(let t=0;t{null==i||i.addEventListener(s,i=>{const s=null===i.target.getAttribute("i")&&-1!==t.interact.capturedSeriesIndex?t.interact.capturedSeriesIndex:i.target.getAttribute("i"),a=null===i.target.getAttribute("j")&&-1!==t.interact.capturedDataPointIndex?t.interact.capturedDataPointIndex:i.target.getAttribute("j"),r=Object.assign({},t,{seriesIndex:t.globals.axisCharts?s:0,dataPointIndex:a});"keydown"===i.type?t.config.chart.accessibility.enabled&&t.config.chart.accessibility.keyboard.enabled&&(e.ctx.keyboardNavigation&&e.ctx.keyboardNavigation.handleKey(i),"function"==typeof t.config.chart.events.keyDown&&t.config.chart.events.keyDown(i,e,r),e.ctx.events.fireEvent("keydown",[i,e,r])):"keyup"===i.type?t.config.chart.accessibility.enabled&&t.config.chart.accessibility.keyboard.enabled&&("function"==typeof t.config.chart.events.keyUp&&t.config.chart.events.keyUp(i,e,r),e.ctx.events.fireEvent("keyup",[i,e,r])):"mousemove"===i.type||"touchmove"===i.type?"function"==typeof t.config.chart.events.mouseMove&&t.config.chart.events.mouseMove(i,e,r):"mouseleave"===i.type||"touchleave"===i.type?"function"==typeof t.config.chart.events.mouseLeave&&t.config.chart.events.mouseLeave(i,e,r):("mouseup"===i.type&&1===i.which||"touchend"===i.type)&&("function"==typeof t.config.chart.events.click&&t.config.chart.events.click(i,e,r),e.ctx.events.fireEvent("click",[i,e,r]))},{capture:!1,passive:!0})}),this.ctx.eventList.forEach(e=>{t.dom.baseEl.addEventListener(e,this.documentEvent,{passive:!0})}),this.ctx.core.setupBrushHandler()}documentEvent(t){const e=this.w,i=t.target.className;if("click"===t.type){const t=e.dom.baseEl.querySelector(".apexcharts-menu");t&&t.classList.contains("apexcharts-menu-open")&&"apexcharts-menu-icon"!==i&&t.classList.remove("apexcharts-menu-open")}e.interact.clientX="touchmove"===t.type?t.touches[0].clientX:t.clientX,e.interact.clientY="touchmove"===t.type?t.touches[0].clientY:t.clientY}}class jt{constructor(t){this.w=t}setCurrentLocaleValues(t){let e=this.w.config.chart.locales;const i=d.getApex();i.chart&&i.chart.locales&&i.chart.locales.length>0&&(e=this.w.config.chart.locales.concat(i.chart.locales));const s=e.filter(e=>e.name===t)[0];if(!s)throw new Error("Wrong locale name provided. Please make sure you set the correct locale name in options");{const t=v.extend(C,s);this.w.globals.locale=t.options}}}class Vt{constructor(t,e){this.w=t,this.ctx=e}drawAxis(t,e){const i=this.w.globals,s=this.w.config,a=new Nt(this.w,this.ctx,e),r=new $t(this.w,{theme:this.ctx.theme,timeScale:this.ctx.timeScale},e);if(i.axisCharts&&"radar"!==t){let t,e;i.isBarHorizontal?(e=r.drawYaxisInversed(0),t=a.drawXaxisInversed(0),this.w.dom.elGraphical.add(t),this.w.dom.elGraphical.add(e)):(t=a.drawXaxis(),this.w.dom.elGraphical.add(t),s.yaxis.map((t,s)=>{if(-1===i.ignoreYAxisIndexes.indexOf(s)&&(e=r.drawYaxis(s),this.w.dom.Paper.add(e),"back"===this.w.config.grid.position)){const t=this.w.dom.Paper.children()[1];t&&(t.remove(),this.w.dom.Paper.add(t))}}))}}}class Ut{constructor(t){this.w=t}drawXCrosshairs(){const t=this.w;t.dom.elGraphical.node.querySelectorAll(":scope > .apexcharts-xcrosshairs").forEach(t=>t.remove());const e=new Dt(this.w),i=new Mt(this.w),s=t.config.xaxis.crosshairs.fill.gradient,a=t.config.xaxis.crosshairs.dropShadow,r=t.config.xaxis.crosshairs.fill.type,n=s.colorFrom,o=s.colorTo,l=s.opacityFrom,h=s.opacityTo,c=s.stops,d=a.enabled,p=a.left,u=a.top,g=a.blur,f=a.color,x=a.opacity;let m=t.config.xaxis.crosshairs.fill.color;if(t.config.xaxis.crosshairs.show){"gradient"===r&&(m=e.drawGradient("vertical",n,o,l,h,null,c,[]));let s=1===t.config.xaxis.crosshairs.width?e.drawLine(0,0,0,0):e.drawRect(),a=t.layout.gridHeight;(!v.isNumber(a)||a<0)&&(a=0);let b=t.config.xaxis.crosshairs.width;(!v.isNumber(b)||Number(b)<0)&&(b=0),s.attr({class:"apexcharts-xcrosshairs",x:0,y:0,y2:a,width:b,height:a,fill:m,filter:"none","fill-opacity":t.config.xaxis.crosshairs.opacity,stroke:t.config.xaxis.crosshairs.stroke.color,"stroke-width":t.config.xaxis.crosshairs.stroke.width,"stroke-dasharray":t.config.xaxis.crosshairs.stroke.dashArray}),d&&(s=i.dropShadow(s,{left:p,top:u,blur:g,color:f,opacity:x})),t.dom.elGraphical.add(s)}}drawYCrosshairs(){const t=this.w;t.dom.elGraphical.node.querySelectorAll(":scope > .apexcharts-ycrosshairs, :scope > .apexcharts-ycrosshairs-hidden").forEach(t=>t.remove());const e=new Dt(this.w),i=t.config.yaxis[0].crosshairs,s=t.globals.barPadForNumericAxis;if(t.config.yaxis[0].crosshairs.show){const a=e.drawLine(-s,0,t.layout.gridWidth+s,0,i.stroke.color,i.stroke.dashArray,i.stroke.width);a.attr({class:"apexcharts-ycrosshairs"}),t.dom.elGraphical.add(a)}const a=e.drawLine(-s,0,t.layout.gridWidth+s,0,i.stroke.color,0,0);a.attr({class:"apexcharts-ycrosshairs-hidden"}),t.dom.elGraphical.add(a)}}function qt(t,e){if(!v.isObject(t)||!v.isObject(e))return void 0!==e?e:t;const i=o({},t);for(const s of Object.keys(e)){const a=e[s];void 0!==a&&(v.isObject(a)&&v.isObject(t[s])?i[s]=qt(t[s],a):i[s]=a)}return i}class Zt{constructor(t){this.w=t,this._activeBreakpoint=null}checkResponsiveConfig(t){const e=this.w,i=e.config;if(0===i.responsive.length)return;const s=i.responsive.slice();s.sort((t,e)=>t.breakpoint>e.breakpoint?1:e.breakpoint>t.breakpoint?-1:0).reverse();const a=new X({}),r=(t={})=>{var i;const r=s[0].breakpoint,n=d.isBrowser()?window.innerWidth>0?window.innerWidth:screen.width:0;if(n>r){if(null!==this._activeBreakpoint){if(!e.globals.initialConfig)return;const i=v.clone(e.globals.initialConfig);i.series=v.clone(e.config.series);const s=H.extendArrayProps(a,i,e);t=v.extend(s,t),this.overrideResponsiveOptions(t),this._activeBreakpoint=null}}else for(let r=0;rqt(t,i[e]))})}this.overrideResponsiveOptions(t),this._activeBreakpoint=s[r].breakpoint}};if(t){let i=H.extendArrayProps(a,t,e);i=v.extend(e.config,i),i=v.extend(i,t),r(i)}else r({})}overrideResponsiveOptions(t){const e=new X(t).init({responsiveOverride:!0});this.w.config=e}}const Kt=/[+-]?(?:\d+\.?\d*|\.\d+)(?:e[+-]?\d+)?/gi;function Jt(t,e){const{ax:i,bx:s,ay:a,by:r}=e,n=[],o=/([MmLlHhVvCcSsQqTtAaZz])([^MmLlHhVvCcSsQqTtAaZz]*)/g;let l;for(;null!==(l=o.exec(t));){const t=l[1].toUpperCase(),e=(l[2].match(Kt)||[]).map(parseFloat);if("Z"===t){n.push("z");continue}if("H"===t){for(const t of e)n.push(`H ${i*t+s}`);continue}if("V"===t){for(const t of e)n.push(`V ${a*t+r}`);continue}if("A"===t){for(let t=0;t+6"C"===t[0]?[Number(t[5]),Number(t[6])]:[Number(t[1]),Number(t[2])]);for(const t of o)if(!isFinite(t[0])||!isFinite(t[1]))return null;return{body:a,closing:r,segType:n,anchors:o}}function te(t,e,i){return[t[0]+(e[0]-t[0])*i,t[1]+(e[1]-t[1])*i]}function ee(t,e,i){const s=t,a=[e[1],e[2]],r=[e[3],e[4]],n=[e[5],e[6]],o=te(s,a,i),l=te(a,r,i),h=te(r,n,i),c=te(o,l,i),d=te(l,h,i),p=te(c,d,i);return{first:["C",o[0],o[1],c[0],c[1],p[0],p[1]],second:["C",d[0],d[1],h[0],h[1],n[0],n[1]],mid:p}}function ie(t,e,i){const s=[e[1],e[2]],a=te(t,s,i);return{first:["L",a[0],a[1]],second:["L",s[0],s[1]],mid:a}}function se(t,e){const{body:i,closing:s,segType:a,anchors:r}=t,n=r.length,o=e.length,l=t=>"C"===a?["C",t[0],t[1],t[0],t[1],t[0],t[1]]:["L",t[0],t[1]],h=[["M",r[0][0],r[0][1]]];let c=0;for(;ch.push(t.slice())),h}function ae(t,e,i,s,a,r){const n=Qt(t,s,r);if(!n)return null;const o=Qt(e,a,r);if(!o)return null;if(n.segType!==o.segType)return null;if((n.closing||o.closing)&&(!n.closing||!o.closing||n.closing[0][0]!==o.closing[0][0]))return null;const l=i.map(t=>t.oldJ),h=i.map(t=>t.newJ);return{from:Z(se(n,l)),toInterp:Z(se(o,h))}}function re(t){var e;const i=t.config.chart.animations;if(!i||!1===i.enabled)return!1;if(!i.dynamicAnimation||!1===i.dynamicAnimation.enabled)return!1;const s=null!=(e=i.largeDatasetThreshold)?e:0;return!(s>0&&t.globals.dataPoints>s)&&!!(d.isBrowser()&&t.globals.dataChanged&&t.globals.shouldAnimate)}function ne(t,e,i){var s,a,r,n;if(null==(s=t.axisFlags)?void 0:s.isXNumeric){const s=null==(r=null==(a=t.seriesData)?void 0:a.seriesX)?void 0:r[e];if(s&&s.length&&null!=s[i])return"x:"+s[i]}const o=null==(n=t.globals.labels)?void 0:n[i];return null!=o&&""!==String(o)?"c:"+(Array.isArray(o)?o.join(" "):String(o)):"j:"+i}function oe(t){const e=new Map;return t.map(t=>{const i=e.get(t)||0;return e.set(t,i+1),0===i?t:`${t}#${i}`})}function le(t,e,i=!1,s=!1){var a,r;if(!re(t))return null;const n=t.globals.prevStreamFrame;if(!n)return null;const o=null==(a=n.seriesY)?void 0:a[e],l=null==(r=t.seriesData.series)?void 0:r[e];if(!Array.isArray(o)||!Array.isArray(l))return null;if(!o.length||!l.length)return null;const h=oe(o.map((t,i)=>function(t,e,i){var s,a;if(t.isXNumeric){const a=null==(s=t.seriesX)?void 0:s[e];if(a&&a.length&&null!=a[i])return"x:"+a[i]}const r=null==(a=t.labels)?void 0:a[i];return null!=r&&""!==String(r)?"c:"+(Array.isArray(r)?r.join(" "):String(r)):"j:"+i}(n,e,i))),c=oe(l.map((i,s)=>ne(t,e,s))),d=function(t,e){const i=new Map;t.forEach((t,e)=>{i.has(t)||i.set(t,e)});const s=new Array(e.length),a=new Set;let r=-1,n=!0,o=t.length===e.length;e.forEach((t,e)=>{const l=i.has(t)&&!a.has(i.get(t))?i.get(t):-1;s[e]=l,-1!==l&&(a.add(l),l{if(t.globals.isDestroyed)return;const l=Math.max(0,Math.min(1,(o-r)/e));s(i(l),l),l<1?b.requestAnimationFrame(n):a&&a()};b.requestAnimationFrame(n)}function de(t,{elPointsMain:e,realIndex:i,speed:s}){var a,r,n,o;if(!(null==e?void 0:e.node))return!1;const l=le(t,i,!0);if(!l)return!1;const h=t.globals.prevStreamFrame;if(!h)return!1;const c=null==(a=h.xPixels)?void 0:a[i],d=null==(r=h.yPixels)?void 0:r[i];if(!c||!d)return!1;const p=e.node.querySelectorAll(".apexcharts-marker");if(!p.length)return!1;const u=(null==(n=t.globals.seriesXvalues)?void 0:n[i])||[],g=(null==(o=t.globals.seriesYvalues)?void 0:o[i])||[],f=he(t),x=Math.max(1,s||1);return e.node.classList.remove("apexcharts-element-hidden"),p.forEach(e=>{var s,a,r,n,o,p,m,b,y;const w=parseInt(null!=(a=null!=(s=e.getAttribute("j"))?s:e.getAttribute("rel"))?a:"",10);if(!isFinite(w)||w<0||w>=l.join.toOld.length)return;const v=l.join.toOld[w],A=null!=u[w]&&null!=g[w]?[u[w],g[w]]:null;if(-1===v||!A){const i=e.style;return i.opacity="0",void ce(t,x,f,t=>{i.opacity=String(t)},()=>{i.opacity=""})}const S=(null!=(r=c[v])?r:NaN)-A[0],C=(null!=(n=d[v])?n:NaN)-A[1];if(!isFinite(S)||!isFinite(C))return;const k=null!=(m=null==(p=null==(o=h.rPixels)?void 0:o[i])?void 0:p[v])?m:NaN,_=parseFloat(null!=(y=null!=(b=e.getAttribute("r"))?b:e.getAttribute("default-marker-size"))?y:""),M=isFinite(k)&&isFinite(_)&&_>0&&Math.abs(k-_)>.25;if(!(Math.abs(S)>=.5||Math.abs(C)>=.5)&&!M)return;const D=t=>{const i=S*(1-t),s=C*(1-t);if(M){const a=(k+(_-k)*t)/_;e.setAttribute("transform",`translate(${i+A[0]*(1-a)}, ${s+A[1]*(1-a)}) scale(${a})`)}else e.setAttribute("transform",`translate(${i}, ${s})`)};D(0),ce(t,x,f,D,()=>{e.removeAttribute("transform")})}),!0}function pe(t,{type:e,realIndex:i,pathFromLine:s,pathFromArea:a,linePaths:r,areaPaths:n}){var o,l;const h=le(t,i);if(!h)return null;const{join:c,oldKeys:d,newKeys:p}=h,u=t.globals.prevStreamFrame;if(!u)return null;const g=null==(o=u.seriesY)?void 0:o[i],f=null==(l=t.seriesData.series)?void 0:l[i];if(g.length<2||f.length<2)return null;if(g.some(t=>null===t)||f.some(t=>null===t))return null;const x=function(t,e){const i=new Set(t.exits),s=[];let a=0;for(let e=0;et&&t.d&&null!=t.key&&!o.has(t.key));if(!l.length)return;const h=new Dt(t),c=null==(n=t.globals.colors)?void 0:n[parseInt(String(i.realIndex),10)];l.forEach(i=>{let s=i.fill||c||"#c8c8c8";0===String(s).indexOf("url(")&&(s=c||"#c8c8c8");const n=h.drawPath({d:i.d,stroke:"none",strokeWidth:0,fill:s,fillOpacity:1,classes:"apexcharts-bar-ghost"}),o=n.node;o.setAttribute("pointer-events","none"),n.attr("clip-path",`url(#gridRectBarMask${t.globals.cuid})`),e.node.insertBefore(o,e.node.firstChild);const l=function(t){const e=/^M\s*([+-]?[\d.eE]+)[\s,]+([+-]?[\d.eE]+)/.exec(t||"");if(!e)return null;const i=parseFloat(e[1]),s=parseFloat(e[2]);return isFinite(i)&&isFinite(s)?{x:i,y:s}:null}(i.d);let d=a?"left center":"center bottom";try{const t=o.getBBox();l&&t&&(d=a?Math.abs(l.x-t.x)<=Math.abs(l.x-(t.x+t.width))?"left center":"right center":Math.abs(l.y-(t.y+t.height))<=Math.abs(l.y-t.y)?"center bottom":"center top")}catch(t){}const p=o.style;p.transformBox="fill-box",p.transformOrigin=d;const u=Math.max(1,r||1),g=performance.now(),f=e=>{if(t.globals.isDestroyed||!o.parentNode)return;const i=Math.max(0,Math.min(1,(e-g)/u)),s=1-Math.pow(1-i,3),r=1-s;p.transform=a?`scaleX(${r})`:`scaleY(${r})`,p.opacity=String(1-s),i<1?b.requestAnimationFrame(f):o.parentNode.removeChild(o)};b.requestAnimationFrame(f)})}function ge(t,e,i){return[...t.querySelectorAll(e)].map(t=>{var e,s,a;return{text:t.textContent||"",display:null!=(a=null!=(s=null==(e=t.querySelector("tspan"))?void 0:e.textContent)?s:t.textContent)?a:"",pos:parseFloat(t.getAttribute(i)||""),transform:t.getAttribute("transform")}})}function fe(t,e,i){return[...t.querySelectorAll(e)].map(t=>parseFloat(t.getAttribute(i)||""))}const xe=":not(.apexcharts-tick-ghost)",me=`.apexcharts-xaxis-texts-g text:not(.apexcharts-xaxis-group-label)${xe}`,be=`.apexcharts-yaxis-texts-g text${xe}`,ye=`.apexcharts-gridlines-vertical line${xe}`,we=`.apexcharts-gridlines-horizontal line${xe}`;function ve(t){var e,i;const s=t.globals;if(!(null==(e=t.axisFlags)?void 0:e.isXNumeric)||s.isBarHorizontal)return null;if(null==(i=t.config.xaxis)?void 0:i.reversed)return null;const a=s.minX,r=s.maxX,n=t.layout.gridWidth;return isFinite(a)&&isFinite(r)&&r>a&&n>0?{min:a,max:r,width:n}:null}function Ae(t,e){var i;const s=t.globals;if(s.isBarHorizontal)return null;if(!Array.isArray(t.config.yaxis)||1!==t.config.yaxis.length)return null;if(null==(i=t.config.yaxis[0])?void 0:i.logarithmic)return null;const a=s.minY,r=s.maxY;if(!(isFinite(a)&&isFinite(r)&&r>a))return null;const n=e.map(t=>t.pos).filter(t=>isFinite(t));return n.length<2?null:{min:a,max:r,pLo:Math.max(...n),pHi:Math.min(...n)}}function Se(t,e){if(!t||!e)return null;const i=t.pHi-t.pLo,s=e.pHi-e.pLo,a=t.max-t.min,r=e.max-e.min;if(!(i&&s&&a>0&&r>0))return null;return{toNew:n=>e.pLo+((e=>t.min+(e-t.pLo)/i*a)(n)-e.min)/r*s,toOld:n=>t.pLo+((t=>e.min+(t-e.pLo)/s*r)(n)-t.min)/a*i}}function Ce(t,e,i,s){const a=e.style;a.opacity="0",ce(t,i,s,t=>{a.opacity=String(t)},()=>{a.opacity=""})}function ke(t,e,i,s,a,r,n){i.forEach(t=>e.setAttribute(t,String(s))),ce(t,r,n,t=>{const r=String(s+(a-s)*t);i.forEach(t=>e.setAttribute(t,r))},()=>{i.forEach(t=>e.setAttribute(t,String(a)))})}function _e(t,{template:e,display:i,attrs:s,from:a,to:r,duration:n,ease:o}){const l=e.parentNode;if(!l)return;const h=e.cloneNode(!0);if(h.classList.add("apexcharts-tick-ghost"),h.setAttribute("pointer-events","none"),h.removeAttribute("id"),void 0!==i){const t=h.querySelector("tspan");t?t.textContent=i:h.textContent=i;const e=h.querySelector("title");e&&(e.textContent=i)}s.forEach(t=>h.setAttribute(t,String(a)));const c=h.style;c.opacity="1",l.appendChild(h),ce(t,n,o,t=>{const e=String(a+(r-a)*t);s.forEach(t=>h.setAttribute(t,e)),c.opacity=String(1-t)},()=>{h.parentNode&&h.parentNode.removeChild(h)})}function Me(t,{newLabels:e,oldLabels:i,posAttr:s,newLines:a,oldLines:r,lineAttrs:n,duration:h,ease:c,project:d}){const p=new Map;i.forEach((t,e)=>{p.has(t.text)||p.set(t.text,l(o({},t),{i:e}))});const u=new Set,g=a.length===e.length,f=r.length===i.length,x=i.map(t=>t.pos).concat(e.map(t=>parseFloat(t.getAttribute(s)||""))).filter(t=>isFinite(t)),m=Math.min(...x),b=Math.max(...x),y=Math.max(40,.25*(b-m)),w=t=>Math.max(m-y,Math.min(b+y,t)),v=(e,i)=>{if(!e)return;const s=parseFloat(e.getAttribute(n[0])||""),a=r[i.i];isFinite(s)&&isFinite(a)&&ke(t,e,n,a,s,h,c)};if(e.forEach((e,i)=>{const r=parseFloat(e.getAttribute(s)||""),o=p.get(e.textContent||""),l=g?a[i]:null;o&&u.add(o.i);const f=e.getAttribute("transform");if(o&&isFinite(o.pos)){if(isFinite(r)&&!(Math.abs(o.pos-r)<.5)){if(f||o.transform){const i=o.pos-r;if(isFinite(i)){const a=f||"";ce(t,h,c,t=>{const r=i*(1-t),n="x"===s?`translate(${r} 0)`:`translate(0 ${r})`;e.setAttribute("transform",`${n} ${a}`.trim())},()=>{a?e.setAttribute("transform",a):e.removeAttribute("transform")})}return void v(l,o)}ke(t,e,[s],o.pos,r,h,c),v(l,o)}}else if(!o){if(d&&isFinite(r)&&!f){const i=isFinite(d.toOld(r))?w(d.toOld(r)):NaN;isFinite(i)&&Math.abs(i-r)>.5&&(ke(t,e,[s],i,r,h,c),l&&ke(t,l,n,i,r,h,c))}Ce(t,e,h,c),l&&Ce(t,l,h,c)}}),!d||!e.length)return;let A=0;i.forEach((i,o)=>{if(u.has(o))return;if(!isFinite(i.pos)||i.transform)return;if(A>=20)return;const l=d.toNew(i.pos);!isFinite(l)||Math.abs(l-i.pos)<.5||(A++,_e(t,{template:e[0],display:i.display,attrs:[s],from:i.pos,to:w(l),duration:h,ease:c}),f&&a.length&&isFinite(r[o])&&_e(t,{template:a[0],attrs:n,from:r[o],to:w(d.toNew(r[o])),duration:h,ease:c}))})}function De(t){const e=t.globals,i=e.prevChromeFrame;if(e.prevChromeFrame=null,!i||!e.axisCharts||!d.isBrowser())return;if(!re(t))return;if(!(t.seriesData.series||[]).some((e,i)=>null!==le(t,i,!0,!0)))return;const s=t.dom.baseEl;if(!v.elementExists(s))return;const a=Math.max(1,t.config.chart.animations.dynamicAnimation.speed||1),r=he(t);try{const e=[...s.querySelectorAll(be)],n=function(t,e){if(!t||!e)return null;const i=t.max-t.min,s=e.max-e.min;return i>0&&s>0&&t.width>0&&e.width>0?{toNew:a=>(t.min+a/t.width*i-e.min)/s*e.width,toOld:a=>(e.min+a/e.width*s-t.min)/i*t.width}:null}(i.xScale,ve(t)),o=Se(i.yAnchors,Ae(t,e.map(t=>({pos:parseFloat(t.getAttribute("y")||"")}))));Me(t,{newLabels:[...s.querySelectorAll(me)],oldLabels:i.xLabels,posAttr:"x",newLines:[...s.querySelectorAll(ye)],oldLines:i.vGrid,lineAttrs:["x1","x2"],duration:a,ease:r,project:n}),Me(t,{newLabels:e,oldLabels:i.yLabels,posAttr:"y",newLines:[...s.querySelectorAll(we)],oldLines:i.hGrid,lineAttrs:["y1","y2"],duration:a,ease:r,project:o})}catch(t){}}const Le=".apexcharts-data-labels[data\\:dlKey]",Pe=".apexcharts-datalabel",Fe=".apexcharts-datalabel-total[data\\:dlTotalKey]";function Ee(t){var e,i;const s=t.config.dataLabels;return!(!(null==(e=null==s?void 0:s.animate)?void 0:e.enabled)&&!(null==(i=null==s?void 0:s.countUp)?void 0:i.enabled))}function Te(t){if(!isFinite(t))return 0;const e=String(Math.abs(t)),i=e.indexOf("e");if(-1!==i){const t=e.slice(0,i),s=parseInt(e.slice(i+1),10),a=t.indexOf("."),r=-1===a?0:t.length-a-1;return Math.min(6,Math.max(0,r-s))}const s=e.indexOf(".");return-1===s?0:Math.min(6,e.length-s-1)}function Ie(t,e){const i=t.querySelector("tspan");i?i.textContent=e:t.textContent=e}function Re(t,{el:e,oldCx:i,oldCy:s,duration:a,ease:r,delay:n=0}){const o=e.hasAttribute("cx")?e:e.querySelector(Pe);if(!o)return;const l=i-parseFloat(o.getAttribute("cx")||""),h=s-parseFloat(o.getAttribute("cy")||"");if(!isFinite(l)||!isFinite(h))return;if(Math.abs(l)+Math.abs(h)<=.5)return;const c=e.getAttribute("transform")||"",d=()=>ce(t,a,r,t=>{const i=1-t;e.setAttribute("transform",`translate(${l*i} ${h*i}) ${c}`.trim())},()=>{c?e.setAttribute("transform",c):e.removeAttribute("transform")});n>0?(e.setAttribute("transform",`translate(${l} ${h}) ${c}`.trim()),setTimeout(()=>{t.globals.isDestroyed||d()},n)):d()}function ze(t,{el:e,from:i,to:s,formatter:a,fmtOpts:r,duration:n,ease:o,delay:l=0}){if(!isFinite(i)||!isFinite(s))return;if(Math.abs(s-i)<=1e-9)return;const h=Math.max(Te(i),Te(s)),c=t=>{const e=Number(t.toFixed(h));let i=e;if("function"==typeof a)try{i=a(e,r)}catch(t){i=e}return String(i)},d=()=>ce(t,n,o,t=>{Ie(e,c(i+(s-i)*t))},()=>{Ie(e,c(s))});l>0?(Ie(e,c(i)),setTimeout(()=>{t.globals.isDestroyed||d()},l)):d()}function Xe(t){var e,i;const s=t.globals,a=s.prevDataLabels;if(s.prevDataLabels=null,!a||!s.axisCharts||!d.isBrowser())return;if(!Ee(t))return;if(!re(t))return;const r=t.dom.baseEl;if(!v.elementExists(r))return;const n=t.config.dataLabels,h=!!(null==(e=n.animate)?void 0:e.enabled),c=!!(null==(i=n.countUp)?void 0:i.enabled),p=n.formatter,u=Math.max(1,t.config.chart.animations.dynamicAnimation.speed||1),g=he(t);try{r.querySelectorAll(Le).forEach(e=>{const i=e.getAttribute("data:dlKey");if(!i)return;const s=e.querySelector(Pe);if(!s)return;const r=a.get(i),n=parseInt(e.getAttribute("data:dlDelay")||"0",10)||0;if(h&&(r&&isFinite(r.cx)&&isFinite(r.cy)?Re(t,{el:e,oldCx:r.cx,oldCy:r.cy,duration:u,ease:g,delay:n}):r||function(t,e,i,s){const a=e.style;a.opacity="0",ce(t,i,s,t=>{a.opacity=String(t)},()=>{a.opacity=""})}(t,e,u,g)),c&&r){const a=parseInt(i,10),h=parseInt(e.getAttribute("data:dlJ")||"",10);ze(t,{el:s,from:r.val,to:parseFloat(e.getAttribute("data:dlVal")||""),formatter:p,fmtOpts:l(o({},t),{seriesIndex:a,dataPointIndex:isFinite(h)?h:0,w:t}),duration:u,ease:g,delay:n})}});const e=t.config.plotOptions.bar.dataLabels.total.formatter||p;r.querySelectorAll(Fe).forEach(i=>{const s=i.getAttribute("data:dlTotalKey");if(!s)return;const r=a.get(`total::${s}`);if(!r)return;const n=parseInt(i.getAttribute("data:dlDelay")||"0",10)||0;if(h&&isFinite(r.cx)&&isFinite(r.cy)&&Re(t,{el:i,oldCx:r.cx,oldCy:r.cy,duration:u,ease:g,delay:n}),c){const a=parseInt(i.getAttribute("data:dlTotalSeries")||s,10);ze(t,{el:i,from:r.val,to:parseFloat(i.getAttribute("data:dlTotalVal")||""),formatter:e,fmtOpts:l(o({},t),{seriesIndex:a,dataPointIndex:0,w:t}),duration:u,ease:g,delay:n})}})}catch(t){}}class Be{constructor(t,{toggleDataSeries:e,revertDefaultAxisMinMax:i,updateSeries:s}={}){this.w=t,this._toggleDataSeries=e||null,this._revertDefaultAxisMinMax=i||null,this._updateSeries=s||null,this.legendInactiveClass="legend-mouseover-inactive"}clearSeriesCache(){const t=this.w;t.globals.cachedSelectors&&(delete t.globals.cachedSelectors.allSeriesEls,delete t.globals.cachedSelectors.highlightSeriesEls)}getAllSeriesEls(){const t=this.w,e="allSeriesEls";return t.globals.cachedSelectors[e]||(t.globals.cachedSelectors[e]=t.dom.baseEl.getElementsByClassName("apexcharts-series")),t.globals.cachedSelectors[e]}getSeriesByName(t){return this.w.dom.baseEl.querySelector(`.apexcharts-inner .apexcharts-series[seriesName='${v.escapeString(t)}']`)}isSeriesHidden(t){var e;const i=this.getSeriesByName(t),s=parseInt(null!=(e=i.getAttribute("data:realIndex"))?e:"0",10);return{isHidden:i.classList.contains("apexcharts-series-collapsed"),realIndex:s}}addCollapsedClassToSeries(t,e){Be.addCollapsedClassToSeries(this.w,t,e)}static addCollapsedClassToSeries(t,e,i){let s=!1;function a(t){for(let a=0;a{t.globals.isDestroyed||e.node.classList.remove("apexcharts-series-collapsing")},n)}toggleSeries(t){var e;const i=this.isSeriesHidden(t);return null==(e=this._toggleDataSeries)||e.call(this,i.realIndex,i.isHidden),i.isHidden}showSeries(t){var e;const i=this.isSeriesHidden(t);i.isHidden&&(null==(e=this._toggleDataSeries)||e.call(this,i.realIndex,!0))}hideSeries(t){var e;const i=this.isSeriesHidden(t);i.isHidden||null==(e=this._toggleDataSeries)||e.call(this,i.realIndex,!1)}prepareDataUpdate(){const t=this.w;this.clearSeriesCache(),t.globals.previousPaths=[],t.globals.axisCharts||(t.globals.collapsedSeries=[],t.globals.ancillaryCollapsedSeries=[],t.globals.collapsedSeriesIndices=[],t.globals.ancillaryCollapsedSeriesIndices=[])}resetSeries(t=!0,e=!0,i=!0){var s,a;const r=this.w;this.clearSeriesCache();let n=v.clone(r.globals.initialSeries);Array.isArray(n)||(n=v.clone(r.config.series)||[]),r.globals.previousPaths=[],i?(r.globals.collapsedSeries=[],r.globals.ancillaryCollapsedSeries=[],r.globals.collapsedSeriesIndices=[],r.globals.ancillaryCollapsedSeriesIndices=[]):n=this.emptyCollapsedSeries(n),r.config.series=n,t&&(e&&(r.interact.zoomed=!1,null==(s=this._revertDefaultAxisMinMax)||s.call(this)),null==(a=this._updateSeries)||a.call(this,n,r.config.chart.animations.dynamicAnimation.enabled))}emptyCollapsedSeries(t){const e=this.w;if(!Array.isArray(t))return t;for(let i=0;i-1&&(t[i]&&"object"==typeof t[i]?t[i].data=[]:t[i]=0);return t}_deriveSeriesNames(t){const e=this.w,i=t||e.config.series||[],s=e.config.labels||[];return i.map((t,e)=>t&&"object"==typeof t&&null!=t.name?String(t.name):null!=s[e]?String(s[e]):`series-${e+1}`)}reconcileCollapsedByName(t){const e=this.w,i=e.globals,s=t||e.config.series,a=this._deriveSeriesNames(s),r=t=>{const e=[],r=[];return t.forEach(t=>{const n=t&&null!=t.name?a.indexOf(t.name):t.index;if(null==n||n<0||n>=s.length)return;const o=s[n];t.index=n,i.axisCharts?o&&Array.isArray(o.data)&&o.data.length&&(t.data=o.data.slice()):t.data=o,e.push(t),r.push(n)}),{records:e,indices:r}},n=r(i.collapsedSeries);i.collapsedSeries=n.records,i.collapsedSeriesIndices=n.indices;const o=r(i.ancillaryCollapsedSeries);i.ancillaryCollapsedSeries=o.records,i.ancillaryCollapsedSeriesIndices=o.indices,i.allSeriesCollapsed=i.collapsedSeries.length+i.ancillaryCollapsedSeries.length===s.length,this.emptyCollapsedSeries(s)}canvasRestyle(t){const e=this.w.globals.activeRenderer;e&&"canvas"===e.kind&&"function"==typeof e.restyle&&e.restyle(t)}highlightSeries(t){var e;const i=this.w,s=this.getSeriesByName(t),a=parseInt(null!=(e=null==s?void 0:s.getAttribute("data:realIndex"))?e:"",10),r="highlightSeriesEls";let n=i.globals.cachedSelectors[r];n||(n=i.dom.baseEl.querySelectorAll(".apexcharts-series, .apexcharts-datalabels, .apexcharts-yaxis"),i.globals.cachedSelectors[r]=n);let o=null,l=null,h=null;if(i.globals.axisCharts||"radialBar"===i.config.chart.type)if(i.globals.axisCharts){o=i.dom.baseEl.querySelector(`.apexcharts-series[data\\:realIndex='${a}']`),l=i.dom.baseEl.querySelector(`.apexcharts-datalabels[data\\:realIndex='${a}']`);const t=i.globals.seriesYAxisReverseMap[a];h=i.dom.baseEl.querySelector(`.apexcharts-yaxis[rel='${t}']`)}else o=i.dom.baseEl.querySelector(`.apexcharts-series[rel='${a+1}']`);else o=i.dom.baseEl.querySelector(`.apexcharts-series[rel='${a+1}'] path`);for(let t=0;t{for(let e=0;e=n.from&&e<=n.to&&s[t].classList.remove(this.legendInactiveClass)}}}getActiveConfigSeriesIndex(t="asc",e=[]){const i=this.w;let s=0;if(i.config.series.length>1){const a=i.config.series.map((t,s)=>t.data&&t.data.length>0&&-1===i.globals.collapsedSeriesIndices.indexOf(s)&&(!i.globals.comboCharts||0===e.length||e.length&&e.indexOf(i.config.series[s].type)>-1)?s:-1);for(let e="asc"===t?0:a.length-1;"asc"===t?e=0;"asc"===t?e++:e--)if(-1!==a[e]){s=a[e];break}}return s}getActiveConfigSeriesIndexByGroup(t=[]){const e=this.w;return(e.labelData.seriesGroups||[]).map(i=>{let s=-1;return e.config.series.forEach((a,r)=>{if(-1===i.indexOf(e.seriesData.seriesNames[r]))return;if(e.globals.comboCharts&&t.length&&-1===t.indexOf(a.type))return;a.data&&a.data.length>0&&-1===e.globals.collapsedSeriesIndices.indexOf(r)&&(s=r)}),s})}getBarSeriesIndices(){return this.w.globals.comboCharts?this.w.config.series.map((t,e)=>"bar"===t.type||"column"===t.type?e:-1).filter(t=>-1!==t):this.w.config.series.map((t,e)=>e)}getPreviousPaths(){var t,e,i,s;const a=this.w;if(function(t){var e,i,s;const a=t.globals;if(a.streamScrolled=!1,!a.axisCharts||!t.seriesData||!Array.isArray(t.seriesData.series)||0===t.seriesData.series.length)return void(a.prevStreamFrame=null);const r=[];(null==(i=null==(e=t.dom)?void 0:e.baseEl)?void 0:i.querySelectorAll)&&t.dom.baseEl.querySelectorAll(".apexcharts-marker").forEach(t=>{var e,i,s,a,n;const o=parseInt(null!=(e=t.getAttribute("index"))?e:"",10),l=parseInt(null!=(s=null!=(i=t.getAttribute("j"))?i:t.getAttribute("rel"))?s:"",10),h=parseFloat(null!=(n=null!=(a=t.getAttribute("r"))?a:t.getAttribute("default-marker-size"))?n:"");isFinite(o)&&isFinite(l)&&isFinite(h)&&((r[o]=r[o]||[])[l]=h)}),a.prevStreamFrame={seriesX:(t.seriesData.seriesX||[]).slice(),seriesY:t.seriesData.series.slice(),xPixels:(a.seriesXvalues||[]).slice(),yPixels:(a.seriesYvalues||[]).slice(),rPixels:r,labels:(a.labels||[]).slice(),isXNumeric:!!(null==(s=t.axisFlags)?void 0:s.isXNumeric)}}(a),function(t){const e=t.globals;if(e.prevChromeFrame=null,!e.axisCharts||!d.isBrowser())return;const i=t.dom.baseEl;if(v.elementExists(i))try{const s=ge(i,be,"y");e.prevChromeFrame={xLabels:ge(i,me,"x"),yLabels:s,vGrid:fe(i,ye,"x1"),hGrid:fe(i,we,"y1"),xScale:ve(t),yAnchors:Ae(t,s)}}catch(t){e.prevChromeFrame=null}}(a),function(t){const e=t.globals;if(e.prevDataLabels=null,!e.axisCharts||!d.isBrowser())return;if(!Ee(t))return;const i=t.dom.baseEl;if(v.elementExists(i))try{const t=new Map;i.querySelectorAll(Le).forEach(e=>{const i=e.getAttribute("data:dlKey");if(!i)return;const s=e.querySelector(Pe);s&&t.set(i,{cx:parseFloat(s.getAttribute("cx")||""),cy:parseFloat(s.getAttribute("cy")||""),val:parseFloat(e.getAttribute("data:dlVal")||"")})}),i.querySelectorAll(Fe).forEach(e=>{const i=e.getAttribute("data:dlTotalKey");i&&t.set(`total::${i}`,{cx:parseFloat(e.getAttribute("cx")||""),cy:parseFloat(e.getAttribute("cy")||""),val:parseFloat(e.getAttribute("data:dlTotalVal")||"")})}),e.prevDataLabels=t.size?t:null}catch(t){e.prevDataLabels=null}}(a),!a.globals.axisCharts)return void(a.globals.previousPaths=a.seriesData.series);if(!v.elementExists(a.dom.baseEl))return void(a.globals.previousPaths=[]);function r(t,e,i){const s=t[e].childNodes,r={type:i,paths:[],realIndex:t[e].getAttribute("data:realIndex")};for(let t=0;t{const e=(i=t,a.dom.baseEl.querySelectorAll(`.apexcharts-${i}-series .apexcharts-series`));var i;for(let i=0;i0)for(let r=0;ro[a].getAttribute(t),n={x:parseFloat(null!=(t=r("x"))?t:"0"),y:parseFloat(null!=(e=r("y"))?e:"0"),width:parseFloat(null!=(i=r("width"))?i:"0"),height:parseFloat(null!=(s=r("height"))?s:"0")};l.push({rect:n,color:o[a].getAttribute("color")})}a.globals.previousPaths.push(l)}}clearPreviousPaths(){const t=this.w;t.globals.previousPaths=[],t.globals.allSeriesCollapsed=!1}handleNoData(){const t=this.w,e=t.config.noData,i=new Dt(this.w);let s=t.globals.svgWidth/2,a=t.globals.svgHeight/2,r="middle";if(t.globals.noData=!0,t.globals.animationEnded=!0,"left"===e.align?(s=10,r="start"):"right"===e.align&&(s=t.globals.svgWidth-10,r="end"),"top"===e.verticalAlign?a=50:"bottom"===e.verticalAlign&&(a=t.globals.svgHeight-50),s+=e.offsetX,a=a+parseInt(e.style.fontSize,10)+2+e.offsetY,void 0!==e.text&&""!==e.text){const n=i.drawText({x:s,y:a,text:e.text,textAnchor:r,fontSize:e.style.fontSize,fontFamily:e.style.fontFamily,foreColor:e.style.color,opacity:1,cssClass:"apexcharts-text-nodata"});t.dom.Paper.add(n)}}setNullSeriesToZeroValues(t){const e=this.w;for(let i=0;it.length>0?t:[])}}const Ne={accent:"--apx-accent",fore:"--apx-fore",grid:"--apx-grid",surface:"--apx-surface"};const Oe="__apexcharts_themes__";function Ye(){return globalThis[Oe]}globalThis[Oe]||(globalThis[Oe]={});const We="#373d3f",He="#f6f7f8",$e="#e0e0e0";class Ge{constructor(t){this.w=t,this.colors=[],this.isColorFn=!1,this.isHeatmapDistributed=this.checkHeatmapDistributed(),this.isBarDistributed=this.checkBarDistributed(),this._tokens={},this._namedTheme=null}checkHeatmapDistributed(){const{chart:t,plotOptions:e}=this.w.config;return"treemap"===t.type&&e.treemap&&e.treemap.distributed||"heatmap"===t.type&&e.heatmap&&e.heatmap.distributed}checkBarDistributed(){const{chart:t,plotOptions:e}=this.w.config;return e.bar&&e.bar.distributed&&("bar"===t.type||"rangeBar"===t.type)}init(){this.setDefaultColors()}setDefaultColors(){var t;const e=this.w,i=new v;var s;this._namedTheme=(s=e.config.theme.name)&&Ye()[s]||null,this._applyNamedThemeMode(),e.dom.elWrap.classList.add(`apexcharts-theme-${e.config.theme.mode||"light"}`),this._applyModeDefaults(),this._tokens=this._resolveTokens(),this.applyTokenChrome(this._tokens);const a=null==(t=e.config.theme.accessibility)?void 0:t.colorBlindMode;if(a){e.globals.colors=this.getColorBlindColors(a),this.applySeriesColors(e.seriesData.seriesColors,e.globals.colors);const t=e.globals.colors.slice();return this.pushExtraColors(e.globals.colors),this.applyColorTypes(["fill","stroke"],t),this.applyDataLabelsColors(t),this.applyRadarPolygonsColors(),this.applyMarkersColors(t),void("highContrast"===a&&e.dom.elWrap.classList.add("apexcharts-high-contrast"))}const r=[...e.config.colors||e.config.fill.colors||[]];e.globals.colors=this.getColors(r),this.applySeriesColors(e.seriesData.seriesColors,e.globals.colors),e.config.theme.monochrome.enabled&&(e.globals.colors=this.getMonochromeColors(e.config.theme.monochrome,e.seriesData.series,i));const n=e.globals.colors.slice();this.pushExtraColors(e.globals.colors),this.applyColorTypes(["fill","stroke"],n),this.applyDataLabelsColors(n),this.applyRadarPolygonsColors(),this.applyMarkersColors(n)}_applyModeDefaults(){const t=this.w,e=t.config.theme.mode;"dark"===e?(t.config.chart.foreColor===We&&(t.config.chart.foreColor=He),"palette1"===t.config.theme.palette&&(t.config.theme.palette="palette4"),t.config.tooltip&&"light"!==t.config.tooltip.theme&&(t.config.tooltip.theme="dark")):"light"===e&&(t.config.chart.foreColor===He&&(t.config.chart.foreColor=We),"palette4"===t.config.theme.palette&&(t.config.theme.palette="palette1"))}_applyNamedThemeMode(){const t=this._namedTheme;if(!t)return;const e=this.w.config.theme;t.mode&&!e.mode&&(e.mode=t.mode),!t.accessibility||!t.accessibility.colorBlindMode||e.accessibility&&e.accessibility.colorBlindMode||(e.accessibility=e.accessibility||{},e.accessibility.colorBlindMode=t.accessibility.colorBlindMode),t.monochrome&&t.monochrome.enabled&&!e.monochrome.enabled&&(e.monochrome=o(o({},e.monochrome),t.monochrome))}_resolveTokens(){const t=this._namedTheme&&this._namedTheme.tokens||{},e=this._shouldUseTokens()?function(t){if(!d.isBrowser())return{};const e=t.dom&&(t.dom.elWrap||t.dom.baseEl)||null;if(!e)return{};const i=b.getComputedStyle(e);if(!i||"function"!=typeof i.getPropertyValue)return{};const s=t=>{const e=i.getPropertyValue(t);return e?String(e).trim():""},a={};for(const t in Ne){const e=s(Ne[t]);e&&(a[t]=e)}const r=[];for(let t=1;t<=24;t++){const e=s(`--apx-series-${t}`);if(!e)break;r.push(e)}return r.length&&(a.series=r),a}(this.w):{};return o(o({},t),e)}_shouldUseTokens(){return!1!==this.w.config.theme.tokens}applyTokenChrome(t){if(!t)return;const e=this.w;if(!t.fore||e.config.chart.foreColor!==We&&e.config.chart.foreColor!==He||(e.config.chart.foreColor=t.fore),t.grid){e.config.grid.borderColor===$e&&(e.config.grid.borderColor=t.grid);const i=e=>{e&&(e.axisBorder&&e.axisBorder.color===$e&&(e.axisBorder.color=t.grid),e.axisTicks&&e.axisTicks.color===$e&&(e.axisTicks.color=t.grid))};i(e.config.xaxis),Array.isArray(e.config.yaxis)?e.config.yaxis.forEach(i):i(e.config.yaxis)}const i=e.globals.tokenSurface,s=e.config.chart.background,a=!s||s===i;if(t.surface){if(a){e.config.chart.background=t.surface,e.globals.tokenSurface=t.surface;const i=e.dom.Paper&&e.dom.Paper.node;i&&i.style&&(i.style.background=t.surface)}}else if(i&&s===i){e.config.chart.background="",e.globals.tokenSurface=void 0;const t=e.dom.Paper&&e.dom.Paper.node;t&&t.style&&(t.style.background="")}}getColors(t){const e=this.w;return t&&0!==t.length?Array.isArray(t)&&t.length>0&&"function"==typeof t[0]?(this.isColorFn=!0,e.config.series.map((i,s)=>{const a=t[s]||t[0];return"function"==typeof a?a({value:e.globals.axisCharts?e.seriesData.series[s][0]||0:e.seriesData.series[s],seriesIndex:s,dataPointIndex:s,w:this.w}):a})):t:this.predefined()}applySeriesColors(t,e){t.forEach((t,i)=>{t&&(e[i]=t)})}getMonochromeColors(t,e,i){const{color:s,shadeIntensity:a,shadeTo:r}=t,n=this.isBarDistributed||this.isHeatmapDistributed?e[0].length*e.length:e.length,o=1/(n/a);let l=0;return Array.from({length:n},()=>{const t="dark"===r?i.shadeColor(-1*l,s):i.shadeColor(l,s);return l+=o,t})}applyColorTypes(t,e){const i=this.w;t.forEach(t=>{i.globals[t].colors=void 0===i.config[t].colors?this.isColorFn?i.config.colors:e:i.config[t].colors.slice(),this.pushExtraColors(i.globals[t].colors)})}applyDataLabelsColors(t){const e=this.w;e.globals.dataLabels.style.colors=void 0===e.config.dataLabels.style.colors?t:e.config.dataLabels.style.colors.slice(),this.pushExtraColors(e.globals.dataLabels.style.colors,50)}applyRadarPolygonsColors(){const t=this.w;t.globals.radarPolygons.fill.colors=void 0===t.config.plotOptions.radar.polygons.fill.colors?["dark"===t.config.theme.mode?"#343A3F":"none"]:t.config.plotOptions.radar.polygons.fill.colors.slice(),this.pushExtraColors(t.globals.radarPolygons.fill.colors,20)}applyMarkersColors(t){const e=this.w;e.globals.markers.colors=void 0===e.config.markers.colors?t:e.config.markers.colors.slice(),this.pushExtraColors(e.globals.markers.colors)}pushExtraColors(t,e,i=null){const s=this.w;let a=e||s.seriesData.series.length;if(null===i&&(i=this.isBarDistributed||this.isHeatmapDistributed||"heatmap"===s.config.chart.type&&s.config.plotOptions.heatmap&&s.config.plotOptions.heatmap.colorScale.inverse),i&&s.seriesData.series.length&&(a=s.seriesData.series[s.globals.maxValsInArrayIndex].length*s.seriesData.series.length),t.lengtht.globals.svgWidth&&(this.dCtx.lgRect.width=t.globals.svgWidth/1.5),this.dCtx.lgRect}getDatalabelsRect(){const t=this.w,e=[];t.config.series.forEach((i,s)=>{i.data.forEach((i,a)=>{const r=(n=t.seriesData.series[s][a],t.config.dataLabels.formatter(n,{seriesIndex:s,dataPointIndex:a,w:t}));var n;e.push(r)})});const i=v.getLargestStringFromArr(e),s=new Dt(this.w),a=t.config.dataLabels.style,r=s.getTextRects(i,parseInt(a.fontSize).toString(),a.fontFamily);return{width:1.05*r.width,height:r.height}}getLargestStringFromMultiArr(t,e){let i=t;if(this.w.axisFlags.isMultiLineX){const t=e.map(t=>Array.isArray(t)?t.length:1),s=Math.max(...t);i=e[t.indexOf(s)]}return i}getSparklineStrokeInset(){const t=this.w,e=Array.isArray(t.config.stroke.width)?Math.max(...t.config.stroke.width):t.config.stroke.width,i=e/2;if(!(t.config.stroke.show&&i>0))return{top:0,bottom:0};const s=t.globals.maxY-t.globals.minY,a=this._getSeriesYExtremes();if(!(this._strokeTracesDataPoints()&&s>0&&a))return{top:i,bottom:i};const r=Math.max(t.globals.svgHeight-e,0),n=r*(t.globals.maxY-a.max)/s,o=r*(a.min-t.globals.minY)/s;return{top:Math.min(Math.max(i-n,0),i),bottom:Math.min(Math.max(i-o,0),i)}}_strokeTracesDataPoints(){const t=this.w;if(!t.globals.axisCharts||t.config.chart.stacked)return!1;const e=["line","area","scatter"];return t.config.series.every(i=>e.includes(i.type||t.config.chart.type))}_getSeriesYExtremes(){let t=1/0,e=-1/0;return this.w.seriesData.series.forEach(i=>{Array.isArray(i)&&i.forEach(i=>{Number.isFinite(i)&&(ie&&(e=i))})}),t===1/0?null:{min:t,max:e}}};class Ue{constructor(t){this.w=t.w,this.dCtx=t}getxAxisLabelsCoords(){const t=this.w;let e,i=t.labelData.labels.slice();if(t.config.xaxis.convertedCatToNumeric&&0===i.length&&(i=t.labelData.categoryLabels),t.labelData.timescaleLabels.length>0){const i=this.getxAxisTimeScaleLabelsCoords();e={width:i.width,height:i.height},t.layout.rotateXLabels=!1}else{this.dCtx.lgWidthForSideLegends="left"!==t.config.legend.position&&"right"!==t.config.legend.position||t.config.legend.floating?0:this.dCtx.lgRect.width;const s=t.formatters.xLabelFormatter;let a=v.getLargestStringFromArr(i),r=this.dCtx.dimHelpers.getLargestStringFromMultiArr(a,i);t.globals.isBarHorizontal&&(a=t.globals.yAxisScale[0].result.reduce((t,e)=>t.length>e.length?t:e,0),r=a);const n=new S(this.w),o=a;a=n.xLabelFormat(s,a,o,{i:void 0,dateFormatter:new A(this.w).formatDate,w:t}),r=n.xLabelFormat(s,r,o,{i:void 0,dateFormatter:new A(this.w).formatDate,w:t}),(t.config.xaxis.convertedCatToNumeric&&void 0===a||""===String(a).trim())&&(a="1",r=a);const l=new Dt(this.w);let h=l.getTextRects(a,t.config.xaxis.labels.style.fontSize),c=h;if(a!==r&&(c=l.getTextRects(r,t.config.xaxis.labels.style.fontSize)),e={width:h.width>=c.width?h.width:c.width,height:h.height>=c.height?h.height:c.height},e.width*i.length>t.globals.svgWidth-this.dCtx.lgWidthForSideLegends-this.dCtx.yAxisWidth-this.dCtx.gridPad.left-this.dCtx.gridPad.right&&0!==t.config.xaxis.labels.rotate||t.config.xaxis.labels.rotateAlways){if(!t.globals.isBarHorizontal){t.layout.rotateXLabels=!0;const i=e=>l.getTextRects(e,t.config.xaxis.labels.style.fontSize,t.config.xaxis.labels.style.fontFamily,`rotate(${t.config.xaxis.labels.rotate} 0 0)`,!1);h=i(a),a!==r&&(c=i(r)),e.height=(h.height>c.height?h.height:c.height)/1.5,e.width=h.width>c.width?h.width:c.width}}else t.layout.rotateXLabels=!1}return t.config.xaxis.labels.show||(e={width:0,height:0}),{width:e.width,height:e.height}}getxAxisGroupLabelsCoords(){var t;const e=this.w;if(!e.labelData.hasXaxisGroups)return{width:0,height:0};const i=(null==(t=e.config.xaxis.group.style)?void 0:t.fontSize)||e.config.xaxis.labels.style.fontSize,s=e.labelData.groups.map(t=>t.title);let a;const r=v.getLargestStringFromArr(s),n=this.dCtx.dimHelpers.getLargestStringFromMultiArr(r,s),o=new Dt(this.w),l=o.getTextRects(r,i);let h=l;return r!==n&&(h=o.getTextRects(n,i)),a={width:l.width>=h.width?l.width:h.width,height:l.height>=h.height?l.height:h.height},e.config.xaxis.labels.show||(a={width:0,height:0}),{width:a.width,height:a.height}}getxAxisTitleCoords(){const t=this.w;let e=0,i=0;if(void 0!==t.config.xaxis.title.text){const s=new Dt(this.w).getTextRects(t.config.xaxis.title.text,t.config.xaxis.title.style.fontSize);e=s.width,i=s.height}return{width:e,height:i}}getxAxisTimeScaleLabelsCoords(){const t=this.w;this.dCtx.timescaleLabels=t.labelData.timescaleLabels.slice();const e=this.dCtx.timescaleLabels.map(t=>t.value),i=e.reduce((t,e)=>void 0===t?0:t.length>e.length?t:e,0),s=new Dt(this.w).getTextRects(i,t.config.xaxis.labels.style.fontSize);return 1.05*s.width*e.length>t.layout.gridWidth&&0!==t.config.xaxis.labels.rotate&&(t.globals.overlappingXLabels=!0),s}additionalPaddingXLabels(t){const e=this.w,i=e.globals,s=e.config,a=s.xaxis.type,r=t.width;i.skipLastTimelinelabel=!1,i.skipFirstTimelinelabel=!1;const n=e.config.yaxis[0].opposite&&e.globals.isBarHorizontal,o=t=>{if(this.dCtx.timescaleLabels&&this.dCtx.timescaleLabels.length){const a=this.dCtx.timescaleLabels[0],n=this.dCtx.timescaleLabels[this.dCtx.timescaleLabels.length-1].position+r/1.75-this.dCtx.yAxisWidthRight,o=a.position-r/1.75+this.dCtx.yAxisWidthLeft,l="right"===e.config.legend.position&&this.dCtx.lgRect.width>0?this.dCtx.lgRect.width:0;n>i.svgWidth-e.layout.translateX-l&&(i.skipLastTimelinelabel=!0),o<-(t.show&&!t.floating||"bar"!==s.chart.type&&"candlestick"!==s.chart.type&&"rangeBar"!==s.chart.type&&"boxPlot"!==s.chart.type&&"violin"!==s.chart.type?10:r/1.75)&&(i.skipFirstTimelinelabel=!0)}else"datetime"===a?this.dCtx.gridPad.right{s.yaxis.length>1&&(t=>-1!==i.collapsedSeriesIndices.indexOf(t))(e)||o(t)};s.yaxis.forEach((t,e)=>{n?(this.dCtx.gridPad.left{const n={seriesIndex:r,dataPointIndex:-1,w:t},o=t.globals.yAxisScale[r];let l=0;if(!s.isYAxisHidden(r)&&a.labels.show&&void 0!==a.labels.minWidth&&(l=a.labels.minWidth),!s.isYAxisHidden(r)&&a.labels.show&&o.result.length){const s=t.formatters.yLabelFormatters[r],h=o.niceMin===Number.MIN_VALUE?0:o.niceMin;let c=o.result.reduce((t,e)=>{var i,a;return(null==(i=String(s(t,n)))?void 0:i.length)>(null==(a=String(s(e,n)))?void 0:a.length)?t:e},h);c=s(c,n);let d=c;if(void 0!==c&&0!==c.length||(c=o.niceMax),1===String(c).length&&(c+=".0",d=c),t.globals.isBarHorizontal){i=0;const e=t.labelData.labels.slice();c=v.getLargestStringFromArr(e),c=s(c,{seriesIndex:r,dataPointIndex:-1,w:t}),d=this.dCtx.dimHelpers.getLargestStringFromMultiArr(c,e)}const p=new Dt(this.w),u="rotate(".concat(a.labels.rotate," 0 0)"),g=p.getTextRects(c,a.labels.style.fontSize,a.labels.style.fontFamily,u,!1);let f=g;c!==d&&(f=p.getTextRects(d,a.labels.style.fontSize,a.labels.style.fontFamily,u,!1)),e.push({width:(l>f.width||l>g.width?l:f.width>g.width?f.width:g.width)+i,height:f.height>g.height?f.height:g.height})}else e.push({width:0,height:0})}),e}getyAxisTitleCoords(){const t=this.w,e=[];return t.config.yaxis.map(t=>{if(t.show&&void 0!==t.title.text){const i=new Dt(this.w),s="rotate(".concat(t.title.rotate," 0 0)"),a=i.getTextRects(t.title.text,t.title.style.fontSize,t.title.style.fontFamily,s,!1);e.push({width:a.width,height:a.height})}else e.push({width:0,height:0})}),e}getTotalYAxisWidth(){const t=this.w;let e=0,i=0,s=0;const a=t.globals.yAxisScale.length>1?10:0,r=new Bt(this.w,{theme:this.dCtx.theme,timeScale:this.dCtx.timeScale}),n=(n,o)=>{const l=t.config.yaxis[o].floating;let h=0;n.width>0&&!l?(h=n.width+a,function(e){return t.globals.ignoreYAxisIndexes.indexOf(e)>-1}(o)&&(h=h-n.width-a)):h=l||r.isYAxisHidden(o)?0:5,t.config.yaxis[o].opposite?s+=h:i+=h,e+=h};return t.layout.yLabelsCoords.map((t,e)=>{n(t,e)}),t.layout.yTitleCoords.map((t,e)=>{n(t,e)}),t.globals.isBarHorizontal&&!t.config.yaxis[0].floating&&(e=t.layout.yLabelsCoords[0].width+t.layout.yTitleCoords[0].width+15),this.dCtx.yAxisWidthLeft=i,this.dCtx.yAxisWidthRight=s,e}}class Ze{constructor(t){this.w=t.w,this.dCtx=t}gridPadForColumnsInNumericAxis(t){const{w:e}=this,{config:i,globals:s}=e;if(s.noData||s.collapsedSeries.length+s.ancillaryCollapsedSeries.length===i.series.length)return 0;const a=t=>["bar","rangeBar","candlestick","boxPlot","violin"].includes(t),r=i.chart.type;let n=0,o=a(r)?i.series.length:1;s.comboBarCount>0&&(o=s.comboBarCount),s.collapsedSeries.forEach(t=>{a(t.type)&&(o-=1)}),i.chart.stacked&&(o=1);const l=a(r)||s.comboBarCount>0;let h=Math.abs(s.initialMaxX-s.initialMinX);if(l&&e.axisFlags.isXNumeric&&!s.isBarHorizontal&&o>0&&0!==h){h<=3&&(h=s.dataPoints);const e=h/t;let a=s.minXDiff&&s.minXDiff/e>0?s.minXDiff/e:0;a>t/2&&(a/=2),n=a*parseInt(i.plotOptions.bar.columnWidth,10)/100,n<1&&(n=1),s.barPadForNumericAxis=n}return n}gridPadForStackedTotalDataLabels(){const{w:t}=this,e=t.config.plotOptions.bar.dataLabels.total;if(!t.globals.isBarHorizontal||!t.config.chart.stacked||"100%"!==t.config.chart.stackType||!e.enabled)return;const i=t.seriesData.stackedSeriesTotals||[];if(!i.length)return;const s=e.formatter||t.config.dataLabels.formatter,a=i.map((e,i)=>String(s?s(e,l(o({},t),{seriesIndex:0,dataPointIndex:i,w:t})):e)),r=new Dt(t).getTextRects(v.getLargestStringFromArr(a),parseFloat(e.style.fontSize).toString(),e.style.fontFamily).width+Math.abs(e.offsetX||0)+2;this.dCtx.xPadRight=Math.max(this.dCtx.xPadRight,r)}gridPadFortitleSubtitle(){const{w:t}=this,{globals:e}=t;let i=this.dCtx.isSparkline||!e.axisCharts?0:10;["title","subtitle"].forEach(s=>{void 0!==t.config[s].text?i+=t.config[s].margin:i+=this.dCtx.isSparkline||!e.axisCharts?0:5}),!t.config.legend.show||"bottom"!==t.config.legend.position||t.config.legend.floating||e.axisCharts||(i+=10);const s=this.dCtx.dimHelpers.getTitleSubtitleCoords("title"),a=this.dCtx.dimHelpers.getTitleSubtitleCoords("subtitle");this.dCtx.titleBlockPad=i,t.layout.gridHeight-=s.height+a.height+i,t.layout.translateY+=s.height+a.height+i}setGridXPosForDualYAxis(t,e){const{w:i}=this,s=new Bt(this.w,{theme:this.dCtx.theme,timeScale:this.dCtx.timeScale});i.config.yaxis.forEach((a,r)=>{-1!==i.globals.ignoreYAxisIndexes.indexOf(r)||a.floating||s.isYAxisHidden(r)||(a.opposite&&(i.layout.translateX-=e[r].width+t[r].width+parseInt(a.labels.style.fontSize,10)/1.2+12),i.layout.translateX<2&&(i.layout.translateX=2))})}}const Ke="http://www.w3.org/1999/xhtml";function Je(t,e){const i=t.config.drilldown&&t.config.drilldown.breadcrumb||{};return o(o({show:!0,position:"top-left",separator:" / ",rootLabel:"All",offsetX:0,offsetY:0,formatter:void 0},i),e||{})}function Qe(t,e){const i=[".apexcharts-title-text",".apexcharts-subtitle-text"].map(e=>t.dom.baseEl.querySelector(e)).filter(t=>null!==t);if(!i.length)return;const s=t.dom.elWrap.getBoundingClientRect().top;for(let t=0;t{const i=e.getBoundingClientRect();return t.lefti.left&&t.topi.top});if(!a)break;e.style.top=a.getBoundingClientRect().bottom-s+4+"px"}}function ti(t,e,i,s){var a;const r=null==(a=null==e?void 0:e.dimensions)?void 0:a.dimHelpers,n=r?r.getTitleSubtitleCoords("title").height+r.getTitleSubtitleCoords("subtitle").height:0,o=i.getBoundingClientRect().height||18,l=s&&s.offsetY||0,h=function(t,e){const i=t.layout.translateY||0,s=t.dom.elWrap;if(!s)return i;const a=t.dom.baseEl.querySelectorAll(".apexcharts-yaxis-label");if(!a.length)return i;const r=s.getBoundingClientRect().top,n=e.getBoundingClientRect();let o=i;for(let t=0;t=n.right||e.right<=n.left||(o=Math.min(o,e.top-r)))}return o}(t,i);if(h-n>=o+1)return i.style.top=`${h-o-1+l}px`,!0;i.style.top=`${n+l}px`;const c="dark"===t.config.theme.mode;return i.style.background=c?"rgba(20,24,30,0.82)":"rgba(255,255,255,0.86)",i.style.borderRadius="4px",!1}function ei(t){const e=t.dom.elWrap;if(!e)return;const i=e.querySelector(".apexcharts-breadcrumb");i&&i.parentNode&&i.parentNode.removeChild(i)}class ii{constructor(t,e){this.w=t,this.ctx=e,this.theme=e.theme,this.timeScale=e.timeScale,this.lgRect={},this.yAxisWidth=0,this.yAxisWidthLeft=0,this.yAxisWidthRight=0,this.xAxisHeight=0,this.isSparkline=this.w.config.chart.sparkline.enabled,this.dimHelpers=new Ve(this),this.dimYAxis=new qe(this),this.dimXAxis=new Ue(this),this.dimGrid=new Ze(this),this.lgWidthForSideLegends=0,this.gridPad=o({},this.w.config.grid.padding),this.xPadRight=0,this.titleBlockPad=0,this.xPadLeft=0,this.datalabelsCoords={width:0,height:0},this.xAxisWidth=0,this.timescaleLabels=[]}plotCoords(){const t=this.w,e=t.globals;if(this.gridPad=o({},t.config.grid.padding),this.lgRect=this.dimHelpers.getLegendsRect(),this.datalabelsCoords={width:0,height:0},this.isSparkline){this.w.globals.markers.largestSize>0&&Object.entries(this.gridPad).forEach(([t,e])=>{this.gridPad[t]=Math.max(e,this.w.globals.markers.largestSize/1.5)});const t=this.dimHelpers.getSparklineStrokeInset();this.gridPad.top=Math.max(t.top,this.gridPad.top),this.gridPad.bottom=Math.max(t.bottom,this.gridPad.bottom)}if(e.axisCharts?this.setDimensionsForAxisCharts():this.setDimensionsForNonAxisCharts(),this.dimGrid.gridPadFortitleSubtitle(),this.gridPadForBreadcrumb(),this.dimGrid.gridPadForStackedTotalDataLabels(),"heatmap"===t.config.chart.type&&"hexagon"===t.config.plotOptions.heatmap.shape&&("numeric"!==t.config.xaxis.type&&"datetime"!==t.config.xaxis.type||!t.axisFlags.isXNumeric)){const i=e.dataPoints||1,s=(t.seriesData.series||[]).length||1,a=t.layout.gridWidth-this.xPadRight-this.xPadLeft,r=t.layout.gridHeight,n=t.config.stroke.show?Array.isArray(t.config.stroke.width)?Math.max(...t.config.stroke.width):t.config.stroke.width:0,o=(a+4*i*(n/2+6))/(4*i+2),l=(r+6*s*(n/2))/(6*s+2);this.gridPad.left=Math.max(o,this.gridPad.left),this.gridPad.right=Math.max(o,this.gridPad.right),this.gridPad.top=Math.max(l,this.gridPad.top),this.gridPad.bottom=Math.max(l,this.gridPad.bottom)}t.layout.gridHeight=t.layout.gridHeight-this.gridPad.top-this.gridPad.bottom,t.layout.gridWidth=t.layout.gridWidth-this.gridPad.left-this.gridPad.right-this.xPadRight-this.xPadLeft;const i=this.dimGrid.gridPadForColumnsInNumericAxis(t.layout.gridWidth);return t.layout.gridWidth=t.layout.gridWidth-2*i,t.layout.translateX=t.layout.translateX+this.gridPad.left+this.xPadLeft+(i>0?i:0),t.layout.translateY=t.layout.translateY+this.gridPad.top,{layout:{gridHeight:t.layout.gridHeight,gridWidth:t.layout.gridWidth,translateX:t.layout.translateX,translateY:t.layout.translateY,translateXAxisX:t.layout.translateXAxisX,translateXAxisY:t.layout.translateXAxisY,rotateXLabels:t.layout.rotateXLabels,xAxisHeight:t.layout.xAxisHeight,xAxisLabelsHeight:t.layout.xAxisLabelsHeight,xAxisGroupLabelsHeight:t.layout.xAxisGroupLabelsHeight,xAxisLabelsWidth:t.layout.xAxisLabelsWidth,yLabelsCoords:t.layout.yLabelsCoords,yTitleCoords:t.layout.yTitleCoords,gridPad:o({},this.gridPad)}}}gridPadForBreadcrumb(){var t,e,i,s,a,r;const n=this.w,o="treemap"===n.config.chart.type;if(o){const i=null==(e=null==(t=n.config.plotOptions)?void 0:t.treemap)?void 0:e.zoom;if(i&&i.enabled){if(!1===Je(n,i.breadcrumb).show)return;return void(this.gridPad.top+=22)}}if(!n.globals.axisCharts)return;if(!this.ctx.drilldown)return;if(!n.config.drilldown||!n.config.drilldown.enabled)return;if(!1===Je(n).show)return;const l=parseFloat(String(null==(r=null==(a=null==(s=null==(i=n.config.yaxis)?void 0:i[0])?void 0:s.labels)?void 0:a.style)?void 0:r.fontSize))||11,h=24+(o?0:Math.ceil(l*B/2)),c=o?0:this.titleBlockPad||0;this.gridPad.top+=Math.max(0,h-c)}setDimensionsForAxisCharts(){const t=this.w,e=t.globals,i=this.dimYAxis.getyAxisLabelsCoords(),s=this.dimYAxis.getyAxisTitleCoords();e.isSlopeChart&&(this.datalabelsCoords=this.dimHelpers.getDatalabelsRect()),t.layout.yLabelsCoords=[],t.layout.yTitleCoords=[],t.config.yaxis.map((e,a)=>{t.layout.yLabelsCoords.push({width:i[a].width,index:a}),t.layout.yTitleCoords.push({width:s[a].width,index:a})}),this.yAxisWidth=this.dimYAxis.getTotalYAxisWidth();const a=this.dimXAxis.getxAxisLabelsCoords(),r=this.dimXAxis.getxAxisGroupLabelsCoords(),n=this.dimXAxis.getxAxisTitleCoords();this.conditionalChecksForAxisCoords(a,n,r),t.layout.translateXAxisY=t.layout.rotateXLabels?this.xAxisHeight/8:-4,t.layout.translateXAxisX=t.layout.rotateXLabels&&t.axisFlags.isXNumeric&&t.config.xaxis.labels.rotate<=-45?-this.xAxisWidth/4:0,t.globals.isBarHorizontal&&(t.layout.rotateXLabels=!1,t.layout.translateXAxisY=(parseInt(t.config.xaxis.labels.style.fontSize,10)||12)/1.5*-1),t.layout.translateXAxisY=t.layout.translateXAxisY+t.config.xaxis.labels.offsetY,t.layout.translateXAxisX=t.layout.translateXAxisX+t.config.xaxis.labels.offsetX;let o=this.yAxisWidth,l=this.xAxisHeight;t.layout.xAxisLabelsHeight=this.xAxisHeight-n.height,t.layout.xAxisGroupLabelsHeight=t.layout.xAxisLabelsHeight-a.height,t.layout.xAxisLabelsWidth=this.xAxisWidth,t.layout.xAxisHeight=this.xAxisHeight;let h=10;("radar"===t.config.chart.type||this.isSparkline)&&(o=0,l=0),this.isSparkline&&(this.lgRect={height:0,width:0}),(this.isSparkline||"treemap"===t.config.chart.type)&&(o=0,l=0,h=0),this.isSparkline||"treemap"===t.config.chart.type||this.dimXAxis.additionalPaddingXLabels(a);const c=()=>{t.layout.translateX=o+this.datalabelsCoords.width,t.layout.gridHeight=e.svgHeight-this.lgRect.height-l-(this.isSparkline||"treemap"===t.config.chart.type?0:t.layout.rotateXLabels?10:15),t.layout.gridWidth=e.svgWidth-o-2*this.datalabelsCoords.width};switch("top"===t.config.xaxis.position&&(h=t.layout.xAxisHeight-t.config.xaxis.axisTicks.height-5),t.config.legend.position){case"bottom":t.layout.translateY=h,c();break;case"top":t.layout.translateY=this.lgRect.height+h,c();break;case"left":t.layout.translateY=h,t.layout.translateX=this.lgRect.width+o+this.datalabelsCoords.width,t.layout.gridHeight=e.svgHeight-l-12,t.layout.gridWidth=e.svgWidth-this.lgRect.width-o-2*this.datalabelsCoords.width;break;case"right":t.layout.translateY=h,t.layout.translateX=o+this.datalabelsCoords.width,t.layout.gridHeight=e.svgHeight-l-12,t.layout.gridWidth=e.svgWidth-this.lgRect.width-o-2*this.datalabelsCoords.width-5;break;default:throw new Error("Legend position not supported")}this.dimGrid.setGridXPosForDualYAxis(s,i);new $t(this.w,{theme:this.theme,timeScale:this.timeScale}).setYAxisXPosition(i,s)}setDimensionsForNonAxisCharts(){const t=this.w,e=t.globals,i=t.config;let s=0;if(t.config.legend.show&&!t.config.legend.floating&&(s=20),"unit"===i.chart.type){const a=i.legend.show&&!i.legend.floating,r=i.legend.position;let n=0,o=0;return a&&("bottom"===r||"top"===r?n=this.lgRect.height:o=this.lgRect.width+s),t.layout.gridWidth=e.svgWidth-o,t.layout.gridHeight=e.svgHeight-n,t.layout.translateX="left"===r?o:0,void(t.layout.translateY="top"===r?n:0)}const a="sunburst"===i.chart.type?"sunburst":"pie"===i.chart.type||"polarArea"===i.chart.type||"donut"===i.chart.type?"pie":"radialBar",r=i.plotOptions[a].offsetY,n=i.plotOptions[a].offsetX;if(!i.legend.show||i.legend.floating){t.layout.gridHeight=e.svgHeight;const i=t.dom.elWrap.getBoundingClientRect().width;return t.layout.gridWidth=Math.min(i,t.layout.gridHeight),t.layout.translateY=r,void(t.layout.translateX=n+(e.svgWidth-t.layout.gridWidth)/2)}switch(i.legend.position){case"bottom":t.layout.gridHeight=e.svgHeight-this.lgRect.height,t.layout.gridWidth=e.svgWidth,t.layout.translateY=r-10,t.layout.translateX=n+(e.svgWidth-t.layout.gridWidth)/2;break;case"top":t.layout.gridHeight=e.svgHeight-this.lgRect.height,t.layout.gridWidth=e.svgWidth,t.layout.translateY=this.lgRect.height+r+10,t.layout.translateX=n+(e.svgWidth-t.layout.gridWidth)/2;break;case"left":t.layout.gridWidth=e.svgWidth-this.lgRect.width-s,t.layout.gridHeight="auto"!==i.chart.height?e.svgHeight:t.layout.gridWidth,t.layout.translateY=r,t.layout.translateX=n+this.lgRect.width+s;break;case"right":t.layout.gridWidth=e.svgWidth-this.lgRect.width-s-5,t.layout.gridHeight="auto"!==i.chart.height?e.svgHeight:t.layout.gridWidth,t.layout.translateY=r,t.layout.translateX=n+10;break;default:throw new Error("Legend position not supported")}}conditionalChecksForAxisCoords(t,e,i){const s=this.w,a=s.labelData.hasXaxisGroups?2:1,r=i.height+t.height+e.height,n=s.axisFlags.isMultiLineX?1.2:B,o=s.layout.rotateXLabels?22:10,l=s.layout.rotateXLabels&&"bottom"===s.config.legend.position?10:0;this.xAxisHeight=r*n+a*o+l,this.xAxisWidth=t.width,this.xAxisHeight-e.height>s.config.xaxis.labels.maxHeight&&(this.xAxisHeight=s.config.xaxis.labels.maxHeight),s.config.xaxis.labels.minHeight&&this.xAxisHeight{h+=t.labels.minWidth,c+=t.labels.maxWidth}),this.yAxisWidthc&&(this.yAxisWidth=c)}}const si=1e3,ai=6e4,ri=36e5,ni=24*ri,oi=7*ni,li=30*ni,hi=365*ni,ci=10/86400,di=[{unit:"second",step:1,approxMs:si},{unit:"second",step:5,approxMs:5e3},{unit:"second",step:15,approxMs:15e3},{unit:"second",step:30,approxMs:3e4},{unit:"minute",step:1,approxMs:ai},{unit:"minute",step:5,approxMs:3e5},{unit:"minute",step:15,approxMs:9e5},{unit:"minute",step:30,approxMs:18e5},{unit:"hour",step:1,approxMs:ri},{unit:"hour",step:3,approxMs:3*ri},{unit:"hour",step:6,approxMs:6*ri},{unit:"hour",step:12,approxMs:12*ri},{unit:"day",step:1,approxMs:ni},{unit:"day",step:2,approxMs:2*ni},{unit:"week",step:1,approxMs:oi},{unit:"week",step:2,approxMs:2*oi},{unit:"month",step:1,approxMs:li},{unit:"month",step:3,approxMs:7776e6},{unit:"month",step:6,approxMs:15552e6},{unit:"year",step:1,approxMs:hi},{unit:"year",step:2,approxMs:63072e6},{unit:"year",step:5,approxMs:15768e7},{unit:"year",step:10,approxMs:31536e7},{unit:"year",step:25,approxMs:7884e8},{unit:"year",step:50,approxMs:15768e8},{unit:"year",step:100,approxMs:31536e8}];class pi{constructor(t,e){this.w=t,this.ctx=e,this.tickInterval=null,this.timeScaleArray=[],this.utc=t.config.xaxis.labels.datetimeUTC}calculateTimeScaleTicks(t,e){const i=this.w;if(i.globals.allSeriesCollapsed)return i.labelData.labels=[],i.labelData.timescaleLabels=[],this.timeScaleArray=[],[];const s=e-t,a=s/ni;i.interact.disableZoomIn=!1,i.interact.disableZoomOut=!1,a5e4&&(i.interact.disableZoomOut=!0);const r=Number.isFinite(i.config.xaxis.tickAmount)?i.config.xaxis.tickAmount:10;this.tickInterval=function(t,e){(!Number.isFinite(e)||e<=0)&&(e=10);if(t<=0)return di[0];const i=t/e;let s=di[0],a=1/0;for(const t of di){const e=Math.abs(Math.log(t.approxMs/i));e0?(h-t)/o*n:0;l.push({timestamp:h,position:s,unit:i.unit,year:e.year,month:e.month+1,day:e.date,hour:e.hour,minute:e.minute,second:e.second,value:h}),h=a.addInterval(h,i.unit,i.step,r),c++}return l}recalcDimensionsBasedOnFormat(t){const e=this.w,i=this.formatDates(t),s=this.removeOverlappingTS(i);e.labelData.timescaleLabels=s.slice();const a=new ii(this.w,this.ctx).plotCoords();this.ctx._writeLayoutCoords(a.layout)}formatDates(t){const e=this.w,i=new A(e),s=e.config.xaxis.labels.format,a=e.config.xaxis.labels.datetimeFormatter,r=this.utc,n=(t,e=2)=>String(t).padStart(e,"0"),o=s||this._effectiveFormat(t,a);return t.map(t=>{const e=i.getDate(t.timestamp),s=i.formatDate(e,o);return{dateString:`${t.year}-${n(t.month)}-${n(t.day)}T${n(t.hour)}:${n(t.minute)}:${n(t.second)}.000${r?"Z":""}`,position:t.position,value:s,unit:t.unit,year:t.year,month:t.month}})}_effectiveFormat(t,e){if(0===t.length)return e.day||"dd MMM";const i=this.tickInterval&&this.tickInterval.unit||t[0].unit,s=e["week"===i?"day":i]||e.day||"dd MMM",a=t[0],r=t[t.length-1],n=a.year!==r.year,o=n||a.month!==r.month||a.day!==r.day,l=/y/i.test(s),h=/M/.test(s),c=/d/i.test(s);if("month"===i||"week"===i)return n&&!l?s+" yyyy":s;if("day"===i)return n&&!l?s+" yyyy":s;if("hour"===i||"minute"===i||"second"===i){if(o&&!c&&!h){return(n?"dd MMM yyyy":"dd MMM")+" "+s}return s}return s}removeOverlappingTS(t){if(0===t.length)return[];const e=this.w,i=new Dt(e);let s,a=!1;t[0].value&&t.every(e=>e.value.length===t[0].value.length)&&(a=!0,s=i.getTextRects(t[0].value,e.config.xaxis.labels.style.fontSize).width);let r=0;return t.map((n,o)=>{if(0===o)return n;if(!e.config.xaxis.labels.hideOverlappingLabels)return n;const l=a?s:i.getTextRects(t[r].value,e.config.xaxis.labels.style.fontSize).width,h=t[r].position;return n.position>h+l+10?(r=o,n):null}).filter(t=>null!==t)}}const ui="__apexcharts_registry__",gi="__apexcharts_custom_types__";function fi(){return globalThis[ui]}function xi(){return globalThis[gi]}function mi(t){return xi().has(t)}function bi(t){Object.assign(fi(),t)}function yi(t){const e=fi()[t];if(!e)throw new Error(`ApexCharts: chart type "${t}" is not registered. Bundler: import 'apexcharts/${t}'. Script tag: add +@endPushOnce diff --git a/src/Foundation/resources/components/assets/cloudflare-turnstile.blade.php b/src/Foundation/resources/components/assets/cloudflare-turnstile.blade.php new file mode 100644 index 0000000..34dfa9e --- /dev/null +++ b/src/Foundation/resources/components/assets/cloudflare-turnstile.blade.php @@ -0,0 +1,7 @@ +@pushOnce('meta', 'cloudflare-turnstile-meta') + +@endPushOnce + +@pushOnce('plugins-scripts', 'cloudflare-turnstile-scripts') + +@endPushOnce diff --git a/src/Foundation/resources/components/assets/coloris.blade.php b/src/Foundation/resources/components/assets/coloris.blade.php new file mode 100644 index 0000000..5755b37 --- /dev/null +++ b/src/Foundation/resources/components/assets/coloris.blade.php @@ -0,0 +1,7 @@ +@pushOnce('plugins-styles', 'coloris-styles') + +@endPushOnce + +@pushOnce('plugins-scripts', 'coloris-scripts') + +@endPushOnce diff --git a/src/Foundation/resources/components/assets/hugerte.blade.php b/src/Foundation/resources/components/assets/hugerte.blade.php new file mode 100644 index 0000000..523d341 --- /dev/null +++ b/src/Foundation/resources/components/assets/hugerte.blade.php @@ -0,0 +1,3 @@ +@pushOnce('plugins-scripts', 'hugerte-scripts') + +@endPushOnce diff --git a/src/Foundation/resources/components/assets/query-builder.blade.php b/src/Foundation/resources/components/assets/query-builder.blade.php new file mode 100644 index 0000000..92766b5 --- /dev/null +++ b/src/Foundation/resources/components/assets/query-builder.blade.php @@ -0,0 +1,11 @@ + + + +@pushOnce('plugins-styles', 'query-builder-styles') + +@endPushOnce + +@pushOnce('plugins-scripts', 'query-builder-scripts') + + +@endPushOnce diff --git a/src/Foundation/resources/components/assets/redot-icon-picker.blade.php b/src/Foundation/resources/components/assets/redot-icon-picker.blade.php new file mode 100644 index 0000000..2e08bd7 --- /dev/null +++ b/src/Foundation/resources/components/assets/redot-icon-picker.blade.php @@ -0,0 +1,53 @@ +@pushOnce('plugins-scripts', 'icon-picker-scripts') + +@endPushOnce + +@pushOnce('templates', 'icon-picker-template') + +@endPushOnce diff --git a/src/Foundation/resources/components/assets/redot-repeater.blade.php b/src/Foundation/resources/components/assets/redot-repeater.blade.php new file mode 100644 index 0000000..b633a2e --- /dev/null +++ b/src/Foundation/resources/components/assets/redot-repeater.blade.php @@ -0,0 +1,3 @@ +@pushOnce('plugins-scripts', 'repeater-scripts') + +@endPushOnce diff --git a/src/Foundation/resources/components/assets/redot-toasts.blade.php b/src/Foundation/resources/components/assets/redot-toasts.blade.php new file mode 100644 index 0000000..116fe33 --- /dev/null +++ b/src/Foundation/resources/components/assets/redot-toasts.blade.php @@ -0,0 +1,3 @@ +@pushOnce('plugins-scripts', 'redot-toasts-scripts') + +@endPushOnce diff --git a/src/Foundation/resources/components/assets/redot-uploader.blade.php b/src/Foundation/resources/components/assets/redot-uploader.blade.php new file mode 100644 index 0000000..8313105 --- /dev/null +++ b/src/Foundation/resources/components/assets/redot-uploader.blade.php @@ -0,0 +1,3 @@ +@pushOnce('plugins-scripts', 'uploader-scripts') + +@endPushOnce diff --git a/src/Foundation/resources/components/assets/tabler-flags.blade.php b/src/Foundation/resources/components/assets/tabler-flags.blade.php new file mode 100644 index 0000000..caa43c8 --- /dev/null +++ b/src/Foundation/resources/components/assets/tabler-flags.blade.php @@ -0,0 +1,3 @@ +@pushOnce('plugins-styles', 'tabler-flags-styles') + +@endPushOnce diff --git a/src/Foundation/resources/components/assets/tabler-socials.blade.php b/src/Foundation/resources/components/assets/tabler-socials.blade.php new file mode 100644 index 0000000..8d8b01c --- /dev/null +++ b/src/Foundation/resources/components/assets/tabler-socials.blade.php @@ -0,0 +1,3 @@ +@pushOnce('plugins-styles', 'tabler-socials-styles') + +@endPushOnce diff --git a/src/Foundation/resources/components/assets/tempus-dominus.blade.php b/src/Foundation/resources/components/assets/tempus-dominus.blade.php new file mode 100644 index 0000000..7dfc320 --- /dev/null +++ b/src/Foundation/resources/components/assets/tempus-dominus.blade.php @@ -0,0 +1,11 @@ +@pushOnce('plugins-styles', 'tempus-dominus-styles') + +@endPushOnce + +@pushOnce('plugins-scripts', 'popper-scripts') + +@endPushOnce + +@pushOnce('plugins-scripts', 'tempus-dominus-scripts') + +@endPushOnce diff --git a/src/Foundation/resources/components/assets/tom-select.blade.php b/src/Foundation/resources/components/assets/tom-select.blade.php new file mode 100644 index 0000000..6ddde3f --- /dev/null +++ b/src/Foundation/resources/components/assets/tom-select.blade.php @@ -0,0 +1,7 @@ +@pushOnce('plugins-styles', 'tom-select-styles') + +@endPushOnce + +@pushOnce('plugins-scripts', 'tom-select-scripts') + +@endPushOnce diff --git a/src/Foundation/resources/components/attachments.blade.php b/src/Foundation/resources/components/attachments.blade.php new file mode 100644 index 0000000..6eeb25e --- /dev/null +++ b/src/Foundation/resources/components/attachments.blade.php @@ -0,0 +1,43 @@ +@if ($title) + +@endif + +
class(['form-control', 'overflow-hidden', 'rounded-3', 'p-0']) }}> + +
diff --git a/src/Foundation/resources/components/avatar.blade.php b/src/Foundation/resources/components/avatar.blade.php new file mode 100644 index 0000000..45c218b --- /dev/null +++ b/src/Foundation/resources/components/avatar.blade.php @@ -0,0 +1,4 @@ + diff --git a/src/Foundation/resources/components/captcha.blade.php b/src/Foundation/resources/components/captcha.blade.php new file mode 100644 index 0000000..d4c371a --- /dev/null +++ b/src/Foundation/resources/components/captcha.blade.php @@ -0,0 +1,7 @@ + + + +
+ +
+
diff --git a/src/Foundation/resources/components/checkboxes.blade.php b/src/Foundation/resources/components/checkboxes.blade.php new file mode 100644 index 0000000..1f41726 --- /dev/null +++ b/src/Foundation/resources/components/checkboxes.blade.php @@ -0,0 +1,15 @@ + +
only('class') }}> + @foreach ($options as $key => $label) + + @endforeach + + {{ $slot }} +
+
diff --git a/src/Foundation/resources/components/color-picker.blade.php b/src/Foundation/resources/components/color-picker.blade.php new file mode 100644 index 0000000..c233391 --- /dev/null +++ b/src/Foundation/resources/components/color-picker.blade.php @@ -0,0 +1,5 @@ + + + + class(['form-control'])->merge(['init' => 'coloris']) }} /> + diff --git a/src/Foundation/resources/components/date-picker.blade.php b/src/Foundation/resources/components/date-picker.blade.php new file mode 100644 index 0000000..f7494aa --- /dev/null +++ b/src/Foundation/resources/components/date-picker.blade.php @@ -0,0 +1,12 @@ + + + +
+ class(['form-control'])->merge(['init' => 'tempus-dominus']) }} /> + + + + +
+
diff --git a/src/Foundation/resources/components/empty.blade.php b/src/Foundation/resources/components/empty.blade.php new file mode 100644 index 0000000..22ec017 --- /dev/null +++ b/src/Foundation/resources/components/empty.blade.php @@ -0,0 +1,31 @@ +@props([ + 'icon' => 'ti ti-circle-x', + 'title' => __('Nothing to show here'), + 'subtitle' => __('Trust me, I\'ve looked everywhere, there\'s nothing here :('), +]) + +
class(['card']) }}> +
+ @if ($icon) +
+ +
+ @endif + +

+ {{ $title }} +

+ + @if ($subtitle) +

+ {{ $subtitle }} +

+ @endif + + @if (isset($slot) && $slot->isNotEmpty()) +
+ {{ $slot }} +
+ @endif +
+
diff --git a/src/Foundation/resources/components/field.blade.php b/src/Foundation/resources/components/field.blade.php new file mode 100644 index 0000000..1f8e51d --- /dev/null +++ b/src/Foundation/resources/components/field.blade.php @@ -0,0 +1,16 @@ +@props([ + 'id' => null, + 'title' => null, + 'hint' => null, + 'required' => false, +]) + +@if ($title) + +@endif + +{{ $slot }} + +@if ($hint) + {{ $hint }} +@endif diff --git a/src/Foundation/resources/components/file-hint.blade.php b/src/Foundation/resources/components/file-hint.blade.php new file mode 100644 index 0000000..4d0e0b6 --- /dev/null +++ b/src/Foundation/resources/components/file-hint.blade.php @@ -0,0 +1,5 @@ +@if ($file) + + {{ __('Click here to view the current file.') }} + +@endif diff --git a/src/Foundation/resources/components/flag.blade.php b/src/Foundation/resources/components/flag.blade.php new file mode 100644 index 0000000..9643d71 --- /dev/null +++ b/src/Foundation/resources/components/flag.blade.php @@ -0,0 +1,8 @@ +@props([ + 'code' => 'eg', + 'size' => 'md', +]) + + + +class(['flag', "flag-$size", "flag-country-$code"]) }}> diff --git a/src/Foundation/resources/components/form-card.blade.php b/src/Foundation/resources/components/form-card.blade.php new file mode 100644 index 0000000..ca22f41 --- /dev/null +++ b/src/Foundation/resources/components/form-card.blade.php @@ -0,0 +1,27 @@ +class('card') }}> +
isset($header)])> +

{{ $title }}

+ + @isset($header) + {{ $header }} + @endisset +
+ + @if ($slot->isEmpty()) +
+ @include("dashboard.$resource.partials.form", ['entry' => $entry]) +
+ @else + {{ $slot }} + @endif + + +
diff --git a/src/Foundation/resources/components/form.blade.php b/src/Foundation/resources/components/form.blade.php new file mode 100644 index 0000000..9e18e43 --- /dev/null +++ b/src/Foundation/resources/components/form.blade.php @@ -0,0 +1,14 @@ + + @csrf + + {{-- Method spoofing --}} + @if (in_array($method, ['PUT', 'PATCH', 'DELETE'])) + @method($method) + @endif + + {{-- Identifier to know which form is being submitted --}} + + + {{ $slot }} + diff --git a/src/Foundation/resources/components/hint.blade.php b/src/Foundation/resources/components/hint.blade.php new file mode 100644 index 0000000..1773a43 --- /dev/null +++ b/src/Foundation/resources/components/hint.blade.php @@ -0,0 +1,3 @@ +merge(['class' => 'form-hint']) }}> + {{ $slot }} + diff --git a/src/Foundation/resources/components/icon-picker.blade.php b/src/Foundation/resources/components/icon-picker.blade.php new file mode 100644 index 0000000..94dc80a --- /dev/null +++ b/src/Foundation/resources/components/icon-picker.blade.php @@ -0,0 +1,20 @@ + + + +
+
+ + + + + class(['form-control'])->merge(['init' => 'icon-picker']) }} /> +
+ +
+ +
+
+
diff --git a/src/Foundation/resources/components/icon.blade.php b/src/Foundation/resources/components/icon.blade.php new file mode 100644 index 0000000..2e760bc --- /dev/null +++ b/src/Foundation/resources/components/icon.blade.php @@ -0,0 +1,7 @@ +@props(['icon']) + +@if (str_starts_with($icon, '<')) + {!! $icon !!} +@else + +@endif diff --git a/src/Foundation/resources/components/input.blade.php b/src/Foundation/resources/components/input.blade.php new file mode 100644 index 0000000..3ac9d7a --- /dev/null +++ b/src/Foundation/resources/components/input.blade.php @@ -0,0 +1,42 @@ + +
$isInputGroup, + 'input-group-flat' => $isInputGroup && $flat, + ])> + @if ($prepend instanceof \Illuminate\View\ComponentSlot) + {{ $prepend }} + @elseif ($prepend) + {{ $prepend }} + @endif + + class(['form-control']) }} /> + + @if ($isPassword) + + @endif + + @if ($append instanceof \Illuminate\View\ComponentSlot) + {{ $append }} + @elseif ($append) + {{ $append }} + @endif +
+
+ +@if ($isPassword) + @pushOnce('scripts', 'password-toggle-scripts') + + @endPushOnce +@endif diff --git a/src/Foundation/resources/components/label.blade.php b/src/Foundation/resources/components/label.blade.php new file mode 100644 index 0000000..351c8d4 --- /dev/null +++ b/src/Foundation/resources/components/label.blade.php @@ -0,0 +1,10 @@ +@props([ + 'title' => null, + 'for' => null, + 'required' => false, +]) + + diff --git a/src/Foundation/resources/components/page-header.blade.php b/src/Foundation/resources/components/page-header.blade.php new file mode 100644 index 0000000..3e4e9fb --- /dev/null +++ b/src/Foundation/resources/components/page-header.blade.php @@ -0,0 +1,32 @@ +@aware([ + 'title' => __('Dashboard'), +]) + +@props([ + 'title' => null, + 'pretitle' => __('Overview'), + 'create' => null, +]) + +
class(['page-header d-print-none mt-0']) }}> +
+
+
{{ $pretitle }}
+

{{ $title }}

+
+ +
+
+ @if ($create && url_allowed($create)) + + + + {{ __('Create') }} + + @endif + + {{ $slot }} +
+
+
+
diff --git a/src/Foundation/resources/components/pagination.blade.php b/src/Foundation/resources/components/pagination.blade.php new file mode 100644 index 0000000..016db43 --- /dev/null +++ b/src/Foundation/resources/components/pagination.blade.php @@ -0,0 +1,94 @@ + diff --git a/src/Foundation/resources/components/query-builder.blade.php b/src/Foundation/resources/components/query-builder.blade.php new file mode 100644 index 0000000..e2ceeaf --- /dev/null +++ b/src/Foundation/resources/components/query-builder.blade.php @@ -0,0 +1,8 @@ + + + +
+ merge(['init' => 'query-builder']) }} /> +
+
+
diff --git a/src/Foundation/resources/components/radios-colored.blade.php b/src/Foundation/resources/components/radios-colored.blade.php new file mode 100644 index 0000000..be6eee1 --- /dev/null +++ b/src/Foundation/resources/components/radios-colored.blade.php @@ -0,0 +1,15 @@ + +
only('class') }}> + @foreach ($options as $key => $color) + + @endforeach + + {{ $slot }} +
+
diff --git a/src/Foundation/resources/components/radios.blade.php b/src/Foundation/resources/components/radios.blade.php new file mode 100644 index 0000000..769b0e6 --- /dev/null +++ b/src/Foundation/resources/components/radios.blade.php @@ -0,0 +1,15 @@ + +
only('class') }}> + @foreach ($options as $key => $label) + + @endforeach + + {{ $slot }} +
+
diff --git a/src/Foundation/resources/components/rating.blade.php b/src/Foundation/resources/components/rating.blade.php new file mode 100644 index 0000000..0253f88 --- /dev/null +++ b/src/Foundation/resources/components/rating.blade.php @@ -0,0 +1,13 @@ + +
only('class')->class(['rating-field']) }}> + @for ($i = $stars; $i > 0; $i--) + except('class') }} /> + + + @endfor +
+
diff --git a/src/Foundation/resources/components/redot-scripts.blade.php b/src/Foundation/resources/components/redot-scripts.blade.php new file mode 100644 index 0000000..c9ed7f7 --- /dev/null +++ b/src/Foundation/resources/components/redot-scripts.blade.php @@ -0,0 +1,45 @@ +{{-- Core --}} + + + + + +{{-- Plugins --}} + + + + + + + + +{{-- Language Script --}} + + +{{-- Initializers --}} + + +{{-- Runtime --}} + + + + + + +@if (isset($errors) && $errors->any()) + +@endif diff --git a/src/Foundation/resources/components/redot-styles.blade.php b/src/Foundation/resources/components/redot-styles.blade.php new file mode 100644 index 0000000..7e21363 --- /dev/null +++ b/src/Foundation/resources/components/redot-styles.blade.php @@ -0,0 +1,13 @@ +@props(['direction' => null]) + +@php($direction ??= \Redot\Models\Language::current()?->direction ?? 'ltr') + + + + + + +@stack('plugins-styles') + + + diff --git a/src/Foundation/resources/components/repeater-card.blade.php b/src/Foundation/resources/components/repeater-card.blade.php new file mode 100644 index 0000000..d4b3b01 --- /dev/null +++ b/src/Foundation/resources/components/repeater-card.blade.php @@ -0,0 +1,21 @@ +
+
+ + + + +
+ + + +
+
+ +
class(['card-body']) }}> + {{ $slot }} +
+
diff --git a/src/Foundation/resources/components/repeater.blade.php b/src/Foundation/resources/components/repeater.blade.php new file mode 100644 index 0000000..4f45003 --- /dev/null +++ b/src/Foundation/resources/components/repeater.blade.php @@ -0,0 +1,50 @@ + + +@push('templates') + +@endpush + +
+ merge(['init' => 'repeater']) }}> + +
+ @if (isset($wrapper)) + {{ $wrapper }} + @else +
+
+ @if ($title) + + @endif +
+ +
+ + + +
+
+ +
+ @if (isset($empty)) +
attributes->merge(['repeater-empty' => true]) }}> + {{ $empty }} +
+ @else + + @endif +
+ @endif +
+
+ +@if ($hint) + {{ $hint }} +@endif diff --git a/src/Foundation/resources/components/rich-editor.blade.php b/src/Foundation/resources/components/rich-editor.blade.php new file mode 100644 index 0000000..bf9ad32 --- /dev/null +++ b/src/Foundation/resources/components/rich-editor.blade.php @@ -0,0 +1,3 @@ + + +@include('components.textarea') diff --git a/src/Foundation/resources/components/select-remote.blade.php b/src/Foundation/resources/components/select-remote.blade.php new file mode 100644 index 0000000..46bc983 --- /dev/null +++ b/src/Foundation/resources/components/select-remote.blade.php @@ -0,0 +1,11 @@ + + {{ $slot }} + + @if ($create) + + + + + + @endif + diff --git a/src/Foundation/resources/components/select.blade.php b/src/Foundation/resources/components/select.blade.php new file mode 100644 index 0000000..bb1a0e1 --- /dev/null +++ b/src/Foundation/resources/components/select.blade.php @@ -0,0 +1,19 @@ +@if ($tom) + +@endif + + +
+
+ + + {{ $append ?? '' }} +
+
+
diff --git a/src/Foundation/resources/components/social-icon.blade.php b/src/Foundation/resources/components/social-icon.blade.php new file mode 100644 index 0000000..a83fefe --- /dev/null +++ b/src/Foundation/resources/components/social-icon.blade.php @@ -0,0 +1,8 @@ +@props([ + 'social' => 'google', + 'size' => 'md', +]) + + + +class(['social', "social-$size", "social-app-$social"]) }}> diff --git a/src/Foundation/resources/components/status.blade.php b/src/Foundation/resources/components/status.blade.php new file mode 100644 index 0000000..b11164c --- /dev/null +++ b/src/Foundation/resources/components/status.blade.php @@ -0,0 +1,11 @@ + + @if (is_array(session($status))) +
    + @foreach (session($status) as $message) +
  • {{ $message }}
  • + @endforeach +
+ @else + {{ session($status) }} + @endif +
diff --git a/src/Foundation/resources/components/textarea.blade.php b/src/Foundation/resources/components/textarea.blade.php new file mode 100644 index 0000000..f36b406 --- /dev/null +++ b/src/Foundation/resources/components/textarea.blade.php @@ -0,0 +1,3 @@ + + + diff --git a/src/Foundation/resources/components/toasts.blade.php b/src/Foundation/resources/components/toasts.blade.php new file mode 100644 index 0000000..8aa247f --- /dev/null +++ b/src/Foundation/resources/components/toasts.blade.php @@ -0,0 +1,17 @@ + + +@pushOnce('plugins-scripts', 'redot-toasts-init') + +@endPushOnce diff --git a/src/Foundation/resources/components/toggle.blade.php b/src/Foundation/resources/components/toggle.blade.php new file mode 100644 index 0000000..ae87417 --- /dev/null +++ b/src/Foundation/resources/components/toggle.blade.php @@ -0,0 +1,8 @@ + + + diff --git a/src/Foundation/resources/components/translatable-switcher.blade.php b/src/Foundation/resources/components/translatable-switcher.blade.php new file mode 100644 index 0000000..58cc991 --- /dev/null +++ b/src/Foundation/resources/components/translatable-switcher.blade.php @@ -0,0 +1,30 @@ +@props([ + 'id' => uniqid('translatable-'), + 'locales' => array_keys(config('app.locales')), +]) + +
class(['dropdown'])->merge(['translatable-switcher' => true]) }}> + + + +
+ +@pushOnce('scripts') + +@endPushOnce diff --git a/src/Foundation/resources/components/translatable.blade.php b/src/Foundation/resources/components/translatable.blade.php new file mode 100644 index 0000000..77c7a6f --- /dev/null +++ b/src/Foundation/resources/components/translatable.blade.php @@ -0,0 +1,24 @@ +
+
+ @foreach ($localesConfig as $locale => $config) +
+ +
+ @endforeach +
+ + @if (count($locales) > 1) + + @endif +
diff --git a/src/Foundation/resources/components/uploader.blade.php b/src/Foundation/resources/components/uploader.blade.php new file mode 100644 index 0000000..0280988 --- /dev/null +++ b/src/Foundation/resources/components/uploader.blade.php @@ -0,0 +1,28 @@ + + + +
+ + +
+
+
+
+ + +
+
+
diff --git a/src/Foundation/resources/inits/apex-chart.js b/src/Foundation/resources/inits/apex-chart.js new file mode 100644 index 0000000..d115ce1 --- /dev/null +++ b/src/Foundation/resources/inits/apex-chart.js @@ -0,0 +1,45 @@ +/** + * Initialize an ApexCharts chart. + * + * @param {string} selector + * @param {object} options + * @returns {object|null} + * @see https://apexcharts.com/docs/options/ + */ +return (selector, options = {}) => { + const $chart = $(selector); + + if (!window.ApexCharts) { + console.error('ApexCharts is not loaded.'); + return null; + } + + const defaultOptions = { + chart: { + type: 'line', + height: 350, + toolbar: { + show: false, + }, + }, + series: [], + }; + + const selectorOptions = getOptionsFromSelector(selector, 'chart-'); + + for (const key of ['height', 'type', 'width']) { + if (!selectorOptions.hasOwnProperty(key)) continue; + + _.set(selectorOptions, `chart.${key}`, selectorOptions[key]); + delete selectorOptions[key]; + } + + options = _.merge(defaultOptions, selectorOptions, options); + + const chart = new ApexCharts($chart.get(0), options); + + chart.render(); + $chart.data('apexcharts', chart); + + return chart; +}; diff --git a/src/Foundation/resources/inits/coloris.js b/src/Foundation/resources/inits/coloris.js new file mode 100644 index 0000000..14b7fbe --- /dev/null +++ b/src/Foundation/resources/inits/coloris.js @@ -0,0 +1,28 @@ +return (selector, options = {}) => { + const $input = $(selector); + + // Ensure the input has an ID for Coloris selector + if (!$input.hasAttr('coloris-id')) { + $input.attr('coloris-id', _.uniqueId('coloris-')); + } + + const defaultOptions = { + rtl: $('html').attr('dir') === 'rtl', + themeMode: localStorage.getItem(window.themerKey), + theme: 'polaroid', + formatToggle: true, + }; + + // Get the options from the selector + const selectorOptions = getOptionsFromSelector(selector, 'coloris-'); + options = _.merge(defaultOptions, selectorOptions, options); + + // Initialize the color picker + const picker = new Coloris({ + el: `[coloris-id="${$input.attr('coloris-id')}"`, + ...options, + }); + + // Set the instance on the input element. + $input.data('coloris', picker); +}; diff --git a/src/Foundation/resources/inits/hugerte.js b/src/Foundation/resources/inits/hugerte.js new file mode 100644 index 0000000..461a67e --- /dev/null +++ b/src/Foundation/resources/inits/hugerte.js @@ -0,0 +1,118 @@ +/** + * Initialize the HugeRTE editor. + * + * @param {string} selector + * @param {object} options + * @returns {object} + * @see https://github.com/hugerte/hugerte-docs + */ +return async (selector, options = {}) => { + if (typeof hugerte === 'undefined') { + console.error('HugeRTE is not loaded.'); + return; + } + + // Get the theme from the data-bs-theme attribute + let theme = $('html').attr('data-bs-theme'); + + if (theme === 'auto') { + theme = window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; + } + + // Resolve Tabler tokens for the iframe body (parent CSS cannot style it). + const css = getCssProperties(document.documentElement, [ + '--tblr-bg-forms', + '--tblr-body-bg', + '--tblr-body-color', + '--tblr-primary', + ]); + + options = Object.assign({}, options, { + selector: '#' + $(selector).attr('id'), + language: document.documentElement.lang, + directionality: document.documentElement.dir, + height: 300, + menubar: false, + branding: false, + skin: theme === 'dark' ? 'oxide-dark' : 'oxide', + content_css: theme === 'dark' ? 'dark' : 'default', + content_style: `body { background-color: ${css['--tblr-bg-forms'] || css['--tblr-body-bg']}; color: ${css['--tblr-body-color']}; } a { color: ${css['--tblr-primary']}; }`, + plugins: 'advlist autolink code directionality link lists table image', + toolbar: + 'undo redo | styles | bold italic underline forecolor backcolor | alignleft aligncenter alignright alignjustify outdent indent ltr rtl | bullist numlist | table image', + toolbar_mode: 'sliding', + image_title: true, + automatic_uploads: true, + images_upload_handler: (blobInfo, progress) => + new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.withCredentials = false; + xhr.open('POST', '/hugerte/upload'); + xhr.setRequestHeader('X-CSRF-TOKEN', $('meta[name="csrf-token"]').attr('content')); + + xhr.upload.onprogress = (e) => { + progress((e.loaded / e.total) * 100); + }; + + xhr.onload = () => { + if (xhr.status === 403) { + reject({ message: 'HTTP Error: ' + xhr.status, remove: true }); + return; + } + + if (xhr.status < 200 || xhr.status >= 300) { + reject('HTTP Error: ' + xhr.status); + return; + } + + const json = JSON.parse(xhr.responseText); + + if (!json || typeof json.location != 'string') { + reject('Invalid JSON: ' + xhr.responseText); + return; + } + + resolve(json.location); + }; + + xhr.onerror = () => { + reject('Image upload failed due to a XHR Transport error. Code: ' + xhr.status); + }; + + const formData = new FormData(); + formData.append('file', blobInfo.blob(), blobInfo.filename()); + + xhr.send(formData); + }), + file_picker_types: 'image', + file_picker_callback: (cb, value, meta) => { + const input = document.createElement('input'); + input.setAttribute('type', 'file'); + input.setAttribute('accept', 'image/*'); + + input.onchange = () => { + const file = input.files[0]; + const reader = new FileReader(); + + reader.onload = () => { + const id = 'blobid' + new Date().getTime(); + const blobCache = hugerte.activeEditor.editorUpload.blobCache; + const base64 = reader.result.split(',')[1]; + const blobInfo = blobCache.create(id, file, base64); + blobCache.add(blobInfo); + + cb(blobInfo.blobUri(), { title: file.name }); + }; + + reader.readAsDataURL(file); + }; + + input.click(); + }, + }); + + const [instance] = await hugerte.init(options); + $(selector).data('hugerte', instance); + + document.addEventListener('theme:changed', () => instance?.destroy(), { once: true }); +}; diff --git a/src/Foundation/resources/inits/icon-picker.js b/src/Foundation/resources/inits/icon-picker.js new file mode 100644 index 0000000..aeec6ea --- /dev/null +++ b/src/Foundation/resources/inits/icon-picker.js @@ -0,0 +1,21 @@ +/** + * Initialize the icon picker input. + * + * @param {string} selector + * @param {object} options + * @see RedotIconPicker + */ +return (selector, options = {}) => { + const defaultOptions = { + maxResults: 100, + searchDebounce: 100, + }; + + const selectorOptions = getOptionsFromSelector(selector, 'iconpicker-'); + options = _.merge(defaultOptions, selectorOptions, options); + + const iconPicker = new RedotIconPicker(selector, options); + + // Set the instance on the input element. + $(selector).data('iconPicker', iconPicker); +}; diff --git a/src/Foundation/resources/inits/overlay-scrollbars.js b/src/Foundation/resources/inits/overlay-scrollbars.js new file mode 100644 index 0000000..3f59fcd --- /dev/null +++ b/src/Foundation/resources/inits/overlay-scrollbars.js @@ -0,0 +1,104 @@ +/** + * Initialize OverlayScrollbars on the given element. + * + * Besides the regular OverlayScrollbars options, three extras are supported + * (usually set through `os-*` attributes on the element): + * + * - `media`: only activate while this media query matches, e.g. "(min-width: 992px)". + * - `viewport`: selector for the viewport element, or "self" for the element itself. + * - `slot`: selector for the element that holds the scrollbars, or "self". + * + * @param {string|HTMLElement} selector + * @param {object} options + * @returns {object|null} + * @see https://kingsora.github.io/OverlayScrollbars + */ +return (selector, options = {}) => { + const $element = $(selector); + const element = $element.get(0); + + // Dark containers get the light scrollbar theme, and vice versa. + const currentTheme = () => ($element.theme() === 'dark' ? 'os-theme-light' : 'os-theme-dark'); + + const defaultOptions = { + overflow: { + y: 'scroll', + }, + scrollbars: { + theme: currentTheme(), + autoHide: 'leave', + autoHideDelay: 300, + autoHideSuspend: true, + }, + }; + + const { media, viewport, slot, ...scrollbarOptions } = _.merge(getOptionsFromSelector(selector, 'os-'), options); + options = _.merge(defaultOptions, scrollbarOptions); + + const resolve = (value) => (value === 'self' ? element : element.querySelector(value)); + + const target = { + target: element, + ...(viewport && { elements: { viewport: resolve(viewport) } }), + ...(slot && { scrollbars: { slot: resolve(slot) } }), + }; + + let instance = null; + const mediaQuery = media ? window.matchMedia(media) : null; + + const $initialized = element === document.body ? $element.add(document.documentElement) : $element; + + // Create or destroy the instance depending on whether the media query matches. + const sync = () => { + if (mediaQuery && !mediaQuery.matches) { + instance?.destroy(); + instance = null; + $initialized.removeAttr('data-overlayscrollbars-initialize'); + return; + } + + if (instance) return; + + $initialized.attr('data-overlayscrollbars-initialize', ''); + instance = OverlayScrollbarsGlobal.OverlayScrollbars(target, options); + }; + + mediaQuery?.addEventListener('change', sync); + document.addEventListener('theme:changed', () => instance?.options({ scrollbars: { theme: currentTheme() } })); + + sync(); + + // Bootstrap modals are their own overflow container, so give each open + // modal its own instance and pause the body scrolling behind it. Overlay + // scrollbars take no layout space, so neither step shifts the page. + // Bound through jQuery: dialogs removed on hide (e.g. bootbox) detach + // before the native event dispatch, so it never bubbles to the document. + if (element === document.body) { + const modalInstance = (modal) => OverlayScrollbarsGlobal.OverlayScrollbars(modal); + + $(document).on('show.bs.modal', (event) => { + if (!instance) return; + + if (!modalInstance(event.target)) { + OverlayScrollbarsGlobal.OverlayScrollbars( + { target: event.target, elements: { viewport: event.target } }, + _.merge({}, options, { overflow: { x: 'hidden' }, scrollbars: { theme: currentTheme() } }), + ); + } + + instance?.options({ overflow: { y: 'hidden' } }); + }); + + $(document).on('shown.bs.modal', (event) => modalInstance(event.target)?.update(true)); + + $(document).on('hidden.bs.modal', (event) => { + modalInstance(event.target)?.destroy(); + + if (!document.querySelector('.modal.show')) { + instance?.options({ overflow: { y: options.overflow.y } }); + } + }); + } + + return instance; +}; diff --git a/src/Foundation/resources/inits/query-builder.js b/src/Foundation/resources/inits/query-builder.js new file mode 100644 index 0000000..0b67a92 --- /dev/null +++ b/src/Foundation/resources/inits/query-builder.js @@ -0,0 +1,114 @@ +/** + * jQuery QueryBuilder plugin wrapper for TomSelect. + * + * @see https://querybuilder.js.org/ + * @see https://tom-select.js.org/ + */ +$.fn.tomselect = function (options = {}) { + return this.each(function () { + const $select = $(this); + + if ($select.data('tomselect')) { + return; + } + + if (!window.__inits?.['tomselect']) { + console.error('TomSelect init is not loaded.'); + return; + } + + window.__inits['tomselect'](this, options); + }); +}; + +/** + * jQuery QueryBuilder plugin wrapper for Tempus Dominus. + * + * @see https://querybuilder.js.org/ + * @see https://getdatepicker.com/ + */ +$.fn.datepicker = function (options = {}) { + return this.each(function () { + const $input = $(this); + + if ($input.data('picker')) { + return; + } + + if (!window.__inits?.['tempus-dominus']) { + console.error('Tempus Dominus init is not loaded.'); + return; + } + + window.__inits['tempus-dominus'](this, options); + }); +}; + +/** + * Initialize the query builder. + * + * @param {string} selector + * @param {object} options + * @see https://querybuilder.js.org/ + */ +return (selector, options = {}) => { + const defaultOptions = { + lang_code: $('html').attr('lang'), + display_empty_filter: false, + display_errors: true, + allow_groups: 2, + allow_empty: true, + default_filter: null, + icons: { + add_group: 'ti ti-folder-plus', + add_rule: 'ti ti-circle-plus', + remove_group: 'ti ti-trash', + remove_rule: 'ti ti-x', + }, + }; + + const selectorOptions = getOptionsFromSelector(selector, 'query-'); + options = _.merge(defaultOptions, selectorOptions, options); + + // Loop through the filters and apply the value setter and getter. + for (const filter of options.filters) { + filter.valueSetter = function (rule, value) { + let count = rule.operator.nb_inputs; + let values = count > 1 ? value : [value]; + let $inputs = rule.$el.find('.rule-value-container').find('input, select'); + + // Set the values for the input and select elements. + $inputs.each((index, element) => setFieldValue($(element), values[index])); + }; + + filter.valueGetter = function (rule) { + let count = rule.operator.nb_inputs; + let $inputs = rule.$el.find('.rule-value-container').find('input, select'); + let values = []; + + // Get the values for the input and select elements. + $inputs.each((index, element) => values.push(getFieldValue($(element)))); + + return count > 1 ? values : values[0]; + }; + } + + // If the input has a value, parse it and set the rules. + options.rules = $(selector).val() ? JSON.parse($(selector).val()) : []; + + // Render the query builder. + let $builder = $(selector).closest('[query-builder-container]').find('[query-builder]'); + let instance = $builder.queryBuilder(options).data('queryBuilder'); + + // Serialize the query builder data when the form is submitted. + let $form = $(selector).closest('form'); + $form.on('submit', () => { + let rules = instance.getRules(); + let value = _.isEmpty(rules) ? null : JSON.stringify(rules); + + $(selector).val(value); + }); + + // Set the instance on the input element. + $(selector).data('queryBuilder', instance); +}; diff --git a/src/Foundation/resources/inits/repeater.js b/src/Foundation/resources/inits/repeater.js new file mode 100644 index 0000000..ccff148 --- /dev/null +++ b/src/Foundation/resources/inits/repeater.js @@ -0,0 +1,22 @@ +/** + * Initialize the repeater input. + * + * @param {string} selector + * @param {object} options + * @see RedotRepeater + */ +return (selector, options = {}) => { + const defaultOptions = { + sortable: true, + scrollable: true, + confirmable: true, + }; + + const selectorOptions = getOptionsFromSelector(selector, 'repeater-'); + options = _.merge(defaultOptions, selectorOptions, options); + + const repeater = new RedotRepeater(selector, options); + + // Set the instance on the input element. + $(selector).data('repeater', repeater); +}; diff --git a/src/Foundation/resources/inits/sortable.js b/src/Foundation/resources/inits/sortable.js new file mode 100644 index 0000000..81e1bfe --- /dev/null +++ b/src/Foundation/resources/inits/sortable.js @@ -0,0 +1,22 @@ +/** + * Initialize the sortable list. + * + * @param {string} selector + * @param {object} options + * @see https://sortablejs.github.io/Sortable/ + */ +return (selector, options = {}) => { + const defaultOptions = { + animation: 150, + }; + + const selectorOptions = getOptionsFromSelector(selector, 'sortable-'); + options = _.merge(defaultOptions, selectorOptions, options); + + const sortable = new Sortable($(selector).get(0), options); + + // Set the instance on the input element. + $(selector).data('sortable', sortable); + + return sortable; +}; diff --git a/src/Foundation/resources/inits/tempus-dominus.js b/src/Foundation/resources/inits/tempus-dominus.js new file mode 100644 index 0000000..d563409 --- /dev/null +++ b/src/Foundation/resources/inits/tempus-dominus.js @@ -0,0 +1,80 @@ +/** + * Initialize the tempus dominus date picker. + * + * @param {string} selector + * @param {object} options + * @returns {object} + * @see https://getdatepicker.com/ + */ +return (selector, options = {}) => { + const $picker = $(selector); + + // Determine if the picker inside a rtl direction + const isRtl = getComputedStyle($picker.get(0)).direction === 'rtl'; + + const defaultOptions = { + display: { + theme: $('html').attr('data-bs-theme'), + + components: { + calendar: true, + clock: false, + }, + + icons: { + previous: isRtl ? 'ti ti-chevron-right' : 'ti ti-chevron-left', + next: isRtl ? 'ti ti-chevron-left' : 'ti ti-chevron-right', + }, + }, + + localization: { + locale: document.documentElement.lang || 'en', + format: 'yyyy-MM-dd', + hourCycle: 'h12', + }, + }; + + // Get the options from the selector + const selectorOptions = getOptionsFromSelector(selector, 'date-'); + options = _.merge(defaultOptions, selectorOptions, options); + + // If the picker has the datetime attribute, add the time components + if ($picker.hasAttr('datetime') || options.type === 'datetime') { + options.display.components.clock = true; + options.display.components.calendar = true; + options.localization.format = 'yyyy-MM-dd hh:mm T'; + } + + // If the picker has only-time attribute, remove the date components + if ($picker.hasAttr('only-time') || options.type === 'time') { + options.display.components.calendar = false; + options.display.components.clock = true; + options.localization.format = 'hh:mm T'; + } + + // Remove the type option because it's not needed anymore + delete options.type; + + // Locale drives month/weekday names via Intl, but the `T` token uses + // dayPeriod (ص/م in Arabic) which Laravel's `date` rule cannot parse. + tempusDominus.DateTime.prototype.meridiem = function () { + return this.getHours() < 12 ? 'AM' : 'PM'; + }; + + tempusDominus.DateTime.prototype.getLocaleAfternoon = function () { + return 'PM'; + }; + + // Initialize the picker + const picker = new tempusDominus.TempusDominus($picker.get(0), options); + $picker.data('picker', picker); + + // Update the theme when the theme changes + document.addEventListener('theme:changed', () => { + const theme = $('html').attr('data-bs-theme'); + + // Hide the picker + picker.hide(); + picker.updateOptions({ display: { theme: theme } }); + }); +}; diff --git a/src/Foundation/resources/inits/tomselect.js b/src/Foundation/resources/inits/tomselect.js new file mode 100644 index 0000000..4d3e9bf --- /dev/null +++ b/src/Foundation/resources/inits/tomselect.js @@ -0,0 +1,214 @@ +/** + * Prepare the options for the remote select box. + */ +function prepareRemoteOptions($select, options) { + let fields = options.searchField || []; + + return _.merge(options, { + preload: 'focus', + placeholder: __('Type to search...'), + valueField: '__value', + labelField: '__text', + searchField: ['__text', '__value', ...fields], + load: function (term, callback) { + const endpoint = new URL(options.queryRoute); + + // Add the search term to the endpoint. + endpoint.searchParams.append('term', term); + endpoint.searchParams.append('data', options.query); + + // If options has limit, add it to the endpoint. + if (options.limit) { + endpoint.searchParams.append('limit', options.limit); + } + + // Append the bindings to the endpoint. + let bindings = getSelectBindings($select); + for (const key in bindings) { + endpoint.searchParams.append(`parameters[${key}]`, bindings[key]); + } + + fetch(endpoint) + .then((response) => response.json()) + .then((response) => callback(response.payload.data)) + .catch(() => callback([])); + }, + }); +} + +/** + * Preload values into the select box using AJAX request. + */ +function preloadValues($select) { + let ids = $select.attr('select-preload-values').trim(); + + // Early exit if there are no ids to preload. + if (ids.length === 0) { + return; + } + + let options = getOptionsFromSelector($select, 'select-'); + let endpoint = new URL(options.fetchRoute); + let instance = $select.data('tomselect'); + + endpoint.searchParams.append('data', options.query); + endpoint.searchParams.append('ids', ids); + + // Append the bindings to the endpoint. + let bindings = getSelectBindings($select); + for (const key in bindings) { + endpoint.searchParams.append(`parameters[${key}]`, bindings[key]); + } + + fetch(endpoint) + .then((response) => response.json()) + .then((response) => { + const data = response.payload.data; + + instance.addOptions(data); + instance.setValue(data.map((item) => item.__value)); + }); +} + +/** + * Get the bindings from the select box. + */ +function getSelectBindings($select) { + let result = {}; + let bindings = getOptionsFromSelector($select, 'bind-'); + + for (const binding in bindings) { + let bind = bindings[binding]; + + if (typeof bind !== 'object') { + result[binding] = bind; + } else if (bind.hasOwnProperty('value')) { + result[binding] = bind.value; + } else if (bind.hasOwnProperty('selector')) { + result[binding] = getFieldValue($.query(bind.selector)); + } + } + + return result; +} + +/** + * Bind the select box to it's bindings inputs. + */ +function bindSelectBindings($select) { + let instance = $select.data('tomselect'); + let bindings = getOptionsFromSelector($select, 'bind-'); + + for (const binding in bindings) { + let value = bindings[binding]; + + // Early exit if the value is not an object or doesn't have a selector. + if (typeof value !== 'object' || !value.hasOwnProperty('selector')) { + continue; + } + + // Get the input element. + let $input = $.query(value.selector); + + // Early exit if the input element is not found. + if ($input.length === 0) { + return console.error(`Input element with selector "${value.selector}" not found.`); + } + + // Bind the input element to the select box. + $input.on('change', function () { + instance.clear(); + instance.clearOptions(); + + $select.attr(`bind-${binding}.value`, $(this).val()); + + // Reset the loaded searches. + instance.loadedSearches = {}; + $(instance.control).closest('.ts-wrapper').removeClass('preloaded'); + }); + } +} + +/** + * Initialize the tom select input. + * + * @param {string} selector + * @param {object} options + * @see https://tom-select.js.org/ + */ +return (selector, options = {}) => { + const $select = $(selector); + + const defaultOptions = { + create: $select.hasAttr('tags'), + placeholder: __('Select an option'), + + onInitialize: function () { + const selected = $select.find('option[selected]'); + + if (selected.length === 0 && $select.hasAttr('removable')) { + this.clear(); + } + }, + + render: { + option: function (data, escape) { + return `
${data.__html || escape(data.__text || data.text)}
`; + }, + }, + }; + + const selectorOptions = getOptionsFromSelector(selector, 'select-'); + options = _.merge(defaultOptions, selectorOptions, options); + + if ($select.hasAttr('same-template')) { + options.render.item = options.render.option; + } + + if ($select.hasAttr('multiple') || $select.hasAttr('removable')) { + options.plugins = options.plugins || []; + options.plugins.push('remove_button'); + } + + if (options.hasOwnProperty('query')) { + options = prepareRemoteOptions($select, options); + } + + const instance = new TomSelect(selector, options); + + // Set the instance on the input element. + $select.data('tomselect', instance); + + // Bind the select box to it's bindings inputs. + bindSelectBindings($select); + + // Bind the select box to browser messages that should preload a value. + window.addEventListener('message', function (event) { + const message = event.data; + if (!message || message.key !== $select.attr('id')) return; + + // If a lightbox is still open, close the last opened lightbox. + Glare.close(); + + const value = _.get(message, 'data.value'); + if (value === undefined || value === null || value === '') return; + + $select.attr('select-preload-values', value); + preloadValues($select); + }); + + // Initial preload values if the attribute is present + if ($select.hasAttr('select-preload-values')) { + preloadValues($select); + } + + // Preload values when `select:preload` event is triggered. + $select.on('select:preload', function () { + preloadValues($select); + }); + + // Enable or disable the select box when the visibility changes. + $select.on('visibility:updated', function (event, visibility) { + visibility ? instance.enable() : instance.disable(); + }); +}; diff --git a/src/Foundation/resources/inits/turnstile.js b/src/Foundation/resources/inits/turnstile.js new file mode 100644 index 0000000..99eb4b1 --- /dev/null +++ b/src/Foundation/resources/inits/turnstile.js @@ -0,0 +1,28 @@ +/** + * Initialize the turnstile captcha. + * + * @param {string} selector + * @param {object} options + * @see https://developers.cloudflare.com/turnstile/get-started/client-side-rendering/ + */ +return (selector, options = {}) => { + const defaultOptions = { + sitekey: $('meta[name="cloudflare-turnstile-site-key"]').attr('content'), + theme: $('html').attr('data-bs-theme'), + language: $('html').attr('lang'), + size: 'flexible', + }; + + const selectorOptions = getOptionsFromSelector(selector, 'captcha-'); + options = _.merge(defaultOptions, selectorOptions, options); + + // Define the callback function. + options.callback = function (token) { + $(selector).find('input').val(token); + }; + + const instance = turnstile.render(selector, options); + + // Set the instance on the input element. + $(selector).data('captcha', instance); +}; diff --git a/src/Foundation/resources/inits/uploader.js b/src/Foundation/resources/inits/uploader.js new file mode 100644 index 0000000..6b25fbd --- /dev/null +++ b/src/Foundation/resources/inits/uploader.js @@ -0,0 +1,26 @@ +/** + * Initialize the uploader input. + * + * @param {string} selector + * @param {object} options + * @see RedotUploader + */ +return (selector, options = {}) => { + const defaultOptions = { + sortable: true, + multiple: true, + accept: '*', + autoUpload: true, + maxSize: 10 * 1024 * 1024, + confirmable: true, + returnType: 'object', + }; + + const selectorOptions = getOptionsFromSelector(selector, 'uploader-'); + options = _.merge(defaultOptions, selectorOptions, options); + + const uploader = new RedotUploader(selector, options); + + // Set the instance on the input element. + $(selector).data('uploader', uploader); +}; diff --git a/src/Foundation/src/Commands/BuildDependenciesCommand.php b/src/Foundation/src/Commands/BuildDependenciesCommand.php index 588f664..295bfed 100644 --- a/src/Foundation/src/Commands/BuildDependenciesCommand.php +++ b/src/Foundation/src/Commands/BuildDependenciesCommand.php @@ -109,19 +109,26 @@ protected function buildLanguageFile(string $locale) protected function buildInitFiles() { $inits = []; - foreach (glob(public_path('assets/inits/*.js')) as $file) { - $inits[] = $file; + + // Application inits override the package inits with the same name. + foreach ([dirname(__DIR__, 2) . '/resources/inits', public_path('assets/inits')] as $directory) { + if (! File::isDirectory($directory)) continue; + + // Push path to the dependencies array. + $this->dependsOnDirectory($directory); + + foreach (glob($directory . '/*.js') as $file) { + $inits[basename($file, '.js')] = $file; + } } - // Push path to the dependencies array. - $this->dependsOnDirectory(public_path('assets/inits')); - $this->dependsOnFile(...$inits); + $this->dependsOnFile(...array_values($inits)); $javascriptFile = 'window.__inits = {};' . "\n"; - foreach ($inits as $file) { + foreach ($inits as $name => $file) { $javascriptFile .= sprintf( 'window.__inits["%s"] = (() => { %s })();', - basename($file, '.js'), + $name, File::get($file) ); } diff --git a/src/Foundation/src/Commands/PublishAssetsCommand.php b/src/Foundation/src/Commands/PublishAssetsCommand.php new file mode 100644 index 0000000..219cca1 --- /dev/null +++ b/src/Foundation/src/Commands/PublishAssetsCommand.php @@ -0,0 +1,41 @@ +callSilently('vendor:publish', [ + '--tag' => 'redot::assets', + '--force' => true, + ]); + + info('Redot assets published successfully!'); + } +} diff --git a/src/Foundation/src/Http/Middleware/EnsureDependenciesBuilt.php b/src/Foundation/src/Http/Middleware/EnsureDependenciesBuilt.php index 981e4d0..ad5702d 100644 --- a/src/Foundation/src/Http/Middleware/EnsureDependenciesBuilt.php +++ b/src/Foundation/src/Http/Middleware/EnsureDependenciesBuilt.php @@ -49,7 +49,8 @@ protected function dependenciesNeedBuilding(string $lockFile): bool foreach (['files', 'directories'] as $type) { foreach ($lock[$type] as $path => $timestamp) { - $path = base_path($path); + // Paths outside the application, such as a symlinked package, are stored as absolute paths. + $path = file_exists(base_path($path)) ? base_path($path) : $path; if (! file_exists($path) || $timestamp !== filemtime($path)) { return true; diff --git a/src/Foundation/src/Jobs/ExtractLanguageTokens.php b/src/Foundation/src/Jobs/ExtractLanguageTokens.php index b727b15..20df49e 100644 --- a/src/Foundation/src/Jobs/ExtractLanguageTokens.php +++ b/src/Foundation/src/Jobs/ExtractLanguageTokens.php @@ -32,6 +32,8 @@ public function handle(): void database_path('seeders'), public_path('assets'), resource_path(), + dirname(__DIR__, 2) . '/public', + dirname(__DIR__, 2) . '/resources', ]; $extractor = new LangExtractor; diff --git a/src/Foundation/src/RedotServiceProvider.php b/src/Foundation/src/RedotServiceProvider.php index 4d0fe5d..7241bed 100644 --- a/src/Foundation/src/RedotServiceProvider.php +++ b/src/Foundation/src/RedotServiceProvider.php @@ -20,6 +20,7 @@ use Illuminate\Support\Facades\Session; use Illuminate\Support\Facades\URL; use Illuminate\Support\Facades\Validator; +use Illuminate\Support\Facades\View; use Illuminate\Support\ServiceProvider; use Redot\Auth\RedotAuthServiceProvider; use Redot\Commands\BuildDependenciesCommand; @@ -29,6 +30,7 @@ use Redot\Commands\LintCommand; use Redot\Commands\ModelPopulateCommand; use Redot\Commands\PublicLinkCommand; +use Redot\Commands\PublishAssetsCommand; use Redot\Commands\PublishLanguageTokensCommand; use Redot\Commands\RevertLanguageTokensCommand; use Redot\Commands\SyncLanguageTokensCommand; @@ -42,14 +44,51 @@ use Redot\Sidebar\Sidebar; use Redot\Support\PermissionNameResolver; use Redot\Toastify\LaravelToastifyServiceProvider; +use Redot\View\Components; class RedotServiceProvider extends ServiceProvider { + /** + * The package Blade components. + * + * @var array + */ + protected array $components = [ + 'alert' => Components\Alert::class, + 'apex-chart' => Components\ApexChart::class, + 'attachments' => Components\Attachments::class, + 'avatar' => Components\Avatar::class, + 'captcha' => Components\Captcha::class, + 'checkboxes' => Components\Checkboxes::class, + 'color-picker' => Components\ColorPicker::class, + 'date-picker' => Components\DatePicker::class, + 'file-hint' => Components\FileHint::class, + 'form' => Components\Form::class, + 'form-card' => Components\FormCard::class, + 'icon-picker' => Components\IconPicker::class, + 'input' => Components\Input::class, + 'query-builder' => Components\QueryBuilder::class, + 'radios' => Components\Radios::class, + 'radios-colored' => Components\RadiosColored::class, + 'rating' => Components\Rating::class, + 'repeater' => Components\Repeater::class, + 'rich-editor' => Components\RichEditor::class, + 'select' => Components\Select::class, + 'select-remote' => Components\SelectRemote::class, + 'status' => Components\Status::class, + 'textarea' => Components\Textarea::class, + 'toasts' => Components\Toasts::class, + 'toggle' => Components\Toggle::class, + 'translatable' => Components\Translatable::class, + 'uploader' => Components\Uploader::class, + ]; + public function register(): void { $this->config(); $this->stubs(); $this->migrations(); + $this->assets(); $this->commands([ BuildDependenciesCommand::class, @@ -59,6 +98,7 @@ public function register(): void LintCommand::class, ModelPopulateCommand::class, PublicLinkCommand::class, + PublishAssetsCommand::class, PublishLanguageTokensCommand::class, RevertLanguageTokensCommand::class, SyncLanguageTokensCommand::class, @@ -106,6 +146,16 @@ protected function migrations(): void ], 'redot::migrations'); } + /** + * Register the package public assets and the third-party libraries they use. + */ + protected function assets(): void + { + $this->publishes([ + __DIR__ . '/../public' => public_path('vendor/redot'), + ], 'redot::assets'); + } + /** * Bootstrap any application services. */ @@ -185,6 +235,16 @@ protected function configureBlade(): void Blade::anonymousComponentPath(resource_path('layouts'), 'layouts'); Blade::componentNamespace('App\\View\\Layouts', 'layouts'); + // Package views resolve after the application's, so a same-named view overrides them. + View::addLocation(__DIR__ . '/../resources'); + + // An application component class with the same name takes precedence over the package one. + foreach ($this->components as $alias => $component) { + if (class_exists($this->app->getNamespace() . 'View\\Components\\' . class_basename($component))) continue; + + Blade::component($alias, $component); + } + Blade::directive('themer', function ($expression = 'theme') { $expression = str_replace(['"', "'", '`'], '', $expression); @@ -194,7 +254,7 @@ protected function configureBlade(): void @push('pre-content') - + @endpush EOT ); diff --git a/src/Foundation/src/View/Components/Alert.php b/src/Foundation/src/View/Components/Alert.php new file mode 100644 index 0000000..a8dff99 --- /dev/null +++ b/src/Foundation/src/View/Components/Alert.php @@ -0,0 +1,54 @@ + 'ti ti-circle-check', + 'error' => 'ti ti-circle-x', + 'warning' => 'ti ti-alert-triangle', + 'info' => 'ti ti-info-circle', + ]; + + /** + * Create a new component instance. + */ + public function __construct( + public ?string $icon = null, + public ?string $title = null, + public ?string $description = null, + public string $type = 'success', + public bool $dismissible = false, + ) {} + + /** + * Get the view / contents that represent the component. + */ + public function render(): View|Closure|string + { + $this->type = in_array($this->type, array_keys(self::TYPES_ICONS)) ? $this->type : 'success'; + $this->icon ??= self::TYPES_ICONS[$this->type]; + + return function (): View { + $this->attributes(function (ComponentAttributeBag $attributes) { + return $attributes->class([ + 'alert', + 'alert-' . ($this->type === 'error' ? 'danger' : $this->type), + 'alert-dismissible' => $this->dismissible, + ]); + }); + + return view($this->view); + }; + } +} diff --git a/src/Foundation/src/View/Components/ApexChart.php b/src/Foundation/src/View/Components/ApexChart.php new file mode 100644 index 0000000..41bca67 --- /dev/null +++ b/src/Foundation/src/View/Components/ApexChart.php @@ -0,0 +1,87 @@ +id ??= uniqid('apex-chart-'); + + $options = $this->normalizeOptions($this->options); + $series = $this->normalizeOptions($this->series); + + if ($series !== []) { + $options['series'] = $series; + } + + if ($this->type) { + data_set($options, 'chart.type', $this->type); + } + + if ($this->height !== null) { + data_set($options, 'chart.height', $this->height); + } + + if ($this->width !== null) { + data_set($options, 'chart.width', $this->width); + } + + return function () use ($options): View { + $this->attributes(function (ComponentAttributeBag $attributes) use ($options) { + return $attributes->merge([ + 'apex-chart' => json_encode($options, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES), + ]); + }); + + return view($this->view); + }; + } + + /** + * Normalize chart options from arrays, collections, or JSON strings. + */ + protected function normalizeOptions(array|string|Collection|null $options): array + { + if ($options instanceof Collection) { + return $options->toArray(); + } + + if (is_array($options)) { + return $options; + } + + if (is_string($options) && trim($options) !== '') { + $decoded = json_decode($options, true); + + return is_array($decoded) ? $decoded : []; + } + + return []; + } +} diff --git a/src/Foundation/src/View/Components/Attachments.php b/src/Foundation/src/View/Components/Attachments.php new file mode 100644 index 0000000..3e975a3 --- /dev/null +++ b/src/Foundation/src/View/Components/Attachments.php @@ -0,0 +1,81 @@ +id ??= uniqid('attachments-'); + + return view($this->view); + } + + /** + * Get the file icon for the given MIME type. + */ + public function getFileIcon(string $mimeType): string + { + $icons = [ + 'application/pdf' => 'ti ti-file-type-pdf', + 'application/msword' => 'ti ti-file-type-doc', + 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' => 'ti ti-file-type-doc', + 'application/vnd.ms-excel' => 'ti ti-file-type-xls', + 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'ti ti-file-type-xls', + 'application/vnd.ms-powerpoint' => 'ti ti-file-type-ppt', + 'application/vnd.openxmlformats-officedocument.presentationml.presentation' => 'ti ti-file-type-ppt', + 'application/zip' => 'ti ti-file-zip', + 'application/x-rar-compressed' => 'ti ti-file-zip', + 'application/x-7z-compressed' => 'ti ti-file-zip', + 'text/plain' => 'ti ti-file-text', + 'text/html' => 'ti ti-file-code', + 'text/css' => 'ti ti-file-code', + 'text/javascript' => 'ti ti-file-code', + 'application/json' => 'ti ti-file-code', + 'video/' => 'ti ti-video', + 'audio/' => 'ti ti-file-music', + ]; + + foreach ($icons as $type => $icon) { + if (str_starts_with($mimeType, $type)) return $icon; + } + + return 'ti ti-file'; + } + + /** + * Format the file size. + */ + public function formatFileSize(int $size): string + { + $units = ['B', 'KB', 'MB', 'GB', 'TB']; + $index = 0; + + while ($size >= 1024 && $index < count($units) - 1) { + $size /= 1024; + $index++; + } + + return round($size, 2) . ' ' . $units[$index]; + } +} diff --git a/src/Foundation/src/View/Components/Avatar.php b/src/Foundation/src/View/Components/Avatar.php new file mode 100644 index 0000000..f2caf83 --- /dev/null +++ b/src/Foundation/src/View/Components/Avatar.php @@ -0,0 +1,45 @@ +attributes(function (ComponentAttributeBag $attributes) { + $style = sprintf('background-image: url(%s)', $this->image); + + return $attributes->class([ + 'avatar', + "avatar-{$this->size}", + ])->style([ + $style => $this->image, + ]); + }); + + return view($this->view); + }; + } +} diff --git a/src/Foundation/src/View/Components/Captcha.php b/src/Foundation/src/View/Components/Captcha.php new file mode 100644 index 0000000..134d2dc --- /dev/null +++ b/src/Foundation/src/View/Components/Captcha.php @@ -0,0 +1,43 @@ +id ??= uniqid('captcha-'); + + return function (): View { + $this->attributes(function (ComponentAttributeBag $attributes) { + return $attributes->class(['cf-turnstile'])->merge([ + 'init' => 'turnstile', + ]); + }); + + return view($this->view); + }; + } +} diff --git a/src/Foundation/src/View/Components/Checkboxes.php b/src/Foundation/src/View/Components/Checkboxes.php new file mode 100644 index 0000000..188b23f --- /dev/null +++ b/src/Foundation/src/View/Components/Checkboxes.php @@ -0,0 +1,56 @@ +disabled)) { + $this->disabled = is_string($this->disabled) ? parse_csv($this->disabled) : [$this->disabled]; + } + + return parent::render(); + } + + /** + * Prepare the attributes and any extra view data once attributes are available. + */ + protected function prepare(array $data): array + { + // If the value is csv, we will convert it to an array. + if (! is_array($this->value)) { + $this->value = is_string($this->value) ? parse_csv($this->value) : [$this->value]; + } + + return []; + } +} diff --git a/src/Foundation/src/View/Components/ColorPicker.php b/src/Foundation/src/View/Components/ColorPicker.php new file mode 100644 index 0000000..4e32e44 --- /dev/null +++ b/src/Foundation/src/View/Components/ColorPicker.php @@ -0,0 +1,20 @@ +attributes->getAttributes()); + + $this->withAttributes($callback($attributes)->getAttributes()); + } +} diff --git a/src/Foundation/src/View/Components/DatePicker.php b/src/Foundation/src/View/Components/DatePicker.php new file mode 100644 index 0000000..da25ef9 --- /dev/null +++ b/src/Foundation/src/View/Components/DatePicker.php @@ -0,0 +1,20 @@ +attributes(function (ComponentAttributeBag $attributes) { + $attributes = $attributes->class(['text-decoration-none']); + + if ($this->lightbox) { + $attributes = $attributes->merge([ + 'data-lightbox' => '', + ]); + } + + return $attributes; + }); + + return view($this->view); + }; + } +} diff --git a/src/Foundation/src/View/Components/Form.php b/src/Foundation/src/View/Components/Form.php new file mode 100644 index 0000000..7e00f63 --- /dev/null +++ b/src/Foundation/src/View/Components/Form.php @@ -0,0 +1,63 @@ +id ??= uniqid('form-'); + $this->method = strtoupper($this->method); + $this->formMethod = $this->method === 'GET' ? 'GET' : 'POST'; + + if ($this->route) { + $this->action = route($this->route, $this->routeParams); + } + + $this->identifier = base64_encode(sprintf('%s:%s', $this->action, $this->method)); + + $keep = request()->query('keep', []); + + // Append the keep params to the action as query params. + if (is_array($keep) && ! empty($keep)) { + $this->action .= str_contains($this->action, '?') ? '&' : '?'; + $this->action .= Arr::query($keep); + } + + return view($this->view); + } +} diff --git a/src/Foundation/src/View/Components/FormCard.php b/src/Foundation/src/View/Components/FormCard.php new file mode 100644 index 0000000..171c91a --- /dev/null +++ b/src/Foundation/src/View/Components/FormCard.php @@ -0,0 +1,70 @@ +title ??= $this->entry ? __('Edit') : __('Create'); + $this->submit ??= $this->entry ? __('Update') : __('Create'); + + // When no explicit URL is passed, resolve `dashboard.{resource}.store|update` and build the action. + if (! $this->action) { + // Route name suffix matches Laravel conventions: store for new records, update for existing. + $this->route ??= "dashboard.$this->resource." . ($this->entry ? 'update' : 'store'); + + // Update routes expect the model (or key) as the last route parameter; merge it into `params`. + if ($this->entry) { + $this->routeParams = array_merge($this->routeParams, [$this->entry]); + } + + // Build the action URL using the route and params. + $this->action = route($this->route, $this->routeParams); + } + + // Form method: PUT for updates, POST for creates. + $this->method ??= $this->entry ? 'PUT' : 'POST'; + + // Back link defaults to the resource index route name. + $this->back ??= "dashboard.$this->resource.index"; + + // If the page is inline, unset the back link. + if (request()->has('inline')) $this->back = null; + + $this->data = array_merge($this->data, [ + 'entry' => $this->entry, + ]); + + return view($this->view, $this->data); + } +} diff --git a/src/Foundation/src/View/Components/FormField.php b/src/Foundation/src/View/Components/FormField.php new file mode 100644 index 0000000..6536ca6 --- /dev/null +++ b/src/Foundation/src/View/Components/FormField.php @@ -0,0 +1,75 @@ +id ??= uniqid(Str::kebab(class_basename($this)) . '-'); + + return function (array $data): View { + $this->fillOldInput(); + + $with = array_merge(['required' => $this->isRequired()], $this->prepare($data)); + + if (property_exists($this, 'value')) { + $with['value'] = $this->value; + } + + return view($this->view, $with); + }; + } + + /** + * Prepare the attributes and any extra view data once attributes are available. + */ + protected function prepare(array $data): array + { + return []; + } + + /** + * Determine if the validation rules contain the `required` rule. + */ + protected function isRequired(): bool + { + $rules = explode('|', (string) $this->attributes->get('validation', $this->validation)); + + return in_array('required', array_map('trim', $rules), true); + } + + /** + * Replace the value with the old input when the field's name was flashed. + */ + protected function fillOldInput(): void + { + $key = str_replace(['[]', '[', ']'], ['', '.', ''], (string) $this->attributes->get('name', $this->name)); + + if (! Arr::has(old(), $key)) return; + + if (property_exists($this, 'value')) { + $this->value = old($key); + } else { + $this->attributes['value'] = old($key); + } + } +} diff --git a/src/Foundation/src/View/Components/IconPicker.php b/src/Foundation/src/View/Components/IconPicker.php new file mode 100644 index 0000000..1db4f7f --- /dev/null +++ b/src/Foundation/src/View/Components/IconPicker.php @@ -0,0 +1,20 @@ +isPassword = strtolower($this->type) === 'password'; + + if ($this->isPassword) { + $this->flat = true; + } + + return parent::render(); + } + + /** + * Prepare the attributes and any extra view data once attributes are available. + */ + protected function prepare(array $data): array + { + return [ + 'isInputGroup' => $data['prepend'] || $data['append'] || $this->isPassword, + ]; + } +} diff --git a/src/Foundation/src/View/Components/QueryBuilder.php b/src/Foundation/src/View/Components/QueryBuilder.php new file mode 100644 index 0000000..aa68057 --- /dev/null +++ b/src/Foundation/src/View/Components/QueryBuilder.php @@ -0,0 +1,56 @@ +filters = QueryFilters::resolve($this->model, $this->filters); + + return parent::render(); + } + + /** + * Prepare the attributes and any extra view data once attributes are available. + */ + protected function prepare(array $data): array + { + // Convert array to JSON string + if (is_array($this->value) || $this->value instanceof Collection) { + $this->value = json_encode($this->value, JSON_UNESCAPED_UNICODE); + } + + $this->attributes(function (ComponentAttributeBag $attributes) { + return $attributes->merge(['query-filters' => is_array($this->filters) ? json_encode($this->filters, JSON_UNESCAPED_UNICODE) : $this->filters]); + }); + + return []; + } +} diff --git a/src/Foundation/src/View/Components/Radios.php b/src/Foundation/src/View/Components/Radios.php new file mode 100644 index 0000000..53d159c --- /dev/null +++ b/src/Foundation/src/View/Components/Radios.php @@ -0,0 +1,43 @@ +disabled)) { + $this->disabled = is_string($this->disabled) ? parse_csv($this->disabled) : [$this->disabled]; + } + + return parent::render(); + } +} diff --git a/src/Foundation/src/View/Components/RadiosColored.php b/src/Foundation/src/View/Components/RadiosColored.php new file mode 100644 index 0000000..79bec1e --- /dev/null +++ b/src/Foundation/src/View/Components/RadiosColored.php @@ -0,0 +1,37 @@ +options as $index => $option) { + $this->options[$index] = $this->getColor($option); + } + + return parent::render(); + } + + /** + * Get the color for the given option. + */ + protected function getColor(string $color): string + { + $color = trim($color); + $isDirectColor = preg_match('/^[a-zA-Z]+$/', $color); + + return $isDirectColor ? "var(--tblr-$color, $color)" : $color; + } +} diff --git a/src/Foundation/src/View/Components/Rating.php b/src/Foundation/src/View/Components/Rating.php new file mode 100644 index 0000000..368a570 --- /dev/null +++ b/src/Foundation/src/View/Components/Rating.php @@ -0,0 +1,39 @@ +size = is_numeric($this->size) ? $this->size . 'px' : $this->size; + + return parent::render(); + } +} diff --git a/src/Foundation/src/View/Components/Repeater.php b/src/Foundation/src/View/Components/Repeater.php new file mode 100644 index 0000000..e0580a7 --- /dev/null +++ b/src/Foundation/src/View/Components/Repeater.php @@ -0,0 +1,36 @@ +value) || $this->value instanceof Collection) { + $this->value = json_encode($this->value, JSON_UNESCAPED_UNICODE); + } + + return []; + } +} diff --git a/src/Foundation/src/View/Components/RichEditor.php b/src/Foundation/src/View/Components/RichEditor.php new file mode 100644 index 0000000..824271f --- /dev/null +++ b/src/Foundation/src/View/Components/RichEditor.php @@ -0,0 +1,25 @@ +attributes(function (ComponentAttributeBag $attributes) { + return $attributes->merge(['init' => 'hugerte']); + }); + + return []; + } +} diff --git a/src/Foundation/src/View/Components/Select.php b/src/Foundation/src/View/Components/Select.php new file mode 100644 index 0000000..4494c23 --- /dev/null +++ b/src/Foundation/src/View/Components/Select.php @@ -0,0 +1,49 @@ +value)) { + $this->value = parse_csv(is_string($this->value) ? $this->value : [$this->value]); + } + + $this->attributes(function (ComponentAttributeBag $attributes) { + $attributes = $attributes->class(['form-select']); + + if ($this->tom) { + $attributes = $attributes->merge(['init' => 'tomselect']); + } + + return $attributes; + }); + + return []; + } +} diff --git a/src/Foundation/src/View/Components/SelectRemote.php b/src/Foundation/src/View/Components/SelectRemote.php new file mode 100644 index 0000000..9c8d205 --- /dev/null +++ b/src/Foundation/src/View/Components/SelectRemote.php @@ -0,0 +1,128 @@ +id ??= uniqid('select-'); + + // If the search is a csv, we will convert it to an array. + if (is_string($this->search)) { + $this->search = parse_csv($this->search); + } + + // If the appends is a csv, we will convert it to an array. + if (is_string($this->appends)) { + $this->appends = parse_csv($this->appends); + } + + // If the query is a string and a class exists, we will instantiate the class and get the query. + if (is_string($this->query) && class_exists($this->query)) { + $this->query = app($this->query)->query(); + } + + // If template doesn't start with `templates.select`, we will prefix it. + if ($this->template && ! str_starts_with($this->template, 'templates.select')) { + $this->template = 'templates.select.' . $this->template; + } + + // Append required params to the create route. + if ($this->create) { + $this->createParams = array_merge($this->createParams, [ + 'inline' => true, + 'keep' => ['from-select' => $this->id], + ]); + } + + return parent::render(); + } + + /** + * Prepare the attributes and any extra view data once attributes are available. + */ + protected function prepare(array $data): array + { + // If the value is csv, we will convert it to an array. + if (! is_array($this->value)) { + $this->value = parse_csv(is_string($this->value) ? $this->value : [$this->value]); + } + + $this->attributes(function (ComponentAttributeBag $attributes) { + return $attributes->merge([ + 'select-query' => $this->getQueryData(), + 'select-query-route' => route('global.select.search'), + 'select-fetch-route' => route('global.select.fetch'), + 'select-search-field' => json_encode($this->search), + 'select-preload-values' => implode(',', $this->value), + ]); + }); + + return []; + } + + /** + * Get the query data as encrypted string. + */ + protected function getQueryData(): string + { + $search = $this->search; + $columns = array_values(array_unique(array_merge($search, [$this->key, $this->text]))); + + $term = uniqid('term_'); + $query = $this->query->clone()->select($this->key); + $query = search_model($query, $columns, sprintf('{%s}', $term)); + + if ($this->template && ! view()->exists($this->template)) { + throw new InvalidArgumentException(sprintf('The template [%s] does not exist.', $this->template)); + } + + $data = [ + 'key' => $this->key, + 'text' => $this->text, + 'template' => $this->template, + + 'query' => $query->toSql(), + 'bindings' => $query->getBindings(), + 'model' => get_class($query->getModel()), + + 'term' => $term, + 'columns' => $columns, + 'appends' => $this->appends, + ]; + + return encrypt(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); + } +} diff --git a/src/Foundation/src/View/Components/Status.php b/src/Foundation/src/View/Components/Status.php new file mode 100644 index 0000000..7699390 --- /dev/null +++ b/src/Foundation/src/View/Components/Status.php @@ -0,0 +1,50 @@ +has($status)) { + $this->status = $status; + + return view($this->view); + } + } + + return ''; + } +} diff --git a/src/Foundation/src/View/Components/Textarea.php b/src/Foundation/src/View/Components/Textarea.php new file mode 100644 index 0000000..baa51e1 --- /dev/null +++ b/src/Foundation/src/View/Components/Textarea.php @@ -0,0 +1,38 @@ +autosize) { + $this->attributes(function (ComponentAttributeBag $attributes) { + return $attributes->merge(['data-bs-toggle' => 'autosize']); + }); + } + + return []; + } +} diff --git a/src/Foundation/src/View/Components/Toasts.php b/src/Foundation/src/View/Components/Toasts.php new file mode 100644 index 0000000..0247d72 --- /dev/null +++ b/src/Foundation/src/View/Components/Toasts.php @@ -0,0 +1,41 @@ +config = config('toastify', []); + $this->messages = session()->pull('toastify', []); + } + + /** + * Get the view / contents that represent the component. + */ + public function render(): View|Closure|string + { + return view($this->view); + } +} diff --git a/src/Foundation/src/View/Components/Toggle.php b/src/Foundation/src/View/Components/Toggle.php new file mode 100644 index 0000000..c733386 --- /dev/null +++ b/src/Foundation/src/View/Components/Toggle.php @@ -0,0 +1,33 @@ +value = (bool) $this->value; + + return []; + } +} diff --git a/src/Foundation/src/View/Components/Translatable.php b/src/Foundation/src/View/Components/Translatable.php new file mode 100644 index 0000000..7f5cfb8 --- /dev/null +++ b/src/Foundation/src/View/Components/Translatable.php @@ -0,0 +1,91 @@ +id ??= uniqid('translatable-'); + + if (! $this->locales) { + $this->locales = array_keys(config('app.locales')); + } + + if (is_null($this->value)) { + $this->value = []; + } + + if (is_string($this->locales)) { + $this->locales = parse_csv($this->locales); + } + + if (is_string($this->validateLocales)) { + $this->validateLocales = parse_csv($this->validateLocales); + } + + foreach ($this->locales as $index => $locale) { + $validation = $this->validation; + + if ($this->validateLocales && ! in_array($locale, $this->validateLocales)) { + $validation = $this->validationWithoutRequiredRule(); + } + + if ($this->validateOnlyMainLocale && $index > 0) { + $validation = $this->validationWithoutRequiredRule(); + } + + $this->localesConfig[$locale] = [ + 'id' => sprintf('%s-%s', $this->id, $locale), + 'name' => $this->name ? sprintf('%s[%s]', $this->name, $locale) : null, + 'value' => $this->value[$locale] ?? null, + 'validation' => $validation, + ]; + } + + return view($this->view); + } + + /** + * Get the validation rules without the required rule. + */ + protected function validationWithoutRequiredRule(): ?string + { + $rules = array_filter( + array_map('trim', explode('|', $this->validation ?? '')), + fn (string $rule): bool => $rule !== '' && $rule !== 'required', + ); + + return $rules ? implode('|', $rules) : null; + } +} diff --git a/src/Foundation/src/View/Components/Uploader.php b/src/Foundation/src/View/Components/Uploader.php new file mode 100644 index 0000000..6208a1a --- /dev/null +++ b/src/Foundation/src/View/Components/Uploader.php @@ -0,0 +1,67 @@ +value) || $this->value instanceof Collection) { + $this->value = json_encode($this->value, JSON_UNESCAPED_UNICODE); + } + + $this->attributes(function (ComponentAttributeBag $attributes) { + return $attributes->merge([ + 'init' => 'uploader', + 'uploader-accept' => $this->accept, + 'uploader-config' => $this->getUploaderConfig(), + ]); + }); + + return []; + } + + /** + * Get the uploader data. + */ + protected function getUploaderConfig(): string + { + $data = [ + 'accept' => $this->accept, + 'directory' => $this->directory, + 'locale' => app()->getLocale(), + 'serverValidation' => $this->serverValidation, + 'optimize' => $this->optimize, + 'thumbnail' => $this->thumbnail, + ]; + + return encrypt(json_encode($data, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)); + } +} diff --git a/tests/Feature/Core/Commands/BuildDependenciesCommandTest.php b/tests/Feature/Core/Commands/BuildDependenciesCommandTest.php new file mode 100644 index 0000000..793783c --- /dev/null +++ b/tests/Feature/Core/Commands/BuildDependenciesCommandTest.php @@ -0,0 +1,24 @@ +artisan('dependencies:build')->assertSuccessful(); + + $build = File::get(dist_path('init.js')); + + expect($build) + ->toContain('window.__inits["uploader"]') + ->toContain("window.__inits[\"tomselect\"] = (() => { return 'application tomselect'; })();") + ->toContain("window.__inits[\"custom\"] = (() => { return 'application custom'; })();") + ->and(substr_count($build, 'window.__inits["tomselect"]'))->toBe(1); + } finally { + File::deleteDirectory($inits); + } +}); diff --git a/tests/Feature/Core/Components/TranslatableTest.php b/tests/Feature/Core/Components/TranslatableTest.php new file mode 100644 index 0000000..5d24fed --- /dev/null +++ b/tests/Feature/Core/Components/TranslatableTest.php @@ -0,0 +1,32 @@ +render(); + + expect($component->localesConfig) + ->toHaveKey('en.validation', 'required | email') + ->toHaveKey('ar.validation', 'email'); +}); + +test('validate locales controls only the required rule', function () { + $component = new Translatable( + validation: 'required|email|max:255', + locales: ['en', 'ar', 'fr'], + validateLocales: ['ar'], + ); + + $component->render(); + + expect($component->localesConfig) + ->toHaveKey('en.validation', 'email|max:255') + ->toHaveKey('ar.validation', 'required|email|max:255') + ->toHaveKey('fr.validation', 'email|max:255'); +}); diff --git a/tests/Feature/Core/ComponentsTest.php b/tests/Feature/Core/ComponentsTest.php new file mode 100644 index 0000000..bc7bbde --- /dev/null +++ b/tests/Feature/Core/ComponentsTest.php @@ -0,0 +1,88 @@ +put('toastify', [ + ['type' => 'success', 'title' => 'Saved', 'message' => null, 'options' => []], + ]); + + $html = Blade::render("@stack('plugins-scripts')"); + + expect($html) + ->toContain('/vendor/redot/plugins/redot-toasts.js') + ->toContain('new RedotToasts(') + ->toContain('"title":"Saved"') + ->and(session()->has('toastify'))->toBeFalse(); +}); + +it('lets an application view override a package component view', function () { + View::getFinder()->prependLocation(dirname(__DIR__, 2) . '/Fixtures/views'); + + expect(Blade::render(''))->toContain('application toasts'); +}); + +it('publishes every package asset under public/vendor/redot', function () { + $resolve = fn (string $provider) => collect(ServiceProvider::pathsToPublish($provider, 'redot::assets')) + ->mapWithKeys(fn ($target, $source) => [realpath($source) => $target]) + ->all(); + + expect($resolve(RedotServiceProvider::class))->toBe([ + realpath(dirname(__DIR__, 3) . '/src/Foundation/public') => public_path('vendor/redot'), + ])->and($resolve(DatatablesServiceProvider::class))->toBe([ + realpath(dirname(__DIR__, 3) . '/src/Datatables/public') => public_path('vendor/redot/datatables'), + ]); +}); + +it('replaces the published assets with the redot publish command', function () { + $published = public_path('vendor/redot'); + File::ensureDirectoryExists($published); + File::put($published . '/stale.js', 'stale'); + + try { + $this->artisan('redot:publish')->assertSuccessful(); + + expect($published . '/stale.js')->not->toBeFile() + ->and($published . '/plugins/redot-toasts.js')->toBeFile() + ->and($published . '/libraries/tom-select/tom-select.complete.min.js')->toBeFile() + ->and($published . '/datatables/datatables.js')->toBeFile(); + } finally { + File::deleteDirectory($published); + } +}); + +it('renders the redot styles in order with the current language direction', function () { + Language::create(['code' => 'ar', 'name' => 'Arabic', 'is_rtl' => true]); + app()->setLocale('ar'); + + $html = Blade::render("@push('plugins-styles')@endpush"); + + expect($html)->toContain('/vendor/redot/libraries/tabler/css/tabler.rtl.min.css') + ->and(strpos($html, 'overlayscrollbars.min.css'))->toBeLessThan(strpos($html, 'plugin.css')) + ->and(strpos($html, 'plugin.css'))->toBeLessThan(strpos($html, 'tabler-vendors.min.css')) + ->and(strpos($html, 'tabler-vendors.min.css'))->toBeLessThan(strpos($html, '/vendor/redot/css/redot.css')); +}); + +it('initializes widgets before restoring validation errors', function () { + View::share('errors', (new ViewErrorBag)->put('default', new MessageBag(['email' => ['Invalid']]))); + + $html = Blade::render(''); + + expect(strpos($html, '/vendor/redot/libraries/jquery/jquery.min.js'))->toBeLessThan(strpos($html, '/vendor/redot/js/functions.js')) + ->and(strpos($html, '/assets/dist/init.js'))->toBeLessThan(strpos($html, 'window.OldBag')) + ->and(strpos($html, '/vendor/redot/js/runtime.js'))->toBeLessThan(strpos($html, 'appendErrorsToForm($form, window.ErrorsBag)')); +}); + +it('skips the error restoration script when there are no errors', function () { + expect(Blade::render('')) + ->toContain('window.ErrorsBag') + ->not->toContain('appendErrorsToForm'); +}); diff --git a/tests/Feature/Core/Http/Middleware/EnsureDependenciesBuiltTest.php b/tests/Feature/Core/Http/Middleware/EnsureDependenciesBuiltTest.php index 9be35ea..76d155b 100644 --- a/tests/Feature/Core/Http/Middleware/EnsureDependenciesBuiltTest.php +++ b/tests/Feature/Core/Http/Middleware/EnsureDependenciesBuiltTest.php @@ -119,6 +119,32 @@ expect($response->getContent())->toBe('next'); }); +it('does not rebuild when a tracked file outside the application is current', function () { + $source = sys_get_temp_dir() . '/redot-outside-' . uniqid() . '.js'; + File::put($source, 'return () => {};'); + + File::put(dist_path('lock.json'), json_encode([ + 'files' => [ + $source => filemtime($source), + ], + 'directories' => [], + ])); + + Cache::shouldReceive('lock')->never(); + $artisan = Mockery::mock(); + $artisan->shouldReceive('call')->never(); + Artisan::swap($artisan); + + try { + (new EnsureDependenciesBuilt)->handle( + Request::create('/'), + fn () => new Response('next') + ); + } finally { + File::delete($source); + } +}); + it('clears the build output when a dependencies build is triggered', function () { File::ensureDirectoryExists(dist_path('translations')); File::put(dist_path('lock.json'), '{}'); diff --git a/tests/Feature/Core/ServiceProviderTest.php b/tests/Feature/Core/ServiceProviderTest.php index 489ce1b..6d6c05a 100644 --- a/tests/Feature/Core/ServiceProviderTest.php +++ b/tests/Feature/Core/ServiceProviderTest.php @@ -40,7 +40,7 @@ $html = ob_get_clean(); expect($html) - ->toContain('http://rendered.test/assets/js/themer.js') + ->toContain('http://rendered.test/vendor/redot/js/themer.js') ->not->toContain('compiled.test'); }); diff --git a/tests/Fixtures/views/components/toasts.blade.php b/tests/Fixtures/views/components/toasts.blade.php new file mode 100644 index 0000000..d545342 --- /dev/null +++ b/tests/Fixtures/views/components/toasts.blade.php @@ -0,0 +1 @@ +
application toasts
diff --git a/tests/Unit/Core/Jobs/ExtractLanguageTokensTest.php b/tests/Unit/Core/Jobs/ExtractLanguageTokensTest.php new file mode 100644 index 0000000..0a2964f --- /dev/null +++ b/tests/Unit/Core/Jobs/ExtractLanguageTokensTest.php @@ -0,0 +1,12 @@ + 'fr', 'name' => 'French', 'is_rtl' => false]); + + (new ExtractLanguageTokens($language))->handle(); + + expect($language->tokens()->where('key', 'Close')->exists())->toBeTrue(); +}); From 963c627a73f5f03ccce0cfee0f054ede6a8e60f3 Mon Sep 17 00:00:00 2001 From: Abdelrhman Said Date: Tue, 27 Oct 2026 22:52:35 +0300 Subject: [PATCH 03/12] feat: serve the component endpoints and shared helpers from core - Move the select search, uploader, and HugeRTE upload controllers into the package and register their global routes before the application's, so an application route with the same URI and name replaces the package one. - Add the is_dashboard_request() and current_sessions() helpers. --- docs/content/foundation/helpers.md | 4 + src/Foundation/routes/global.php | 13 ++ src/Foundation/src/Application.php | 6 +- .../Http/Controllers/HugeRteController.php | 28 ++++ .../src/Http/Controllers/SelectController.php | 132 ++++++++++++++++++ .../Http/Controllers/UploaderController.php | 121 ++++++++++++++++ .../src/utilities/authorization.php | 15 ++ src/Foundation/src/utilities/navigation.php | 17 +++ tests/Feature/Core/ApplicationTest.php | 5 +- 9 files changed, 338 insertions(+), 3 deletions(-) create mode 100644 src/Foundation/routes/global.php create mode 100644 src/Foundation/src/Http/Controllers/HugeRteController.php create mode 100644 src/Foundation/src/Http/Controllers/SelectController.php create mode 100644 src/Foundation/src/Http/Controllers/UploaderController.php diff --git a/docs/content/foundation/helpers.md b/docs/content/foundation/helpers.md index 534af1f..63a8f8a 100644 --- a/docs/content/foundation/helpers.md +++ b/docs/content/foundation/helpers.md @@ -42,6 +42,8 @@ {{ __('Back') }} ``` +- **`is_dashboard_request()`** — whether the current request belongs to the dashboard, including unmatched URLs (such as 404s) under the dashboard prefix. Useful in shared views like error pages. + ## Requests & API responses - **`throw_api_exception($e)`** — turn any caught exception into the standard JSON error envelope (mapping common exceptions to the right HTTP status). You rarely call this directly — it is wired in as the global JSON exception renderer. See [Controllers & API Responses](/foundation/controllers-and-responses). @@ -54,6 +56,8 @@ } ``` +- **`current_sessions('admins')`** — the active browser sessions of the account signed in on the given guard, newest first. Returns an empty collection unless the `database` session driver is used. + - **`is_mobile()` / `is_desktop()`** — detect the device from the request's user agent. Both return `false` safely when there is no request (e.g. console). ```php diff --git a/src/Foundation/routes/global.php b/src/Foundation/routes/global.php new file mode 100644 index 0000000..f0b2e8a --- /dev/null +++ b/src/Foundation/routes/global.php @@ -0,0 +1,13 @@ +name('hugerte.upload'); + +Route::get('tomselect/search', [SelectController::class, 'index'])->name('select.search'); +Route::get('tomselect/fetch', [SelectController::class, 'show'])->name('select.fetch'); + +Route::post('uploader/upload', [UploaderController::class, 'store'])->name('uploader.upload'); diff --git a/src/Foundation/src/Application.php b/src/Foundation/src/Application.php index b6a8617..88530f4 100644 --- a/src/Foundation/src/Application.php +++ b/src/Foundation/src/Application.php @@ -44,8 +44,10 @@ public static function configure(?string $basePath = null): ApplicationBuilder } }); - // Load the global routes - Route::as('global.')->middleware(['web', Localization::class . ':website'])->group(base_path('routes/global.php')); + // Load the package and application global routes, so the application can override package routes + foreach ([__DIR__ . '/../routes/global.php', base_path('routes/global.php')] as $routes) { + Route::as('global.')->middleware(['web', Localization::class . ':website'])->group($routes); + } // Load the website and dashboard routes $group = Route::middleware('web'); diff --git a/src/Foundation/src/Http/Controllers/HugeRteController.php b/src/Foundation/src/Http/Controllers/HugeRteController.php new file mode 100644 index 0000000..8426a15 --- /dev/null +++ b/src/Foundation/src/Http/Controllers/HugeRteController.php @@ -0,0 +1,28 @@ +validate([ + 'file' => 'required|image', + ]); + + $url = $this->uploadFile(request()->file('file'), 'hugerte'); + + return response()->json([ + 'location' => $url, + ]); + } +} diff --git a/src/Foundation/src/Http/Controllers/SelectController.php b/src/Foundation/src/Http/Controllers/SelectController.php new file mode 100644 index 0000000..f09ca7c --- /dev/null +++ b/src/Foundation/src/Http/Controllers/SelectController.php @@ -0,0 +1,132 @@ +validate([ + 'data' => 'required', + 'term' => 'nullable|string', + 'limit' => 'nullable|integer|min:1|max:100', + 'parameters' => 'nullable|array', + ]); + + $data = json_decode(decrypt($request->data)); + $term = trim($request->query('term', '')); + $limit = (int) $request->query('limit', 20); + + // Merge the parameters with the term. + $parameters = array_merge($request->query('parameters', []), [$data->term => $term]); + $parameters = collect($parameters)->mapWithKeys(fn ($value, $key) => [sprintf('{%s}', $key) => $value])->toArray(); + $bindings = str_replace(array_keys($parameters), array_values($parameters), $data->bindings ?? []); + + // Prepare the query. + $query = $data->query . " limit $limit"; + + $items = $this->prepareResults(DB::select($query, $bindings), $data); + + return $this->respond([ + 'data' => $items, + 'count' => count($items), + ]); + } + + /** + * Display the specified resource. + */ + public function show(Request $request) + { + $request->validate([ + 'data' => 'required', + 'ids' => 'required|string', + 'parameters' => 'nullable|array', + ]); + + $data = json_decode(decrypt($request->data)); + $ids = array_values(array_filter(parse_csv($request->query('ids')), fn ($id) => filled($id))); + + if (blank($ids)) { + return $this->respond([ + 'data' => [], + 'count' => 0, + ]); + } + + $uniqid = uniqid('cte_'); + $key = $data->key; + + // Merge the parameters with the term. + $parameters = array_merge($request->query('parameters', []), [$data->term => '']); + $parameters = collect($parameters)->mapWithKeys(fn ($value, $key) => [sprintf('{%s}', $key) => $value])->toArray(); + $bindings = str_replace(array_keys($parameters), array_values($parameters), $data->bindings ?? []); + $bindings = array_values((array) $bindings); + + // Prepare the query. + $placeholders = implode(',', array_fill(0, count($ids), '?')); + $query = "select $key from ($data->query) as $uniqid where $uniqid.$key in ($placeholders)"; + $bindings = [...$bindings, ...$ids]; + + $items = $this->prepareResults(DB::select($query, $bindings), $data); + + return $this->respond([ + 'data' => $items, + 'count' => count($items), + ]); + } + + /** + * Prepare the results to be returned. + */ + protected function prepareResults(array $items, $data): array + { + $model = $data->model; + $columns = array_merge($data->columns, $data->appends ?? []); + + $relations = []; + foreach ($columns as $column) { + $relations = array_merge($relations, $this->extractRelations($column)); + } + + $items = array_column($items, $data->key); + $items = $model::whereIn($data->key, $items)->with(array_unique($relations))->get(); + + // Map the items to the required format. + $items = $items->map(function ($item) use ($data, $columns) { + $arr = $item->toArray(); + $arr = Arr::only(Arr::dot($arr), $columns); + + return array_merge([ + '__value' => Arr::get($arr, $data->key), + '__text' => Arr::get($arr, $data->text), + '__html' => $data->template ? view($data->template, ['item' => $item])->render() : '', + ], $arr); + }); + + return $items->toArray(); + } + + /** + * Extract relations from the column. + */ + protected function extractRelations($column) + { + $relations = explode('.', $column); + + // Remove the last element. + array_pop($relations); + + return $relations; + } +} diff --git a/src/Foundation/src/Http/Controllers/UploaderController.php b/src/Foundation/src/Http/Controllers/UploaderController.php new file mode 100644 index 0000000..7d3f82a --- /dev/null +++ b/src/Foundation/src/Http/Controllers/UploaderController.php @@ -0,0 +1,121 @@ +validate([ + 'file' => 'required|file', + 'config' => 'required|string', + ]); + + $config = json_decode(decrypt($request->config)); + + // If config is null, return an error to prevent unauthorized access + if ($config === null) { + throw ValidationException::withMessages([ + 'config' => [__('Unauthorized access.')], + ]); + } + + $file = $request->file('file'); + + // Set the locale + if ($config->locale) { + app()->setLocale($config->locale); + } + + // Validate the file type + if ($config->accept) { + $this->validateFileType($file, $config->accept); + } + + // Run the server validation + if ($config->serverValidation) { + $request->validate(['file' => $config->serverValidation]); + } + + // Get the path to store the file + $url = $this->uploadFile($file, $config->directory, $config->optimize); + $path = str_replace(URL::to('/'), '', $url); + + // Fix for windows directory separator + $path = str_replace(['/', '\\'], DIRECTORY_SEPARATOR, $path); + + $payload = [ + 'url' => $url, + 'path' => $path, + 'size' => filesize(public_path($path)), + ]; + + if ($config->thumbnail && is_image(public_path($path))) { + try { + $payload['thumbnail'] = create_thumbnail(public_path($path)); + } catch (\Exception $e) { + $payload['thumbnail'] = null; + } + } + + return $this->respond($payload); + } + + /** + * Validate file type based on accept parameter. + */ + protected function validateFileType(UploadedFile $file, string $accept) + { + $acceptedTypes = parse_csv($accept); + $fileMimeType = $file->getMimeType(); + $fileExtension = '.' . strtolower($file->getClientOriginalExtension()); + + $isValid = false; + + foreach ($acceptedTypes as $type) { + // Check wildcard accept all + if ($type === '*' || $type === '*/*') { + $isValid = true; + break; + } + + // Check file extension + if (str_starts_with($type, '.')) { + if (strtolower($type) === $fileExtension) { + $isValid = true; + break; + } + } elseif (str_ends_with($type, '/*')) { + $category = str_replace('/*', '', $type); + if (str_starts_with($fileMimeType, $category . '/')) { + $isValid = true; + break; + } + } else { + if ($fileMimeType === $type) { + $isValid = true; + break; + } + } + } + + if (! $isValid) { + throw ValidationException::withMessages([ + 'file' => [__('The file type is not allowed. Accepted types: :types', ['types' => $accept])], + ]); + } + } +} diff --git a/src/Foundation/src/utilities/authorization.php b/src/Foundation/src/utilities/authorization.php index 9a6cbc9..baf1ddc 100644 --- a/src/Foundation/src/utilities/authorization.php +++ b/src/Foundation/src/utilities/authorization.php @@ -2,6 +2,7 @@ use Illuminate\Auth\Middleware\Authenticate; use Illuminate\Routing\Route as RoutingRoute; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Request; use Illuminate\Support\Facades\Route; @@ -78,3 +79,17 @@ function url_allowed(string $url, ?string $guard = null): bool return route_allowed(route_from_url($url) ?: '', $guard); } + +/** + * Get the active browser sessions for the current account on the given guard. + */ +function current_sessions(string $guard): Collection +{ + if (config('session.driver') !== 'database' || ! $user = auth($guard)->user()) { + return collect(); + } + + return $user->sessions()->wherePivot('guard', $guard) + ->where('last_activity', '>=', now()->subMinutes(config('session.lifetime'))->timestamp) + ->orderByDesc('last_activity')->get(); +} diff --git a/src/Foundation/src/utilities/navigation.php b/src/Foundation/src/utilities/navigation.php index 9951ecf..f361d35 100644 --- a/src/Foundation/src/utilities/navigation.php +++ b/src/Foundation/src/utilities/navigation.php @@ -38,3 +38,20 @@ function back_or_route(string $route, mixed $parameters = [], bool $absolute = t return $sameOrigin && $insideApp ? $url : $route; } + +/** + * Determine whether the current request belongs to the dashboard scope. + */ +function is_dashboard_request(): bool +{ + if (request()->routeIs('dashboard.*')) { + return true; + } + + // Unmatched requests (e.g. 404s) carry no dashboard route, so compare the + // URL against the dashboard root, which already reflects the configured + // prefix and the current locale. + $root = route('dashboard.index'); + + return url()->current() === $root || str_starts_with(url()->current(), "{$root}/"); +} diff --git a/tests/Feature/Core/ApplicationTest.php b/tests/Feature/Core/ApplicationTest.php index 278b90c..e871cc0 100644 --- a/tests/Feature/Core/ApplicationTest.php +++ b/tests/Feature/Core/ApplicationTest.php @@ -33,7 +33,10 @@ expect(app()->runningUnitTests())->toBe($environment === 'testing') ->and(config("redot.features.{$feature}.enabled"))->toBe($expected) ->and(Route::has($route))->toBe($expected) - ->and(Route::has('global.index'))->toBeTrue(); + ->and(Route::has('global.index'))->toBeTrue() + ->and(Route::has('global.select.search'))->toBeTrue() + ->and(Route::has('global.uploader.upload'))->toBeTrue() + ->and(Route::has('global.hugerte.upload'))->toBeTrue(); } finally { $this->app['env'] = $originalEnvironment; Container::setInstance($this->app); From a6476453f18ad470b0ec895399733e01a7c691ef Mon Sep 17 00:00:00 2001 From: Abdelrhman Said Date: Tue, 27 Oct 2026 22:52:51 +0300 Subject: [PATCH 04/12] feat(config): make route files, layouts, and the dashboard guard configurable - Add redot.paths for the application route files and the layouts directory and namespace. - Add redot.features.dashboard.guard and use it wherever the sidebar, route_guard(), route_allowed(), and permissions:sync assumed "admins". - Build the dashboard root for is_dashboard_request() from the configured prefix instead of requiring a dashboard.index route. --- docs/content/architecture/configuration.md | 11 ++++++- docs/content/foundation/helpers.md | 2 +- src/Foundation/config/redot.php | 27 +++++++++++++++++ src/Foundation/src/Application.php | 10 +++---- .../src/Commands/SyncPermissionsCommand.php | 5 ++-- src/Foundation/src/RedotServiceProvider.php | 4 +-- .../src/utilities/authorization.php | 6 ++-- src/Foundation/src/utilities/navigation.php | 7 +++-- src/Sidebar/src/Sidebar.php | 8 ++--- tests/Feature/Core/ApplicationTest.php | 27 +++++++++++++++++ tests/Feature/Core/ServiceProviderTest.php | 13 ++++++++ .../Application/routes/custom/website.php | 5 ++++ tests/Fixtures/layouts/fixture.blade.php | 1 + tests/Unit/Core/HelpersTest.php | 30 +++++++++++++++++++ tests/Unit/Packages/Sidebar/ItemTest.php | 7 +++++ 15 files changed, 142 insertions(+), 21 deletions(-) create mode 100644 tests/Fixtures/Application/routes/custom/website.php create mode 100644 tests/Fixtures/layouts/fixture.blade.php diff --git a/docs/content/architecture/configuration.md b/docs/content/architecture/configuration.md index df4e9a4..f45e2ba 100644 --- a/docs/content/architecture/configuration.md +++ b/docs/content/architecture/configuration.md @@ -15,7 +15,7 @@ The config is merged at runtime, so every key is readable without publishing. Pu `redot.features` toggles the four mountable surfaces and, where relevant, their URL prefix. The package reads these flags both when registering routes and to conditionally render UI (e.g. hiding a "Preview website" link). - **`website`** — mounts the public website routes. Set `enabled` to turn it on or off. -- **`dashboard`** — mounts the back-office routes. `enabled` toggles it; `prefix` sets the URL segment it lives under (default `dashboard`). +- **`dashboard`** — mounts the back-office routes. `enabled` toggles it; `prefix` sets the URL segment it lives under (default `dashboard`); `guard` names the auth guard dashboard users sign in with (default `admins`). The sidebar, `route_allowed()`, and `permissions:sync` fall back to this guard when a route doesn't name one. - **`website-api`** — mounts the public website API routes under `api/`. Set `enabled` to toggle it. - **`dashboard-api`** — mounts the dashboard API routes. `enabled` toggles it; `prefix` sets the segment under `api/` (default `dashboard`). @@ -43,6 +43,15 @@ Once languages exist in the database, the active locale list is built from them, - **`append_locale_to_url`** — when on, the website/dashboard routes are prefixed with a two-letter `{locale}` segment. Turn it off to serve those routes without a locale segment. - **`redirect_non_locale_urls`** — when on, a request to a non-prefixed URL is redirected to its locale-prefixed equivalent (preserving the query string). When off, such URLs return a 404 instead. +## Paths + +`redot.paths` tells core where your application keeps the files it loads by convention. Paths are relative to the application base path. + +- **`routes`** — the `global`, `website`, `dashboard`, `website-api`, and `dashboard-api` route files. Core registers its own global routes (select search, uploads) before yours, so a route in your global file with the same URI and name replaces the package one. +- **`layouts.path`** / **`layouts.namespace`** — where `` finds anonymous layout views and layout classes. + +When you change one path, copy the whole `paths` block into your config: Laravel merges package config only at the top level, so a partial block leaves the other paths undefined. + ## Permissions `redot.permissions` controls local development shortcuts around route gating. diff --git a/docs/content/foundation/helpers.md b/docs/content/foundation/helpers.md index 63a8f8a..b446bef 100644 --- a/docs/content/foundation/helpers.md +++ b/docs/content/foundation/helpers.md @@ -20,7 +20,7 @@ ## URLs & routing -- **`route_allowed('route.name')`** — whether the current admin may access a named route. Use it to show/hide permission-gated UI. It applies the same conventional and explicit permission aliases as route middleware. Routes that opt out of permission middleware are allowed; protected routes defer to the gate. The guard is guessed from the route's `auth` middleware (falling back to `admins`); pass one explicitly as the second argument to override. See [Datatables](/packages/datatables/overview) for the common use. +- **`route_allowed('route.name')`** — whether the current admin may access a named route. Use it to show/hide permission-gated UI. It applies the same conventional and explicit permission aliases as route middleware. Routes that opt out of permission middleware are allowed; protected routes defer to the gate. The guard is guessed from the route's `auth` middleware (falling back to `redot.features.dashboard.guard`); pass one explicitly as the second argument to override. See [Datatables](/packages/datatables/overview) for the common use. ```php Action::edit('posts.edit')->visible(route_allowed('posts.edit')); diff --git a/src/Foundation/config/redot.php b/src/Foundation/config/redot.php index ff529a4..7a76050 100644 --- a/src/Foundation/config/redot.php +++ b/src/Foundation/config/redot.php @@ -33,6 +33,7 @@ 'dashboard' => [ 'enabled' => true, 'prefix' => 'dashboard', + 'guard' => 'admins', ], ], @@ -73,6 +74,32 @@ 'redirect_non_locale_urls' => true, ], + /* + |-------------------------------------------------------------------------- + | Paths + |-------------------------------------------------------------------------- + | + | Application files Redot loads by convention. Route files and the layouts + | path are relative to the application base path. When overriding, copy + | the whole block so no path is left undefined. + | + */ + + 'paths' => [ + 'routes' => [ + 'global' => 'routes/global.php', + 'website' => 'routes/website.php', + 'dashboard' => 'routes/dashboard.php', + 'website-api' => 'routes/api/website.php', + 'dashboard-api' => 'routes/api/dashboard.php', + ], + + 'layouts' => [ + 'path' => 'resources/layouts', + 'namespace' => 'App\\View\\Layouts', + ], + ], + /* |-------------------------------------------------------------------------- | Permissions diff --git a/src/Foundation/src/Application.php b/src/Foundation/src/Application.php index 88530f4..06f8b91 100644 --- a/src/Foundation/src/Application.php +++ b/src/Foundation/src/Application.php @@ -36,16 +36,16 @@ public static function configure(?string $basePath = null): ApplicationBuilder // Load the API routes for the website and dashboard Route::middleware('api')->as('api.')->prefix('api')->group(function () { if (config('redot.features.website-api.enabled')) { - Route::as('website.')->group(base_path('routes/api/website.php')); + Route::as('website.')->group(base_path(config('redot.paths.routes.website-api'))); } if (config('redot.features.dashboard-api.enabled')) { - Route::as('dashboard.')->prefix(config('redot.features.dashboard-api.prefix'))->middleware(RoutePermission::class)->group(base_path('routes/api/dashboard.php')); + Route::as('dashboard.')->prefix(config('redot.features.dashboard-api.prefix'))->middleware(RoutePermission::class)->group(base_path(config('redot.paths.routes.dashboard-api'))); } }); // Load the package and application global routes, so the application can override package routes - foreach ([__DIR__ . '/../routes/global.php', base_path('routes/global.php')] as $routes) { + foreach ([__DIR__ . '/../routes/global.php', base_path(config('redot.paths.routes.global'))] as $routes) { Route::as('global.')->middleware(['web', Localization::class . ':website'])->group($routes); } @@ -61,11 +61,11 @@ public static function configure(?string $basePath = null): ApplicationBuilder $group->group(function () { if (config('redot.features.website.enabled')) { - Route::as('website.')->middleware(Localization::class . ':website')->group(base_path('routes/website.php')); + Route::as('website.')->middleware(Localization::class . ':website')->group(base_path(config('redot.paths.routes.website'))); } if (config('redot.features.dashboard.enabled')) { - Route::as('dashboard.')->prefix(config('redot.features.dashboard.prefix'))->middleware('dashboard')->group(base_path('routes/dashboard.php')); + Route::as('dashboard.')->prefix(config('redot.features.dashboard.prefix'))->middleware('dashboard')->group(base_path(config('redot.paths.routes.dashboard'))); } }); diff --git a/src/Foundation/src/Commands/SyncPermissionsCommand.php b/src/Foundation/src/Commands/SyncPermissionsCommand.php index 2b85450..f44de45 100644 --- a/src/Foundation/src/Commands/SyncPermissionsCommand.php +++ b/src/Foundation/src/Commands/SyncPermissionsCommand.php @@ -171,13 +171,14 @@ protected function resolveGrantee(string $grant): ?Model } /** - * Resolve the eloquent model behind the admins guard. + * Resolve the eloquent model behind the dashboard guard. * * @return class-string */ protected function adminModel(): string { - $provider = config('auth.guards.admins.provider', 'admins'); + $guard = config('redot.features.dashboard.guard'); + $provider = config("auth.guards.{$guard}.provider", $guard); return config("auth.providers.{$provider}.model"); } diff --git a/src/Foundation/src/RedotServiceProvider.php b/src/Foundation/src/RedotServiceProvider.php index 7241bed..f55e21b 100644 --- a/src/Foundation/src/RedotServiceProvider.php +++ b/src/Foundation/src/RedotServiceProvider.php @@ -232,8 +232,8 @@ protected function configureAboutCommand(): void */ protected function configureBlade(): void { - Blade::anonymousComponentPath(resource_path('layouts'), 'layouts'); - Blade::componentNamespace('App\\View\\Layouts', 'layouts'); + Blade::anonymousComponentPath(base_path(config('redot.paths.layouts.path')), 'layouts'); + Blade::componentNamespace(config('redot.paths.layouts.namespace'), 'layouts'); // Package views resolve after the application's, so a same-named view overrides them. View::addLocation(__DIR__ . '/../resources'); diff --git a/src/Foundation/src/utilities/authorization.php b/src/Foundation/src/utilities/authorization.php index baf1ddc..654db49 100644 --- a/src/Foundation/src/utilities/authorization.php +++ b/src/Foundation/src/utilities/authorization.php @@ -27,7 +27,7 @@ function route_from_url(string $url): ?string /** * Resolve the guard a route authenticates against. */ -function route_guard(RoutingRoute $route, string $default = 'admins'): string +function route_guard(RoutingRoute $route, ?string $default = null): string { foreach (Route::gatherRouteMiddleware($route) as $middleware) { if (is_string($middleware) && str($middleware)->startsWith(Authenticate::class . ':')) { @@ -35,7 +35,7 @@ function route_guard(RoutingRoute $route, string $default = 'admins'): string } } - return $default; + return $default ?? config('redot.features.dashboard.guard'); } /** @@ -46,7 +46,7 @@ function route_allowed(RoutingRoute|string $route, ?string $guard = null): bool $registeredRoute = PermissionNameResolver::route($route); // Guess the guard from the route's auth middleware when none is given - $guard ??= $registeredRoute ? route_guard($registeredRoute) : 'admins'; + $guard ??= $registeredRoute ? route_guard($registeredRoute) : config('redot.features.dashboard.guard'); if (! auth($guard)->check()) { return false; diff --git a/src/Foundation/src/utilities/navigation.php b/src/Foundation/src/utilities/navigation.php index f361d35..ce432a2 100644 --- a/src/Foundation/src/utilities/navigation.php +++ b/src/Foundation/src/utilities/navigation.php @@ -49,9 +49,10 @@ function is_dashboard_request(): bool } // Unmatched requests (e.g. 404s) carry no dashboard route, so compare the - // URL against the dashboard root, which already reflects the configured - // prefix and the current locale. - $root = route('dashboard.index'); + // URL against the dashboard root built from the configured prefix and, + // when locales are part of the URL, the current locale. + $prefix = config('redot.features.dashboard.prefix'); + $root = url(config('redot.routing.append_locale_to_url') ? app()->getLocale() . '/' . $prefix : $prefix); return url()->current() === $root || str_starts_with(url()->current(), "{$root}/"); } diff --git a/src/Sidebar/src/Sidebar.php b/src/Sidebar/src/Sidebar.php index 4a89c9d..e2c0ba0 100644 --- a/src/Sidebar/src/Sidebar.php +++ b/src/Sidebar/src/Sidebar.php @@ -19,21 +19,21 @@ class Sidebar /** * Sidebar guard. */ - public string $guard = 'admins'; + public string $guard; /** * Create a new sidebar instance. */ - public function __construct(array $items = [], string $guard = 'admins') + public function __construct(array $items = [], ?string $guard = null) { $this->items = $items; - $this->guard = $guard; + $this->guard = $guard ?? config('redot.features.dashboard.guard'); } /** * Create a new sidebar instance statically. */ - public static function make(array $items = [], string $guard = 'admins'): static + public static function make(array $items = [], ?string $guard = null): static { return new static($items, $guard); } diff --git a/tests/Feature/Core/ApplicationTest.php b/tests/Feature/Core/ApplicationTest.php index e871cc0..6b2c521 100644 --- a/tests/Feature/Core/ApplicationTest.php +++ b/tests/Feature/Core/ApplicationTest.php @@ -54,3 +54,30 @@ 'feature configuration tests' => [false, 'testing'], 'production' => [true, 'production'], ]); + +it('loads the application route files from the configured paths', function () { + $basePath = $this->app->basePath(); + $routes = Route::getRoutes(); + $property = new ReflectionProperty(RouteServiceProvider::class, 'alwaysLoadRoutesUsing'); + $original = $property->getValue(); + + try { + Application::configure(dirname(__DIR__, 2) . '/Fixtures/Application'); + $registerRoutes = $property->getValue(); + Container::setInstance($this->app); + $this->app->setBasePath(dirname(__DIR__, 2) . '/Fixtures/Application'); + Route::setRoutes(new RouteCollection); + config(['redot.paths.routes.website' => 'routes/custom/website.php']); + + $registerRoutes(); + Route::getRoutes()->refreshNameLookups(); + + expect(Route::has('website.custom'))->toBeTrue() + ->and(Route::has('website.index'))->toBeFalse(); + } finally { + Container::setInstance($this->app); + $this->app->setBasePath($basePath); + Route::setRoutes($routes); + RouteServiceProvider::loadRoutesUsing($original); + } +}); diff --git a/tests/Feature/Core/ServiceProviderTest.php b/tests/Feature/Core/ServiceProviderTest.php index 6d6c05a..b740843 100644 --- a/tests/Feature/Core/ServiceProviderTest.php +++ b/tests/Feature/Core/ServiceProviderTest.php @@ -16,6 +16,19 @@ ->and(config('redot.locales'))->toHaveCount(2); }); +it('registers layout components from the configured path and namespace', function () { + app()->setBasePath(dirname(__DIR__, 3)); + config()->set('redot.paths.layouts', [ + 'path' => 'tests/Fixtures/layouts', + 'namespace' => 'Tests\\Fixtures\\Layouts', + ]); + + app()->register(RedotServiceProvider::class, force: true); + + expect(Blade::render(''))->toContain('fixture layout') + ->and(Blade::getClassComponentNamespaces())->toHaveKey('layouts', 'Tests\\Fixtures\\Layouts'); +}); + it('uses the package pagination view as the paginator default', function () { expect(Paginator::$defaultView)->toBe('components.pagination'); }); diff --git a/tests/Fixtures/Application/routes/custom/website.php b/tests/Fixtures/Application/routes/custom/website.php new file mode 100644 index 0000000..9bfa617 --- /dev/null +++ b/tests/Fixtures/Application/routes/custom/website.php @@ -0,0 +1,5 @@ + 'custom')->name('custom'); diff --git a/tests/Fixtures/layouts/fixture.blade.php b/tests/Fixtures/layouts/fixture.blade.php new file mode 100644 index 0000000..3231cd9 --- /dev/null +++ b/tests/Fixtures/layouts/fixture.blade.php @@ -0,0 +1 @@ +
fixture layout
diff --git a/tests/Unit/Core/HelpersTest.php b/tests/Unit/Core/HelpersTest.php index deda42f..95d4a4a 100644 --- a/tests/Unit/Core/HelpersTest.php +++ b/tests/Unit/Core/HelpersTest.php @@ -235,3 +235,33 @@ 'path sharing the base prefix' => ['https://app.com/admin', 'https://app.com/administrator'], 'path outside the base path' => ['https://app.com/admin', 'https://app.com/other'], ]); + +it('falls back to the configured dashboard guard for routes without auth middleware', function () { + config(['redot.features.dashboard.guard' => 'staff']); + + $guarded = Route::get('/guard-test/guarded', fn () => 'ok')->middleware('auth:admins'); + $open = Route::get('/guard-test/open', fn () => 'ok'); + + expect(route_guard($guarded))->toBe('admins') + ->and(route_guard($open))->toBe('staff') + ->and(route_guard($open, 'users'))->toBe('users'); +}); + +it('detects unmatched dashboard urls from the configured prefix without a dashboard route', function (bool $appendLocale, string $url, bool $expected) { + config([ + 'redot.features.dashboard.prefix' => 'admin', + 'redot.routing.append_locale_to_url' => $appendLocale, + ]); + app()->setLocale('en'); + + $this->get($url); + + expect(Route::has('dashboard.index'))->toBeFalse() + ->and(is_dashboard_request())->toBe($expected); +})->with([ + 'localized dashboard url' => [true, '/en/admin/missing', true], + 'localized dashboard root' => [true, '/en/admin', true], + 'localized website url' => [true, '/en/administrator', false], + 'unlocalized dashboard url' => [false, '/admin/missing', true], + 'unlocalized website url' => [false, '/missing', false], +]); diff --git a/tests/Unit/Packages/Sidebar/ItemTest.php b/tests/Unit/Packages/Sidebar/ItemTest.php index 425aa2c..c31c02b 100644 --- a/tests/Unit/Packages/Sidebar/ItemTest.php +++ b/tests/Unit/Packages/Sidebar/ItemTest.php @@ -110,3 +110,10 @@ expect($items)->toHaveCount(1) ->and($items[0]->title)->toBe('Website'); }); + +it('uses the configured dashboard guard unless one is given', function () { + config(['redot.features.dashboard.guard' => 'staff']); + + expect(Sidebar::make()->guard)->toBe('staff') + ->and(Sidebar::make([], 'admins')->guard)->toBe('admins'); +}); From 8e335ea9904b1e4d264a007e501be810a77348aa Mon Sep 17 00:00:00 2001 From: Abdelrhman Said Date: Tue, 27 Oct 2026 22:53:08 +0300 Subject: [PATCH 05/12] refactor(config): merge the datatables and toastify config into the redot config Datatables and Toastify now read their settings from the datatables and toastify keys of config/redot.php, so a project has one Redot config file. The remaining datatables publish tags move under redot:: as redot::datatables-views and redot::datatables-lang. --- docs/content/architecture/configuration.md | 10 +- docs/content/getting-started/installation.md | 7 +- docs/content/packages/datatables/export.md | 12 +-- docs/content/packages/datatables/frontend.md | 4 +- docs/content/packages/toastify.md | 4 +- src/Datatables/config/datatables.php | 52 ---------- .../resources/views/datatable.blade.php | 4 +- src/Datatables/src/Datatable.php | 8 +- .../src/DatatablesServiceProvider.php | 16 +--- .../src/Exporters/ExportManager.php | 2 +- src/Foundation/config/redot.php | 95 +++++++++++++++++++ src/Foundation/src/View/Components/Toasts.php | 2 +- src/Toastify/config/toastify.php | 50 ---------- .../src/LaravelToastifyServiceProvider.php | 12 --- src/Toastify/src/Toastify.php | 2 +- .../Packages/Datatables/ExportTest.php | 12 +++ tests/Unit/Packages/Toastify/ToastifyTest.php | 8 ++ 17 files changed, 148 insertions(+), 152 deletions(-) delete mode 100644 src/Datatables/config/datatables.php delete mode 100644 src/Toastify/config/toastify.php diff --git a/docs/content/architecture/configuration.md b/docs/content/architecture/configuration.md index f45e2ba..bed8a8e 100644 --- a/docs/content/architecture/configuration.md +++ b/docs/content/architecture/configuration.md @@ -1,6 +1,6 @@ # Configuration -`config/redot.php` is the single configuration file for `redot/core`. It controls which application surfaces are mounted, the locales the app supports, and locale-aware routing. Its values are available as `config('redot.*')` out of the box. Runtime-editable settings are defined separately in `app/settings.php`. +`config/redot.php` is the single configuration file for `redot/core`. It controls which application surfaces are mounted, the locales the app supports, locale-aware routing, and the bundled packages (Datatables and Toastify). Its values are available as `config('redot.*')` out of the box. Runtime-editable settings are defined separately in `app/settings.php`. ## Publishing the config @@ -52,6 +52,14 @@ Once languages exist in the database, the active locale list is built from them, When you change one path, copy the whole `paths` block into your config: Laravel merges package config only at the top level, so a partial block leaves the other paths undefined. +## Datatables + +`redot.datatables` configures the [Datatables](/packages/datatables/overview) package: `assets` holds the CSS/JS paths the table loads, and `export` lists each export format with its `enabled` flag and exporter class (plus the template, adapter, and engine options for [PDF](/packages/datatables/export)). + +## Toastify + +`redot.toastify` configures [Toastify](/packages/toastify): `toastifiers` maps each toast type to its icon and color, and `defaults` sets the position, delay, and close button applied to every toast. + ## Permissions `redot.permissions` controls local development shortcuts around route gating. diff --git a/docs/content/getting-started/installation.md b/docs/content/getting-started/installation.md index da7a588..daa145b 100644 --- a/docs/content/getting-started/installation.md +++ b/docs/content/getting-started/installation.md @@ -53,11 +53,10 @@ php artisan migrate ## Sub-package publish tags -The bundled packages expose their own tags, all following the `package::resource` convention. Their config, views, lang, and routes load automatically; publish only to override. +The bundled packages share the Redot configuration and publish tags: their settings live in `config/redot.php` (under `datatables` and `toastify`), and their assets are published by `php artisan redot:publish`. Views and translations load automatically; publish only to override. -- **Datatables** — `datatables::config`, `datatables::views`, `datatables::lang`. Its CSS/JS are published with the rest of the Redot assets by `php artisan redot:publish`. See [Datatables](/packages/datatables/overview). -- **Toastify** — `toastify::config`. See [Toastify](/packages/toastify). -- **Auth, Sidebar, LangExtractor** — nothing to publish; they are wired up for you. +- **Datatables** — `redot::datatables-views`, `redot::datatables-lang`. See [Datatables](/packages/datatables/overview). +- **Toastify, Auth, Sidebar, LangExtractor** — nothing extra to publish; they are wired up for you. ## Publish everything at once diff --git a/docs/content/packages/datatables/export.md b/docs/content/packages/datatables/export.md index 9c5a1cc..64248a1 100644 --- a/docs/content/packages/datatables/export.md +++ b/docs/content/packages/datatables/export.md @@ -4,10 +4,10 @@ Every datatable can offer an export menu so users download the current dataset. ## Enabling PDF export -PDF is configured in `config/datatables.php` under the `export` block. Publish the config first: +PDF is configured under `datatables.export` in `config/redot.php`. Publish the Redot config first if you haven't: ```bash -php artisan vendor:publish --tag=datatables::config +php artisan vendor:publish --tag=redot::config ``` PDF export needs a rendering library installed. The default uses mPDF — install it and you're done: @@ -20,7 +20,7 @@ If the export menu offers PDF but the library isn't installed, the export fails ## Options -Configure these under `export.pdf` in `config/datatables.php`: +Configure these under `datatables.export.pdf` in `config/redot.php`: - **`enabled`** — whether PDF appears among the table's export choices. - **`template`** — the Blade view rendered into the PDF. Defaults to the packaged template; point it at your own for a custom layout. @@ -38,7 +38,7 @@ composer require barryvdh/laravel-dompdf ``` ```php -// config/datatables.php +// config/redot.php — datatables.export.pdf 'adapter' => \Redot\Datatables\Adapters\PDF\DomPdf::class, ``` @@ -76,14 +76,14 @@ Set `template` to your own Blade view. Your template receives `$headings` (an ar ``` ```php -// config/datatables.php +// config/redot.php — datatables.export.pdf 'template' => 'templates.pdf.datatable', ``` To tweak the packaged template instead of replacing it, publish the views and edit your copy: ```bash -php artisan vendor:publish --tag=datatables::views +php artisan vendor:publish --tag=redot::datatables-views ``` ### Per-table overrides diff --git a/docs/content/packages/datatables/frontend.md b/docs/content/packages/datatables/frontend.md index e159bf5..a11b3f7 100644 --- a/docs/content/packages/datatables/frontend.md +++ b/docs/content/packages/datatables/frontend.md @@ -79,10 +79,10 @@ Publish the package's views or translations to override them: ```bash # Blade views -> resources/views/vendor/datatables -php artisan vendor:publish --tag=datatables::views +php artisan vendor:publish --tag=redot::datatables-views # Translations -> lang/vendor/datatables -php artisan vendor:publish --tag=datatables::lang +php artisan vendor:publish --tag=redot::datatables-lang ``` All built-in labels, placeholders, and messages are localizable through the published translation files. diff --git a/docs/content/packages/toastify.md b/docs/content/packages/toastify.md index 43585d2..cf2f352 100644 --- a/docs/content/packages/toastify.md +++ b/docs/content/packages/toastify.md @@ -76,10 +76,10 @@ toastify().success('Saved', 'Your changes were saved.', { delay: 5000 }); ## Customizing toast types -The available types and their styling live in `config/toastify.php`. Publish it to add or restyle types: +The available types and their styling live under the `toastify` key of `config/redot.php`. Publish the Redot config if you haven't already, then add or restyle types there: ```bash -php artisan vendor:publish --tag=toastify::config +php artisan vendor:publish --tag=redot::config ``` - **`toastifiers`** — the map of toast types. Out of the box: `toast`, `error`, `success`, `info`, and `warning`, each with an icon and optional icon color. Add a key here to create a new type — it becomes callable as `toastify()->yourType(...)` and from JavaScript. diff --git a/src/Datatables/config/datatables.php b/src/Datatables/config/datatables.php deleted file mode 100644 index 550b0b3..0000000 --- a/src/Datatables/config/datatables.php +++ /dev/null @@ -1,52 +0,0 @@ - [ - 'css' => 'vendor/redot/datatables/datatables.css', - 'js' => 'vendor/redot/datatables/datatables.js', - ], - - 'export' => [ - 'xlsx' => [ - 'enabled' => true, - 'exporter' => XlsxExporter::class, - ], - - 'csv' => [ - 'enabled' => true, - 'exporter' => CsvExporter::class, - ], - - 'json' => [ - 'enabled' => true, - 'exporter' => JsonExporter::class, - ], - - 'pdf' => [ - 'enabled' => true, - 'exporter' => PdfExporter::class, - 'template' => 'datatables::pdf.default', - 'adapter' => LaravelMpdf::class, - 'options' => [ - 'format' => 'A4', - 'orientation' => 'P', - ], - ], - ], -]; diff --git a/src/Datatables/resources/views/datatable.blade.php b/src/Datatables/resources/views/datatable.blade.php index 404c3bc..9c6d534 100644 --- a/src/Datatables/resources/views/datatable.blade.php +++ b/src/Datatables/resources/views/datatable.blade.php @@ -1,6 +1,6 @@ @assets - - + + @endassets
diff --git a/src/Datatables/src/Datatable.php b/src/Datatables/src/Datatable.php index 346c57d..46ff44c 100644 --- a/src/Datatables/src/Datatable.php +++ b/src/Datatables/src/Datatable.php @@ -147,13 +147,13 @@ public function __construct() $this->defaultPerPage = $this->perPage; // Set the PDF adapter and options - $this->pdfTemplate ??= config('datatables.export.pdf.template'); - $this->pdfAdapter ??= config('datatables.export.pdf.adapter'); - $this->pdfOptions = array_merge(config('datatables.export.pdf.options') ?? [], $this->pdfOptions); + $this->pdfTemplate ??= config('redot.datatables.export.pdf.template'); + $this->pdfAdapter ??= config('redot.datatables.export.pdf.adapter'); + $this->pdfOptions = array_merge(config('redot.datatables.export.pdf.options') ?? [], $this->pdfOptions); // Set the allowed export formats if (! isset($this->allowedExports)) { - $this->allowedExports = array_keys(array_filter(config('datatables.export') ?? [], fn ($export) => $export['enabled'])); + $this->allowedExports = array_keys(array_filter(config('redot.datatables.export') ?? [], fn ($export) => $export['enabled'])); } } diff --git a/src/Datatables/src/DatatablesServiceProvider.php b/src/Datatables/src/DatatablesServiceProvider.php index 99d6980..a8d702f 100644 --- a/src/Datatables/src/DatatablesServiceProvider.php +++ b/src/Datatables/src/DatatablesServiceProvider.php @@ -7,23 +7,11 @@ class DatatablesServiceProvider extends ServiceProvider { - /** - * Register the application services. - */ - public function register(): void - { - $this->mergeConfigFrom(__DIR__ . '/../config/datatables.php', 'datatables'); - } - /** * Bootstrap the application services. */ public function boot(): void { - $this->publishes([ - __DIR__ . '/../config/datatables.php' => config_path('datatables.php'), - ], 'datatables::config'); - $this->views(); $this->lang(); $this->assets(); @@ -45,7 +33,7 @@ protected function views(): void $this->publishes([ __DIR__ . '/../resources/views' => resource_path('views/vendor/datatables'), - ], 'datatables::views'); + ], 'redot::datatables-views'); } /** @@ -60,7 +48,7 @@ protected function lang(): void $this->publishes([ __DIR__ . '/../lang' => lang_path('vendor/datatables'), - ], 'datatables::lang'); + ], 'redot::datatables-lang'); } /** diff --git a/src/Datatables/src/Exporters/ExportManager.php b/src/Datatables/src/Exporters/ExportManager.php index a99bf26..461ac6b 100644 --- a/src/Datatables/src/Exporters/ExportManager.php +++ b/src/Datatables/src/Exporters/ExportManager.php @@ -39,7 +39,7 @@ public function ensureAllowed(string $format): void */ public function exporter(string $format, array $parameters = []): Exporter { - $exporter = config("datatables.export.$format.exporter") ?? static::DEFAULT_EXPORTERS[$format] ?? null; + $exporter = config("redot.datatables.export.$format.exporter") ?? static::DEFAULT_EXPORTERS[$format] ?? null; if (! $exporter || ! is_a($exporter, Exporter::class, true)) { throw new InvalidArgumentException(sprintf('No exporter registered for the "%s" format.', $format)); diff --git a/src/Foundation/config/redot.php b/src/Foundation/config/redot.php index 7a76050..12483c6 100644 --- a/src/Foundation/config/redot.php +++ b/src/Foundation/config/redot.php @@ -1,5 +1,11 @@ [ + 'assets' => [ + 'css' => 'vendor/redot/datatables/datatables.css', + 'js' => 'vendor/redot/datatables/datatables.js', + ], + + 'export' => [ + 'xlsx' => [ + 'enabled' => true, + 'exporter' => XlsxExporter::class, + ], + + 'csv' => [ + 'enabled' => true, + 'exporter' => CsvExporter::class, + ], + + 'json' => [ + 'enabled' => true, + 'exporter' => JsonExporter::class, + ], + + 'pdf' => [ + 'enabled' => true, + 'exporter' => PdfExporter::class, + 'template' => 'datatables::pdf.default', + 'adapter' => LaravelMpdf::class, + 'options' => [ + 'format' => 'A4', + 'orientation' => 'P', + ], + ], + ], + ], + + /* + |-------------------------------------------------------------------------- + | Toastify + |-------------------------------------------------------------------------- + | + | The toast types available to toastify() and their default display + | options. + | + */ + + 'toastify' => [ + 'toastifiers' => [ + 'toast' => [ + 'icon' => 'ti ti-bell', + 'color' => 'var(--tblr-secondary)', + ], + 'error' => [ + 'icon' => 'ti ti-circle-x', + 'color' => 'var(--tblr-danger)', + ], + 'success' => [ + 'icon' => 'ti ti-circle-check', + 'color' => 'var(--tblr-success)', + ], + 'info' => [ + 'icon' => 'ti ti-info-circle', + 'color' => 'var(--tblr-info)', + ], + 'warning' => [ + 'icon' => 'ti ti-alert-triangle', + 'color' => 'var(--tblr-warning)', + ], + ], + + // The default values for the toastifiers. + + 'defaults' => [ + 'position' => 'bottom-right', + 'close' => true, + 'autohide' => true, + 'delay' => 5000, + ], + ], + ]; diff --git a/src/Foundation/src/View/Components/Toasts.php b/src/Foundation/src/View/Components/Toasts.php index 0247d72..51e7ff0 100644 --- a/src/Foundation/src/View/Components/Toasts.php +++ b/src/Foundation/src/View/Components/Toasts.php @@ -27,7 +27,7 @@ class Toasts extends Component */ public function __construct() { - $this->config = config('toastify', []); + $this->config = config('redot.toastify', []); $this->messages = session()->pull('toastify', []); } diff --git a/src/Toastify/config/toastify.php b/src/Toastify/config/toastify.php deleted file mode 100644 index 0f1caba..0000000 --- a/src/Toastify/config/toastify.php +++ /dev/null @@ -1,50 +0,0 @@ - [ - 'toast' => [ - 'icon' => 'ti ti-bell', - 'color' => 'var(--tblr-secondary)', - ], - 'error' => [ - 'icon' => 'ti ti-circle-x', - 'color' => 'var(--tblr-danger)', - ], - 'success' => [ - 'icon' => 'ti ti-circle-check', - 'color' => 'var(--tblr-success)', - ], - 'info' => [ - 'icon' => 'ti ti-info-circle', - 'color' => 'var(--tblr-info)', - ], - 'warning' => [ - 'icon' => 'ti ti-alert-triangle', - 'color' => 'var(--tblr-warning)', - ], - ], - - /*-------------------------------------------------------------------------- - | Toastify Defaults - |-------------------------------------------------------------------------- - | - | The default values for the toastifiers. - | - */ - - 'defaults' => [ - 'position' => 'bottom-right', - 'close' => true, - 'autohide' => true, - 'delay' => 5000, - ], -]; diff --git a/src/Toastify/src/LaravelToastifyServiceProvider.php b/src/Toastify/src/LaravelToastifyServiceProvider.php index 0e12c88..545f98e 100644 --- a/src/Toastify/src/LaravelToastifyServiceProvider.php +++ b/src/Toastify/src/LaravelToastifyServiceProvider.php @@ -11,19 +11,7 @@ class LaravelToastifyServiceProvider extends ServiceProvider */ public function register(): void { - $this->mergeConfigFrom(__DIR__ . '/../config/toastify.php', 'toastify'); - $this->app->singleton(Toastify::class, fn () => new Toastify); $this->app->alias(Toastify::class, 'toastify'); } - - /** - * Bootstrap the application services. - */ - public function boot(): void - { - $this->publishes([ - __DIR__ . '/../config/toastify.php' => config_path('toastify.php'), - ], 'toastify::config'); - } } diff --git a/src/Toastify/src/Toastify.php b/src/Toastify/src/Toastify.php index abc01dd..570afd3 100644 --- a/src/Toastify/src/Toastify.php +++ b/src/Toastify/src/Toastify.php @@ -28,7 +28,7 @@ protected function push(string $title, ?string $message, string $type, array $op */ public function __call(string $name, array $arguments) { - if (! array_key_exists($name, config('toastify.toastifiers', []))) { + if (! array_key_exists($name, config('redot.toastify.toastifiers', []))) { throw new BadMethodCallException(sprintf('Toast type [%s] is not defined in the toastify configuration.', $name)); } diff --git a/tests/Feature/Packages/Datatables/ExportTest.php b/tests/Feature/Packages/Datatables/ExportTest.php index 6368f45..1cceb7e 100644 --- a/tests/Feature/Packages/Datatables/ExportTest.php +++ b/tests/Feature/Packages/Datatables/ExportTest.php @@ -109,3 +109,15 @@ public function exportData(): array 'allowed formats' => ['allowedExports', ['xlsx', 'csv', 'json', 'pdf']], 'pdf adapter class' => ['pdfAdapter', 'App\\Evil'], ]); + +it('reads export formats and pdf settings from the redot config', function () { + config([ + 'redot.datatables.export.csv.enabled' => false, + 'redot.datatables.export.pdf.template' => 'custom.pdf.template', + ]); + + $datatable = new RunActionDatatable; + + expect($datatable->allowedExports)->toBe(['xlsx', 'json', 'pdf']) + ->and($datatable->pdfTemplate)->toBe('custom.pdf.template'); +}); diff --git a/tests/Unit/Packages/Toastify/ToastifyTest.php b/tests/Unit/Packages/Toastify/ToastifyTest.php index ecda4b3..c513ef6 100644 --- a/tests/Unit/Packages/Toastify/ToastifyTest.php +++ b/tests/Unit/Packages/Toastify/ToastifyTest.php @@ -17,3 +17,11 @@ it('requires a title when pushing a toast', function () { toastify()->success(); })->throws(InvalidArgumentException::class); + +it('accepts toast types defined in the redot config', function () { + config(['redot.toastify.toastifiers.notice' => ['icon' => 'ti ti-bell']]); + + toastify()->notice('Heads up'); + + expect(session('toastify.0.type'))->toBe('notice'); +}); From f8c1cda64feadeb768c7a9a9d12d74e715066852 Mon Sep 17 00:00:00 2001 From: Abdelrhman Said Date: Tue, 27 Oct 2026 22:54:27 +0300 Subject: [PATCH 06/12] refactor(datatables): register views and translations under the redot namespace Datatable views move to redot::datatables.* and translations to redot::datatables.*, so they are overridden from resources/views/vendor/redot/datatables and lang/vendor/redot. --- docs/content/packages/datatables/frontend.md | 4 ++-- .../lang/ar/{datatable.php => datatables.php} | 0 .../lang/en/{datatable.php => datatables.php} | 0 .../views/{ => datatables}/datatable.blade.php | 18 +++++++++--------- .../{ => datatables}/filters/date.blade.php | 0 .../{ => datatables}/filters/number.blade.php | 0 .../{ => datatables}/filters/select.blade.php | 0 .../{ => datatables}/filters/string.blade.php | 0 .../{ => datatables}/filters/ternary.blade.php | 0 .../views/datatables/filters/trashed.blade.php | 5 +++++ .../pagination/default.blade.php | 8 ++++---- .../partials/action-group.blade.php | 2 +- .../{ => datatables}/partials/action.blade.php | 0 .../partials/bulk-actions.blade.php | 14 +++++++------- .../{ => datatables}/partials/empty.blade.php | 0 .../{ => datatables}/partials/export.blade.php | 8 ++++---- .../partials/filters-toggle.blade.php | 0 .../partials/filters.blade.php | 0 .../partials/pagination.blade.php | 2 +- .../partials/per-page.blade.php | 0 .../partials/refresh.blade.php | 0 .../{ => datatables}/partials/search.blade.php | 2 +- .../{ => datatables}/partials/table.blade.php | 10 +++++----- .../{ => datatables}/pdf/default.blade.php | 4 ++-- .../resources/views/filters/trashed.blade.php | 5 ----- src/Datatables/src/Actions/Action.php | 12 ++++++------ src/Datatables/src/Actions/BulkAction.php | 8 ++++---- src/Datatables/src/Columns/TernaryColumn.php | 4 ++-- src/Datatables/src/Datatable.php | 6 +++--- .../src/DatatablesServiceProvider.php | 8 ++++---- src/Datatables/src/Filters/DateFilter.php | 2 +- src/Datatables/src/Filters/NumberFilter.php | 14 +++++++------- src/Datatables/src/Filters/SelectFilter.php | 4 ++-- src/Datatables/src/Filters/StringFilter.php | 18 +++++++++--------- src/Datatables/src/Filters/TernaryFilter.php | 10 +++++----- src/Datatables/src/Filters/TrashedFilter.php | 4 ++-- src/Foundation/config/redot.php | 2 +- .../Unit/Packages/Datatables/ResourcesTest.php | 10 ++++++++++ 38 files changed, 97 insertions(+), 87 deletions(-) rename src/Datatables/lang/ar/{datatable.php => datatables.php} (100%) rename src/Datatables/lang/en/{datatable.php => datatables.php} (100%) rename src/Datatables/resources/views/{ => datatables}/datatable.blade.php (67%) rename src/Datatables/resources/views/{ => datatables}/filters/date.blade.php (100%) rename src/Datatables/resources/views/{ => datatables}/filters/number.blade.php (100%) rename src/Datatables/resources/views/{ => datatables}/filters/select.blade.php (100%) rename src/Datatables/resources/views/{ => datatables}/filters/string.blade.php (100%) rename src/Datatables/resources/views/{ => datatables}/filters/ternary.blade.php (100%) create mode 100644 src/Datatables/resources/views/datatables/filters/trashed.blade.php rename src/Datatables/resources/views/{ => datatables}/pagination/default.blade.php (89%) rename src/Datatables/resources/views/{ => datatables}/partials/action-group.blade.php (90%) rename src/Datatables/resources/views/{ => datatables}/partials/action.blade.php (100%) rename src/Datatables/resources/views/{ => datatables}/partials/bulk-actions.blade.php (64%) rename src/Datatables/resources/views/{ => datatables}/partials/empty.blade.php (100%) rename src/Datatables/resources/views/{ => datatables}/partials/export.blade.php (86%) rename src/Datatables/resources/views/{ => datatables}/partials/filters-toggle.blade.php (100%) rename src/Datatables/resources/views/{ => datatables}/partials/filters.blade.php (100%) rename src/Datatables/resources/views/{ => datatables}/partials/pagination.blade.php (85%) rename src/Datatables/resources/views/{ => datatables}/partials/per-page.blade.php (100%) rename src/Datatables/resources/views/{ => datatables}/partials/refresh.blade.php (100%) rename src/Datatables/resources/views/{ => datatables}/partials/search.blade.php (74%) rename src/Datatables/resources/views/{ => datatables}/partials/table.blade.php (90%) rename src/Datatables/resources/views/{ => datatables}/pdf/default.blade.php (94%) delete mode 100644 src/Datatables/resources/views/filters/trashed.blade.php create mode 100644 tests/Unit/Packages/Datatables/ResourcesTest.php diff --git a/docs/content/packages/datatables/frontend.md b/docs/content/packages/datatables/frontend.md index a11b3f7..946cd6c 100644 --- a/docs/content/packages/datatables/frontend.md +++ b/docs/content/packages/datatables/frontend.md @@ -78,10 +78,10 @@ The script exposes its helpers as `window.Datatables` — the package views cons Publish the package's views or translations to override them: ```bash -# Blade views -> resources/views/vendor/datatables +# Blade views -> resources/views/vendor/redot/datatables php artisan vendor:publish --tag=redot::datatables-views -# Translations -> lang/vendor/datatables +# Translations -> lang/vendor/redot php artisan vendor:publish --tag=redot::datatables-lang ``` diff --git a/src/Datatables/lang/ar/datatable.php b/src/Datatables/lang/ar/datatables.php similarity index 100% rename from src/Datatables/lang/ar/datatable.php rename to src/Datatables/lang/ar/datatables.php diff --git a/src/Datatables/lang/en/datatable.php b/src/Datatables/lang/en/datatables.php similarity index 100% rename from src/Datatables/lang/en/datatable.php rename to src/Datatables/lang/en/datatables.php diff --git a/src/Datatables/resources/views/datatable.blade.php b/src/Datatables/resources/views/datatables/datatable.blade.php similarity index 67% rename from src/Datatables/resources/views/datatable.blade.php rename to src/Datatables/resources/views/datatables/datatable.blade.php index 9c6d534..f9f7c9f 100644 --- a/src/Datatables/resources/views/datatable.blade.php +++ b/src/Datatables/resources/views/datatables/datatable.blade.php @@ -6,47 +6,47 @@
- @include('datatables::partials.per-page') + @include('redot::datatables.partials.per-page')
@if ($searchable)
- @include('datatables::partials.search') + @include('redot::datatables.partials.search')
@endif @if ($exportable)
- @include('datatables::partials.export') + @include('redot::datatables.partials.export')
@endif @if ($filterable)
- @include('datatables::partials.filters-toggle') + @include('redot::datatables.partials.filters-toggle')
@endif
- @include('datatables::partials.refresh') + @include('redot::datatables.partials.refresh')
@if ($filterable)
- @include('datatables::partials.filters') + @include('redot::datatables.partials.filters')
@endif @if ($selectable)
- @include('datatables::partials.bulk-actions') + @include('redot::datatables.partials.bulk-actions')
@endif - @include('datatables::partials.table') + @include('redot::datatables.partials.table')
diff --git a/src/Datatables/resources/views/filters/date.blade.php b/src/Datatables/resources/views/datatables/filters/date.blade.php similarity index 100% rename from src/Datatables/resources/views/filters/date.blade.php rename to src/Datatables/resources/views/datatables/filters/date.blade.php diff --git a/src/Datatables/resources/views/filters/number.blade.php b/src/Datatables/resources/views/datatables/filters/number.blade.php similarity index 100% rename from src/Datatables/resources/views/filters/number.blade.php rename to src/Datatables/resources/views/datatables/filters/number.blade.php diff --git a/src/Datatables/resources/views/filters/select.blade.php b/src/Datatables/resources/views/datatables/filters/select.blade.php similarity index 100% rename from src/Datatables/resources/views/filters/select.blade.php rename to src/Datatables/resources/views/datatables/filters/select.blade.php diff --git a/src/Datatables/resources/views/filters/string.blade.php b/src/Datatables/resources/views/datatables/filters/string.blade.php similarity index 100% rename from src/Datatables/resources/views/filters/string.blade.php rename to src/Datatables/resources/views/datatables/filters/string.blade.php diff --git a/src/Datatables/resources/views/filters/ternary.blade.php b/src/Datatables/resources/views/datatables/filters/ternary.blade.php similarity index 100% rename from src/Datatables/resources/views/filters/ternary.blade.php rename to src/Datatables/resources/views/datatables/filters/ternary.blade.php diff --git a/src/Datatables/resources/views/datatables/filters/trashed.blade.php b/src/Datatables/resources/views/datatables/filters/trashed.blade.php new file mode 100644 index 0000000..5c7cfef --- /dev/null +++ b/src/Datatables/resources/views/datatables/filters/trashed.blade.php @@ -0,0 +1,5 @@ + diff --git a/src/Datatables/resources/views/pagination/default.blade.php b/src/Datatables/resources/views/datatables/pagination/default.blade.php similarity index 89% rename from src/Datatables/resources/views/pagination/default.blade.php rename to src/Datatables/resources/views/datatables/pagination/default.blade.php index 3134589..0ac5e65 100644 --- a/src/Datatables/resources/views/pagination/default.blade.php +++ b/src/Datatables/resources/views/datatables/pagination/default.blade.php @@ -4,7 +4,7 @@
    {{-- Previous Page Link --}} @if ($paginator->onFirstPage()) -
  • +
  • @else @@ -12,7 +12,7 @@ + wire:loading.attr="disabled" rel="prev" aria-label="@lang('redot::datatables.pagination.previous')">‹ @endif @@ -48,10 +48,10 @@ class="page-link">{{ $element }} + wire:loading.attr="disabled" rel="next" aria-label="@lang('redot::datatables.pagination.next')">› @else -
  • +
  • @endif diff --git a/src/Datatables/resources/views/partials/action-group.blade.php b/src/Datatables/resources/views/datatables/partials/action-group.blade.php similarity index 90% rename from src/Datatables/resources/views/partials/action-group.blade.php rename to src/Datatables/resources/views/datatables/partials/action-group.blade.php index 1243995..d81ae0d 100644 --- a/src/Datatables/resources/views/partials/action-group.blade.php +++ b/src/Datatables/resources/views/datatables/partials/action-group.blade.php @@ -12,7 +12,7 @@