diff --git a/CHANGELOG.md b/CHANGELOG.md index f2926a6..bfc9067 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,7 @@ internos pueden omitirse si no afectan al uso del proyecto. - [context] Generaliza los parámetros de contexto - [context] Define un `trait` común de contexto - Modifica tipos para atributos HTML a minúsculas -- Renombra `with_component` por `add_component` +- Renombra `with_component` por `add_child` ### Corregido diff --git a/Cargo.lock b/Cargo.lock index e0d497c..2f9fa42 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,9 +44,9 @@ dependencies = [ [[package]] name = "actix-http" -version = "3.11.1" +version = "3.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44cceded2fb55f3c4b67068fa64962e2ca59614edc5b03167de9ff82ae803da0" +checksum = "7926860314cbe2fb5d1f13731e387ab43bd32bca224e82e6e2db85de0a3dba49" dependencies = [ "actix-codec", "actix-rt", @@ -227,9 +227,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.24.2" +version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" +checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b" dependencies = [ "gimli", ] @@ -328,9 +328,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.20" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -343,9 +343,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -390,9 +390,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "backtrace" -version = "0.3.75" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" +checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", "cfg-if", @@ -400,7 +400,7 @@ dependencies = [ "miniz_oxide", "object", "rustc-demangle", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -484,9 +484,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.38" +version = "1.2.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80f41ae168f955c12fb8960b057d70d0ca153fb83182b57d86380443527be7e9" +checksum = "ac9fe6cdbb24b6ade63616c0a0688e45bb56732262c158df3c0c4bea4ca47cb7" dependencies = [ "find-msvc-tools", "jobserver", @@ -520,7 +520,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -589,9 +589,9 @@ checksum = "7439becb5fafc780b6f4de382b1a7a3e70234afe783854a4702ee8adbb838609" [[package]] name = "config" -version = "0.15.16" +version = "0.15.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cef036f0ecf99baef11555578630e2cca559909b4c50822dbba828c252d21c49" +checksum = "180e549344080374f9b32ed41bf3b6b57885ff6a289367b3dbc10eea8acc1918" dependencies = [ "pathdiff", "serde_core", @@ -703,9 +703,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "a41953f86f8a05768a6cda24def994fd2f424b04ec5c719cf89989779f199071" dependencies = [ "powerfmt", ] @@ -788,7 +788,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -805,15 +805,15 @@ checksum = "4742a071cd9694fc86f9fa1a08fa3e53d40cc899d7ee532295da2d085639fbc5" [[package]] name = "find-msvc-tools" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ced73b1dacfc750a6db6c0a0c3a3853c8b41997e2e2c563dc90804ae6867959" +checksum = "52051878f80a721bb68ebfbc930e07b65ba72f2da88968ea5c06fd6ca3d3a127" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "dc5a4e564e38c699f2880d3fda590bedc2e69f3f84cd48b457bd892ce61d0aa9" dependencies = [ "crc32fast", "miniz_oxide", @@ -851,7 +851,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54f0d287c53ffd184d04d8677f590f4ac5379785529e5e08b1c8083acdd5c198" dependencies = [ "memchr", - "thiserror 2.0.16", + "thiserror 2.0.17", ] [[package]] @@ -994,9 +994,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.1" +version = "0.32.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7" [[package]] name = "glob" @@ -1356,9 +1356,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.80" +version = "0.3.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852f13bec5eba4ba9afbeb93fd7c13fe56147f055939ae21c43a29a0ecb2702e" +checksum = "ec48937a97411dcb524a265206ccd4c90bb711fca92b2792c407f268825b9305" dependencies = [ "once_cell", "wasm-bindgen", @@ -1387,9 +1387,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.175" +version = "0.2.177" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" +checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" [[package]] name = "linux-raw-sys" @@ -1422,11 +1422,10 @@ checksum = "4d873d7c67ce09b42110d801813efbc9364414e356be9935700d368351657487" [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] @@ -1447,9 +1446,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "mime" @@ -1474,6 +1473,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] @@ -1520,9 +1520,9 @@ dependencies = [ [[package]] name = "object" -version = "0.36.7" +version = "0.37.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" +checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe" dependencies = [ "memchr", ] @@ -1560,12 +1560,15 @@ dependencies = [ "fluent-templates", "indoc", "itoa", + "pagetop-aliner", + "pagetop-bootsier", "pagetop-build", "pagetop-macros", "pagetop-statics", "parking_lot", "pastey", "serde", + "serde_json", "substring", "tempfile", "terminal_size", @@ -1576,6 +1579,23 @@ dependencies = [ "unic-langid", ] +[[package]] +name = "pagetop-aliner" +version = "0.0.9" +dependencies = [ + "pagetop", + "pagetop-build", +] + +[[package]] +name = "pagetop-bootsier" +version = "0.0.18" +dependencies = [ + "pagetop", + "pagetop-build", + "serde", +] + [[package]] name = "pagetop-build" version = "0.3.1" @@ -1608,9 +1628,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -1618,15 +1638,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -1813,9 +1833,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "ce25767e7b499d1b604768e7cde645d14cc8584231ea6b295e9c9eb22c02e1d1" dependencies = [ "proc-macro2", ] @@ -1887,18 +1907,18 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.11.2" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" +checksum = "4a52d8d02cacdb176ef4678de6c052efb4b3da14b78e4db683a4252762be5433" dependencies = [ "aho-corasick", "memchr", @@ -1908,9 +1928,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.10" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" +checksum = "722166aa0d7438abbaa4d5cc2c649dac844e8c56d82fb3d33e9c34b5cd268fc6" dependencies = [ "aho-corasick", "memchr", @@ -1960,7 +1980,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -2004,9 +2024,9 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6c24dee235d0da097043389623fb913daddf92c76e9f5a1db88607a0bcbd1d" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ "serde_core", "serde_derive", @@ -2014,18 +2034,18 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "659356f9a0cb1e529b24c01e43ad2bdf520ec4ceaf83047b83ddcc2251f96383" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.225" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea936adf78b1f766949a4977b91d2f5595825bd6ec079aa9543ad2685fc4516" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -2047,9 +2067,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5417783452c2be558477e104686f7de5dae53dba813c28435e0e70f82d9b04ee" +checksum = "e24345aa0fe688594e73770a5f6d1b216508b4f93484c0026d521acd30134392" dependencies = [ "serde_core", ] @@ -2112,6 +2132,12 @@ dependencies = [ "libc", ] +[[package]] +name = "simd-adler32" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" + [[package]] name = "siphasher" version = "1.0.1" @@ -2161,9 +2187,9 @@ dependencies = [ [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "strsim" @@ -2210,15 +2236,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.22.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84fa4d11fadde498443cca10fd3ac23c951f0dc59e080e9f4b93d4df4e4eea53" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] @@ -2242,11 +2268,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.16", + "thiserror-impl 2.0.17", ] [[package]] @@ -2262,9 +2288,9 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", @@ -2355,9 +2381,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00e5e5d9bf2475ac9d4f0d9edab68cc573dc2fd644b0dba36b0c30a92dd9eaa0" +checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" dependencies = [ "serde_core", "serde_spanned", @@ -2368,18 +2394,18 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f1085dec27c2b6632b04c80b3bb1b4300d6495d1e129693bdda7d91e72eec1" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] [[package]] name = "toml_parser" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cf893c33be71572e0e9aa6dd15e6677937abd686b066eac3f8cd3531688a627" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ "winnow", ] @@ -2495,9 +2521,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unic-langid" @@ -2659,9 +2685,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab10a69fbd0a177f5f649ad4d8d3305499c42bab9aef2f7ff592d0ec8f833819" +checksum = "c1da10c01ae9f1ae40cbfac0bac3b1e724b320abfcf52229f80b547c0d250e2d" dependencies = [ "cfg-if", "once_cell", @@ -2672,9 +2698,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb702423545a6007bbc368fde243ba47ca275e549c8a28617f56f6ba53b1d1c" +checksum = "671c9a5a66f49d8a47345ab942e2cb93c7d1d0339065d4f8139c486121b43b19" dependencies = [ "bumpalo", "log", @@ -2686,9 +2712,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc65f4f411d91494355917b605e1480033152658d71f722a90647f56a70c88a0" +checksum = "7ca60477e4c59f5f2986c50191cd972e3a50d8a95603bc9434501cf156a9a119" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2696,9 +2722,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc003a991398a8ee604a401e194b6b3a39677b3173d6e74495eb51b82e99a32" +checksum = "9f07d2f20d4da7b26400c9f4a0511e6e0345b040694e8a75bd41d578fa4421d7" dependencies = [ "proc-macro2", "quote", @@ -2709,9 +2735,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.103" +version = "0.2.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "293c37f4efa430ca14db3721dfbe48d8c33308096bd44d80ebaa775ab71ba1cf" +checksum = "bad67dc8b2a1a6e5448428adec4c3e84c43e561d8c9ee8a9e5aabeb193ec41d1" dependencies = [ "unicode-ident", ] @@ -2722,27 +2748,27 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.0", + "windows-sys 0.61.2", ] [[package]] name = "windows-core" -version = "0.62.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57fe7168f7de578d2d8a05b07fd61870d2e73b4020e9f49aa00da8471723497c" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", - "windows-link 0.2.0", + "windows-link", "windows-result", "windows-strings", ] [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", @@ -2751,9 +2777,9 @@ dependencies = [ [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", @@ -2762,32 +2788,26 @@ dependencies = [ [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - -[[package]] -name = "windows-link" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45e46c0661abb7180e7b9c281db115305d49ca1709ab8242adf09666d2173c65" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-result" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7084dcc306f89883455a206237404d3eaf961e5bd7e0f312f7c91f57eb44167f" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] name = "windows-strings" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7218c655a553b0bed4426cf54b20d7ba363ef543b52d515b3e48d7fd55318dda" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -2814,16 +2834,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", ] [[package]] name = "windows-sys" -version = "0.61.0" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e201184e40b2ede64bc2ea34968b28e33622acdbbf37104f0e4a33f7abe657aa" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.0", + "windows-link", ] [[package]] @@ -2844,19 +2864,19 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.1.3", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] @@ -2867,9 +2887,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -2879,9 +2899,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -2891,9 +2911,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -2903,9 +2923,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -2915,9 +2935,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -2927,9 +2947,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -2939,9 +2959,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -2951,9 +2971,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" diff --git a/Cargo.toml b/Cargo.toml index 913f3d7..b1bae0a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,7 @@ actix-web = { workspace = true, default-features = true } actix-session = { version = "0.11", features = ["cookie-session"] } actix-web-files = { package = "actix-files", version = "0.6" } -serde = { version = "1.0", features = ["derive"] } +serde.workspace = true pagetop-macros.workspace = true pagetop-statics.workspace = true @@ -49,7 +49,10 @@ default = [] testing = [] [dev-dependencies] -tempfile = "3.22" +tempfile = "3.23" +serde_json = "1.0" +pagetop-aliner.workspace = true +pagetop-bootsier.workspace = true [build-dependencies] pagetop-build.workspace = true @@ -58,9 +61,13 @@ pagetop-build.workspace = true [workspace] resolver = "2" members = [ + # Helpers "helpers/pagetop-build", "helpers/pagetop-macros", "helpers/pagetop-statics", + # Extensions + "extensions/pagetop-aliner", + "extensions/pagetop-bootsier", ] [workspace.package] @@ -71,7 +78,13 @@ authors = ["Manuel Cillero "] [workspace.dependencies] actix-web = { version = "4.11", default-features = false } - +serde = { version = "1.0", features = ["derive"] } +# Helpers pagetop-build = { version = "0.3", path = "helpers/pagetop-build" } pagetop-macros = { version = "0.2", path = "helpers/pagetop-macros" } pagetop-statics = { version = "0.1", path = "helpers/pagetop-statics" } +# Extensions +pagetop-aliner = { version = "0.0", path = "extensions/pagetop-aliner" } +pagetop-bootsier = { version = "0.0", path = "extensions/pagetop-bootsier" } +# PageTop +pagetop = { version = "0.4", path = "." } diff --git a/README.md b/README.md index c6c12e0..9a12c84 100644 --- a/README.md +++ b/README.md @@ -6,10 +6,10 @@

Un entorno para el desarrollo de soluciones web modulares, extensibles y configurables.

-[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) [![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) [![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop#licencia)
@@ -60,7 +60,7 @@ impl Extension for HelloWorld { async fn hello_world(request: HttpRequest) -> ResultPage { Page::new(request) - .add_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + .add_child(Html::with(|_| html! { h1 { "Hello World!" } })) .render() } @@ -96,6 +96,15 @@ El código se organiza en un *workspace* donde actualmente se incluyen los sigui * **[pagetop-macros](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-macros)**, proporciona una colección de macros que mejoran la experiencia de desarrollo con PageTop. +## Extensiones + + * **[pagetop-aliner](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-aliner)**, + es un tema para demos y pruebas que muestra esquemáticamente la composición de las páginas HTML. + + * **[pagetop-bootsier](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier)**, + tema basado en [Bootstrap](https://getbootstrap.com) para integrar su catálogo de estilos y + componentes flexibles. + # 🧪 Pruebas diff --git a/examples/hello-name.rs b/examples/hello-name.rs index e1285d0..c6a82aa 100644 --- a/examples/hello-name.rs +++ b/examples/hello-name.rs @@ -14,7 +14,7 @@ async fn hello_name( ) -> ResultPage { let name = path.into_inner(); Page::new(request) - .add_component(Html::with(move |_| html! { h1 { "Hello " (name) "!" } })) + .add_child(Html::with(move |_| html! { h1 { "Hello " (name) "!" } })) .render() } diff --git a/examples/hello-world.rs b/examples/hello-world.rs index d56f210..6481746 100644 --- a/examples/hello-world.rs +++ b/examples/hello-world.rs @@ -10,7 +10,7 @@ impl Extension for HelloWorld { async fn hello_world(request: HttpRequest) -> ResultPage { Page::new(request) - .add_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + .add_child(Html::with(|_| html! { h1 { "Hello World!" } })) .render() } diff --git a/examples/navbar-menus.rs b/examples/navbar-menus.rs new file mode 100644 index 0000000..071d24b --- /dev/null +++ b/examples/navbar-menus.rs @@ -0,0 +1,109 @@ +use pagetop::prelude::*; + +use pagetop_bootsier::prelude::*; + +struct SuperMenu; + +impl Extension for SuperMenu { + fn dependencies(&self) -> Vec { + vec![&pagetop_aliner::Aliner, &pagetop_bootsier::Bootsier] + } + + fn initialize(&self) { + let home_path = |cx: &Context| match cx.langid().language.as_str() { + "en" => "/en", + _ => "/", + }; + + let navbar_menu = Navbar::brand_left(navbar::Brand::new().with_path(Some(home_path))) + .with_expand(BreakPoint::LG) + .add_item(navbar::Item::nav( + Nav::new() + .add_item(nav::Item::link( + L10n::l("sample_menus_item_link"), + home_path, + )) + .add_item(nav::Item::link_blank( + L10n::l("sample_menus_item_blank"), + |_| "https://docs.rs/pagetop", + )) + .add_item(nav::Item::dropdown( + Dropdown::new() + .with_title(L10n::l("sample_menus_test_title")) + .add_item(dropdown::Item::header(L10n::l("sample_menus_dev_header"))) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_dev_getting_started"), + |_| "/dev/getting-started", + )) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_dev_guides"), + |_| "/dev/guides", + )) + .add_item(dropdown::Item::link_blank( + L10n::l("sample_menus_dev_forum"), + |_| "https://forum.example.dev", + )) + .add_item(dropdown::Item::divider()) + .add_item(dropdown::Item::header(L10n::l("sample_menus_sdk_header"))) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_sdk_rust"), + |_| "/dev/sdks/rust", + )) + .add_item(dropdown::Item::link(L10n::l("sample_menus_sdk_js"), |_| { + "/dev/sdks/js" + })) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_sdk_python"), + |_| "/dev/sdks/python", + )) + .add_item(dropdown::Item::divider()) + .add_item(dropdown::Item::header(L10n::l( + "sample_menus_plugin_header", + ))) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_plugin_auth"), + |_| "/dev/sdks/rust/plugins/auth", + )) + .add_item(dropdown::Item::link( + L10n::l("sample_menus_plugin_cache"), + |_| "/dev/sdks/rust/plugins/cache", + )) + .add_item(dropdown::Item::divider()) + .add_item(dropdown::Item::label(L10n::l("sample_menus_item_label"))) + .add_item(dropdown::Item::link_disabled( + L10n::l("sample_menus_item_disabled"), + |_| "#", + )), + )) + .add_item(nav::Item::link_disabled( + L10n::l("sample_menus_item_disabled"), + |_| "#", + )), + )) + .add_item(navbar::Item::nav( + Nav::new() + .with_classes( + ClassesOp::Add, + classes::Margin::with(Side::Start, ScaleSize::Auto).to_class(), + ) + .add_item(nav::Item::link( + L10n::l("sample_menus_item_sign_up"), + |_| "/auth/sign-up", + )) + .add_item(nav::Item::link(L10n::l("sample_menus_item_login"), |_| { + "/auth/login" + })), + )); + + InRegion::Key("header").add(Child::with( + Container::new() + .with_width(container::Width::FluidMax(UnitValue::RelRem(75.0))) + .add_child(navbar_menu), + )); + } +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&SuperMenu).run()?.await +} diff --git a/extensions/pagetop-aliner/Cargo.toml b/extensions/pagetop-aliner/Cargo.toml new file mode 100644 index 0000000..603a630 --- /dev/null +++ b/extensions/pagetop-aliner/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "pagetop-aliner" +version = "0.0.9" +edition = "2021" + +description = """ + Tema de PageTop que muestra esquemáticamente la composición de las páginas HTML +""" +categories = ["web-programming", "gui"] +keywords = ["pagetop", "theme", "css"] + +repository.workspace = true +homepage.workspace = true +license.workspace = true +authors.workspace = true + +[dependencies] +pagetop.workspace = true + +[build-dependencies] +pagetop-build.workspace = true diff --git a/extensions/pagetop-aliner/LICENSE-APACHE b/extensions/pagetop-aliner/LICENSE-APACHE new file mode 100644 index 0000000..263ddac --- /dev/null +++ b/extensions/pagetop-aliner/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 Manuel Cillero + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/extensions/pagetop-aliner/LICENSE-MIT b/extensions/pagetop-aliner/LICENSE-MIT new file mode 100644 index 0000000..cd8af3d --- /dev/null +++ b/extensions/pagetop-aliner/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Manuel Cillero + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/extensions/pagetop-aliner/README.md b/extensions/pagetop-aliner/README.md new file mode 100644 index 0000000..43fb65a --- /dev/null +++ b/extensions/pagetop-aliner/README.md @@ -0,0 +1,100 @@ +
+ +

PageTop Aliner

+ +

Tema de PageTop que muestra esquemáticamente la composición de las páginas HTML.

+ +[![Doc API](https://img.shields.io/docsrs/pagetop-aliner?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-aliner) +[![Crates.io](https://img.shields.io/crates/v/pagetop-aliner.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-aliner) +[![Descargas](https://img.shields.io/crates/d/pagetop-aliner.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-aliner) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-aliner#licencia) + +
+
+ +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# ⚡️ Guía rápida + +Igual que con otras extensiones, **añade la dependencia** a tu `Cargo.toml`: + +```toml +[dependencies] +pagetop-aliner = "..." +``` + +**Declara la extensión** en tu aplicación (o extensión que la requiera). Recuerda que el orden en +`dependencies()` determina la prioridad relativa frente a las otras extensiones: + +```rust,no_run +use pagetop::prelude::*; + +struct MyApp; + +impl Extension for MyApp { + fn dependencies(&self) -> Vec { + vec![ + // ... + &pagetop_aliner::Aliner, + // ... + ] + } +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&MyApp).run()?.await +} +``` + +Y **selecciona el tema en la configuración** de la aplicación: + +```toml +[app] +theme = "Aliner" +``` + +…o **fuerza el tema por código** en una página concreta: + +```rust,no_run +use pagetop::prelude::*; + +async fn homepage(request: HttpRequest) -> ResultPage { + Page::new(request) + .with_theme("Aliner") + .add_child( + Block::new() + .with_title(L10n::l("sample_title")) + .add_child(Html::with(|cx| html! { + p { (L10n::l("sample_content").using(cx)) } + })), + ) + .render() +} +``` + + +# 🚧 Advertencia + +**PageTop** es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos +hasta que se libere la versión **1.0.0**. + + +# 📜 Licencia + +El código está disponible bajo una doble licencia: + + * **Licencia MIT** + ([LICENSE-MIT](LICENSE-MIT) o también https://opensource.org/licenses/MIT) + + * **Licencia Apache, Versión 2.0** + ([LICENSE-APACHE](LICENSE-APACHE) o también https://www.apache.org/licenses/LICENSE-2.0) + +Puedes elegir la licencia que prefieras. Este enfoque de doble licencia es el estándar de facto en +el ecosistema Rust. diff --git a/extensions/pagetop-aliner/build.rs b/extensions/pagetop-aliner/build.rs new file mode 100644 index 0000000..26713f5 --- /dev/null +++ b/extensions/pagetop-aliner/build.rs @@ -0,0 +1,7 @@ +use pagetop_build::StaticFilesBundle; + +fn main() -> std::io::Result<()> { + StaticFilesBundle::from_dir("./static", None) + .with_name("aliner") + .build() +} diff --git a/extensions/pagetop-aliner/src/lib.rs b/extensions/pagetop-aliner/src/lib.rs new file mode 100644 index 0000000..cbc0f52 --- /dev/null +++ b/extensions/pagetop-aliner/src/lib.rs @@ -0,0 +1,118 @@ +/*! +
+ +

PageTop Aliner

+ +

Tema para PageTop que muestra esquemáticamente la composición de las páginas HTML.

+ +[![Doc API](https://img.shields.io/docsrs/pagetop-aliner?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-aliner) +[![Crates.io](https://img.shields.io/crates/v/pagetop-aliner.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-aliner) +[![Descargas](https://img.shields.io/crates/d/pagetop-aliner.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-aliner) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-aliner#licencia) + +
+
+ +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# ⚡️ Guía rápida + +Igual que con otras extensiones, **añade la dependencia** a tu `Cargo.toml`: + +```toml +[dependencies] +pagetop-aliner = "..." +``` + +**Declara la extensión** en tu aplicación (o extensión que la requiera). Recuerda que el orden en +`dependencies()` determina la prioridad relativa frente a las otras extensiones: + +```rust,no_run +use pagetop::prelude::*; + +struct MyApp; + +impl Extension for MyApp { + fn dependencies(&self) -> Vec { + vec![ + // ... + &pagetop_aliner::Aliner, + // ... + ] + } +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&MyApp).run()?.await +} +``` + +Y **selecciona el tema en la configuración** de la aplicación: + +```toml +[app] +theme = "Aliner" +``` + +…o **fuerza el tema por código** en una página concreta: + +```rust,no_run +use pagetop::prelude::*; + +async fn homepage(request: HttpRequest) -> ResultPage { + Page::new(request) + .with_theme("Aliner") + .add_child( + Block::new() + .with_title(L10n::l("sample_title")) + .add_child(Html::with(|cx| html! { + p { (L10n::l("sample_content").using(cx)) } + })), + ) + .render() +} +``` +*/ + +use pagetop::prelude::*; + +/// El tema usa las mismas regiones predefinidas por [`DefaultRegions`]. +pub type AlinerRegions = DefaultRegions; + +/// Implementa el tema para usar en pruebas que muestran el esquema de páginas HTML. +/// +/// Tema mínimo ideal para **pruebas y demos** que renderiza el **esqueleto HTML** con las mismas +/// regiones básicas definidas por [`DefaultRegions`]. No pretende ser un tema para producción, está +/// pensado para: +/// +/// - Verificar integración de componentes y composiciones (*layouts*) sin estilos complejos. +/// - Realizar pruebas de renderizado rápido con salida estable y predecible. +/// - Preparar ejemplos y documentación, sin dependencias visuales (CSS/JS) innecesarias. +pub struct Aliner; + +impl Extension for Aliner { + fn theme(&self) -> Option { + Some(&Self) + } + + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + static_files_service!(scfg, [aliner] => "/aliner"); + } +} + +impl Theme for Aliner { + fn after_render_page_body(&self, page: &mut Page) { + page.alter_param("include_basic_assets", true) + .alter_assets(ContextOp::AddStyleSheet( + StyleSheet::from("/aliner/css/styles.css") + .with_version(env!("CARGO_PKG_VERSION")) + .with_weight(-90), + )); + } +} diff --git a/extensions/pagetop-aliner/static/css/styles.css b/extensions/pagetop-aliner/static/css/styles.css new file mode 100644 index 0000000..1cc2f5d --- /dev/null +++ b/extensions/pagetop-aliner/static/css/styles.css @@ -0,0 +1,356 @@ +html { + background-color: white; + padding: 1px 3px; +} +body { + padding: 1px 3px; +} +div { + padding: 1px 3px; + margin: 5px; +} +h1, h2, h3, h4,h5, h6, p { + background-color: snow; +} +* * { + outline: 5px solid rgba(255,0,0,.1); +} +* * * { + outline: 3px dashed rgba(255,0,0,.4); +} +* * * * { + outline: 2px dotted rgba(255,0,0,.6); +} +* * * * * { + outline: 1px dotted rgba(255,0,0,.9); +} +* * * * * * { + outline-color: gray; +} + +*::before, *::after { + background: #faa; + border-radius: 3px; + font: normal normal 400 10px/1.2 monospace; + vertical-align: middle; + padding: 1px 3px; + margin: 0 3px; +} +*::before { + content: "("; +} +*::after { + content: ")"; +} + +a::before { content: ""; } +a::after { content: ""; } +abbr::before { content: ""; } +abbr::after { content: ""; } +acronym::before { content: ""; } +acronym::after { content: ""; } +address::before { content: "
"; } +address::after { content: "
"; } +applet::before { content: ""; } +applet::after { content: ""; } +area::before { content: ""; } +area::after { content: ""; } +article::before { content: "
"; } +article::after { content: "
"; } +aside::before { content: ""; } +audio::before { content: ""; } + +b::before { content: ""; } +b::after { content: ""; } +base::before { content: ""; } +base::after { content: ""; } +basefont::before { content: ""; } +basefont::after { content: ""; } +bdi::before { content: ""; } +bdi::after { content: ""; } +bdo::before { content: ""; } +bdo::after { content: ""; } +bgsound::before { content: ""; } +bgsound::after { content: ""; } +big::before { content: ""; } +big::after { content: ""; } +blink::before { content: ""; } +blink::after { content: ""; } +blockquote::before { content: "
"; } +blockquote::after { content: "
"; } +body::before { content: ""; } +body::after { content: ""; } +br::before { content: "
"; } +br::after { content: "
"; } +button::before { content: ""; } + +caption::before { content: ""; } +caption::after { content: ""; } +canvas::before { content: ""; } +canvas::after { content: ""; } +center::before { content: "
"; } +center::after { content: "
"; } +cite::before { content: ""; } +cite::after { content: ""; } +code::before { content: ""; } +code::after { content: ""; } +col::before { content: ""; } +col::after { content: ""; } +colgroup::before { content: ""; } +colgroup::after { content: ""; } +command::before { content: ""; } +command::after { content: ""; } +content::before { content: ""; } +content::after { content: ""; } + +data::before { content: ""; } +data::after { content: ""; } +datalist::before { content: ""; } +datalist::after { content: ""; } +dd::before { content: "
"; } +dd::after { content: "
"; } +del::before { content: ""; } +del::after { content: ""; } +details::before { content: "
"; } +details::after { content: "
"; } +dfn::before { content: ""; } +dfn::after { content: ""; } +dialog::before { content: ""; } +dialog::after { content: ""; } +dir::before { content: ""; } +dir::after { content: ""; } +div::before { content: "
"; } +div::after { content: "
"; } +dl::before { content: "
"; } +dl::after { content: "
"; } +dt::before { content: "
"; } +dt::after { content: "
"; } + +element::before { content: ""; } +element::after { content: ""; } +em::before { content: ""; } +em::after { content: ""; } +embed::before { content: ""; } +embed::after { content: ""; } + +fieldset::before { content: "
"; } +fieldset::after { content: "
"; } +figcaption::before { content: "
"; } +figcaption::after { content: "
"; } +figure::before { content: "
"; } +figure::after { content: "
"; } +font::before { content: ""; } +font::after { content: ""; } +footer::before { content: "
"; } +footer::after { content: "
"; } +form::before { content: "
"; } +form::after { content: "
"; } +frame::before { content: ""; } +frame::after { content: ""; } +frameset::before { content: ""; } +frameset::after { content: ""; } + +h1::before { content: "

"; } +h1::after { content: "

"; } +h2::before { content: "

"; } +h2::after { content: "

"; } +h3::before { content: "

"; } +h3::after { content: "

"; } +h4::before { content: "

"; } +h4::after { content: "

"; } +h5::before { content: "
"; } +h5::after { content: "
"; } +h6::before { content: "
"; } +h6::after { content: "
"; } +head::before { content: ""; } +head::after { content: ""; } +header::before { content: "
"; } +header::after { content: "
"; } +hgroup::before { content: "
"; } +hgroup::after { content: "
"; } +hr::before { content: "
"; } +hr::after { content: ""; } +html::before { content: ""; } +html::after { content: ""; } + +i::before { content: ""; } +i::after { content: ""; } +iframe::before { content: ""; } +image::before { content: ""; } +image::after { content: ""; } +img::before { content: ""; } +img::after { content: ""; } +input::before { content: ""; } +input::after { content: ""; } +ins::before { content: ""; } +ins::after { content: ""; } +isindex::before { content: ""; } +isindex::after { content: ""; } + +kbd::before { content: ""; } +kbd::after { content: ""; } +keygen::before { content: ""; } +keygen::after { content: ""; } + +label::before { content: ""; } +legend::before { content: ""; } +legend::after { content: ""; } +li::before { content: "
  • "; } +li::after { content: "
  • "; } +link::before { content: ""; } +link::after { content: ""; } +listing::before { content: ""; } +listing::after { content: ""; } + +main::before { content: "
    "; } +main::after { content: "
    "; } +map::before { content: ""; } +map::after { content: ""; } +mark::before { content: ""; } +mark::after { content: ""; } +marquee::before { content: ""; } +marquee::after { content: ""; } +menu::before { content: ""; } +menu::after { content: ""; } +menuitem::before { content: ""; } +menuitem::after { content: ""; } +meta::before { content: ""; } +meta::after { content: ""; } +meter::before { content: ""; } +meter::after { content: ""; } +multicol::before { content: ""; } +multicol::after { content: ""; } + +nav::before { content: ""; } +nextid::before { content: ""; } +nextid::after { content: ""; } +nobr::before { content: ""; } +nobr::after { content: ""; } +noembed::before { content: ""; } +noembed::after { content: ""; } +noframes::before { content: ""; } +noframes::after { content: ""; } +noscript::before { content: ""; } + +object::before { content: ""; } +object::after { content: ""; } +ol::before { content: "
      "; } +ol::after { content: "
    "; } +optgroup::before { content: ""; } +optgroup::after { content: ""; } +option::before { content: ""; } +output::before { content: ""; } +output::after { content: ""; } + +p::before { content: "

    "; } +p::after { content: "

    "; } +param::before { content: ""; } +param::after { content: ""; } +picture::before { content: ""; } +picture::after { content: ""; } +plaintext::before { content: ""; } +plaintext::after { content: "</plaintext>"; } +pre::before { content: "<pre>"; } +pre::after { content: "</pre>"; } +progress::before { content: "<progress>"; } +progress::after { content: "</progress>"; } + +q::before { content: "<q>"; } +q::after { content: "</q>"; } + +rb::before { content: "<rb>"; } +rb::after { content: "</rb>"; } +rp::before { content: "<rp>"; } +rp::after { content: "</rp>"; } +rt::before { content: "<rt>"; } +rt::after { content: "</rt>"; } +rtc::before { content: "<rtc>"; } +rtc::after { content: "</rtc>"; } +ruby::before { content: "<ruby>"; } +ruby::after { content: "</ruby>"; } + +s::before { content: "<s>"; } +s::after { content: "</s>"; } +samp::before { content: "<samp>"; } +samp::after { content: "</samp>"; } +script::before { content: "<script>"; } +script::after { content: "</script>"; } +section::before { content: "<section>"; } +section::after { content: "</section>"; } +select::before { content: "<select>"; } +select::after { content: "</select>"; } +shadow::before { content: "<shadow>"; } +shadow::after { content: "</shadow>"; } +slot::before { content: "<slot>"; } +slot::after { content: "</slot>"; } +small::before { content: "<small>"; } +small::after { content: "</small>"; } +source::before { content: "<source>"; } +source::after { content: "</source>"; } +spacer::before { content: "<spacer>"; } +spacer::after { content: "</spacer>"; } +span::before { content: "<span>"; } +span::after { content: "</span>"; } +strike::before { content: "<strike>"; } +strike::after { content: "</strike>"; } +strong::before { content: "<strong>"; } +strong::after { content: "</strong>"; } +style::before { content: "<style>"; } +style::after { content: "<\/style>"; } +sub::before { content: "<sub>"; } +sub::after { content: "</sub>"; } +summary::before { content: "<summary>"; } +summary::after { content: "</summary>"; } +sup::before { content: "<sup>"; } +sup::after { content: "</sup>"; } + +table::before { content: "<table>"; } +table::after { content: "</table>"; } +tbody::before { content: "<tbody>"; } +tbody::after { content: "</tbody>"; } +td::before { content: "<td>"; } +td::after { content: "</td>"; } +template::before { content: "<template>"; } +template::after { content: "</template>"; } +textarea::before { content: "<textarea>"; } +textarea::after { content: "</textarea>"; } +tfoot::before { content: "<tfoot>"; } +tfoot::after { content: "</tfoot>"; } +th::before { content: "<th>"; } +th::after { content: "</th>"; } +thead::before { content: "<thead>"; } +thead::after { content: "</thead>"; } +time::before { content: "<time>"; } +time::after { content: "</time>"; } +title::before { content: "<title>"; } +title::after { content: "</title>"; } +tr::before { content: "<tr>"; } +tr::after { content: "</tr>"; } +track::before { content: "<track>"; } +track::after { content: "</track>"; } +tt::before { content: "<tt>"; } +tt::after { content: "</tt>"; } + +u::before { content: "<u>"; } +u::after { content: "</u>"; } +ul::before { content: "<ul>"; } +ul::after { content: "</ul>"; } + +var::before { content: "<var>"; } +var::after { content: "</var>"; } +video::before { content: "<video>"; } +video::after { content: "</video>"; } + +wbr::before { content: "<wbr>"; } +wbr::after { content: "</wbr>"; } + +xmp::before { content: "<xmp>"; } +xmp::after { content: "</xmp>"; } diff --git a/extensions/pagetop-bootsier/.gitattributes b/extensions/pagetop-bootsier/.gitattributes new file mode 100644 index 0000000..940d6a8 --- /dev/null +++ b/extensions/pagetop-bootsier/.gitattributes @@ -0,0 +1 @@ +static/** linguist-vendored diff --git a/extensions/pagetop-bootsier/Cargo.toml b/extensions/pagetop-bootsier/Cargo.toml new file mode 100644 index 0000000..6df6cf6 --- /dev/null +++ b/extensions/pagetop-bootsier/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "pagetop-bootsier" +version = "0.0.18" +edition = "2021" + +description = """ + Tema de PageTop basado en Bootstrap para aplicar su catálogo de estilos y componentes flexibles. +""" +categories = ["web-programming", "gui"] +keywords = ["pagetop", "theme", "bootstrap", "css", "js"] + +repository.workspace = true +homepage.workspace = true +license.workspace = true +authors.workspace = true + +[dependencies] +pagetop.workspace = true +serde.workspace = true + +[build-dependencies] +pagetop-build.workspace = true diff --git a/extensions/pagetop-bootsier/LICENSE-APACHE b/extensions/pagetop-bootsier/LICENSE-APACHE new file mode 100644 index 0000000..263ddac --- /dev/null +++ b/extensions/pagetop-bootsier/LICENSE-APACHE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2022 Manuel Cillero + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/extensions/pagetop-bootsier/LICENSE-MIT b/extensions/pagetop-bootsier/LICENSE-MIT new file mode 100644 index 0000000..cd8af3d --- /dev/null +++ b/extensions/pagetop-bootsier/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Manuel Cillero + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/extensions/pagetop-bootsier/README.md b/extensions/pagetop-bootsier/README.md new file mode 100644 index 0000000..84e11b5 --- /dev/null +++ b/extensions/pagetop-bootsier/README.md @@ -0,0 +1,100 @@ +<div align="center"> + +<h1>PageTop Bootsier</h1> + +<p>Tema de <strong>PageTop</strong> basado en Bootstrap para aplicar su catálogo de estilos y componentes flexibles.</p> + +[![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) +[![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) +[![Descargas](https://img.shields.io/crates/d/pagetop-bootsier.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-bootsier) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier#licencia) + +<br> +</div> + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# ⚡️ Guía rápida + +Igual que con otras extensiones, **añade la dependencia** a tu `Cargo.toml`: + +```toml +[dependencies] +pagetop-bootsier = "..." +``` + +**Declara la extensión** en tu aplicación (o extensión que la requiera). Recuerda que el orden en +`dependencies()` determina la prioridad relativa frente a las otras extensiones: + +```rust,no_run +use pagetop::prelude::*; + +struct MyApp; + +impl Extension for MyApp { + fn dependencies(&self) -> Vec<ExtensionRef> { + vec![ + // ... + &pagetop_bootsier::Bootsier, + // ... + ] + } +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&MyApp).run()?.await +} +``` + +Y **selecciona el tema en la configuración** de la aplicación: + +```toml +[app] +theme = "Bootsier" +``` + +…o **fuerza el tema por código** en una página concreta: + +```rust,no_run +use pagetop::prelude::*; + +async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { + Page::new(request) + .with_theme("Bootsier") + .add_child( + Block::new() + .with_title(L10n::l("sample_title")) + .add_child(Html::with(|cx| html! { + p { (L10n::l("sample_content").using(cx)) } + })), + ) + .render() +} +``` + + +# 🚧 Advertencia + +**PageTop** es un proyecto personal para aprender [Rust](https://www.rust-lang.org/es) y conocer su +ecosistema. Su API está sujeta a cambios frecuentes. No se recomienda su uso en producción, al menos +hasta que se libere la versión **1.0.0**. + + +# 📜 Licencia + +El código está disponible bajo una doble licencia: + + * **Licencia MIT** + ([LICENSE-MIT](LICENSE-MIT) o también https://opensource.org/licenses/MIT) + + * **Licencia Apache, Versión 2.0** + ([LICENSE-APACHE](LICENSE-APACHE) o también https://www.apache.org/licenses/LICENSE-2.0) + +Puedes elegir la licencia que prefieras. Este enfoque de doble licencia es el estándar de facto en +el ecosistema Rust. diff --git a/extensions/pagetop-bootsier/build.rs b/extensions/pagetop-bootsier/build.rs new file mode 100644 index 0000000..df7a275 --- /dev/null +++ b/extensions/pagetop-bootsier/build.rs @@ -0,0 +1,20 @@ +use pagetop_build::StaticFilesBundle; + +use std::env; +use std::path::Path; + +fn main() -> std::io::Result<()> { + StaticFilesBundle::from_scss("./static/scss/bootsier.scss", "bootstrap.min.css") + .with_name("bootsier_bs") + .build()?; + StaticFilesBundle::from_dir("./static/js", Some(bootstrap_js_files)) + .with_name("bootsier_js") + .build() +} + +fn bootstrap_js_files(path: &Path) -> bool { + let bootstrap_js = "bootstrap.bundle.min.js"; + // No filtra durante el desarrollo, solo en la compilación "release". + env::var("PROFILE").unwrap_or_else(|_| "release".to_string()) != "release" + || path.file_name().is_some_and(|f| f == bootstrap_js) +} diff --git a/extensions/pagetop-bootsier/src/config.rs b/extensions/pagetop-bootsier/src/config.rs new file mode 100644 index 0000000..6c2365b --- /dev/null +++ b/extensions/pagetop-bootsier/src/config.rs @@ -0,0 +1,41 @@ +//! Opciones de configuración del tema. +//! +//! Ejemplo: +//! +//! ```toml +//! [bootsier] +//! max_width = "90rem" +//! ``` +//! +//! Uso: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! use pagetop_bootsier::config; +//! +//! assert_eq!(config::SETTINGS.bootsier.max_width, UnitValue::Px(1440)); +//! ``` +//! +//! Consulta [`pagetop::config`] para ver cómo PageTop lee los archivos de configuración y aplica +//! los valores a los ajustes. + +use pagetop::prelude::*; + +use serde::Deserialize; + +include_config!(SETTINGS: Settings => [ + // [bootsier] + "bootsier.max_width" => "1440px", +]); + +#[derive(Debug, Deserialize)] +/// Tipos para la sección [`[bootsier]`](Bootsier) de [`SETTINGS`]. +pub struct Settings { + pub bootsier: Bootsier, +} +#[derive(Debug, Deserialize)] +/// Sección `[bootsier]` de la configuración. Forma parte de [`Settings`]. +pub struct Bootsier { + /// Ancho máximo predeterminado para la página, por ejemplo "100%" o "90rem". + pub max_width: UnitValue, +} diff --git a/extensions/pagetop-bootsier/src/lib.rs b/extensions/pagetop-bootsier/src/lib.rs new file mode 100644 index 0000000..76f9d1e --- /dev/null +++ b/extensions/pagetop-bootsier/src/lib.rs @@ -0,0 +1,134 @@ +/*! +<div align="center"> + +<h1>PageTop Bootsier</h1> + +<p>Tema de <strong>PageTop</strong> basado en Bootstrap para aplicar su catálogo de estilos y componentes flexibles.</p> + +[![Doc API](https://img.shields.io/docsrs/pagetop-bootsier?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-bootsier) +[![Crates.io](https://img.shields.io/crates/v/pagetop-bootsier.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-bootsier) +[![Descargas](https://img.shields.io/crates/d/pagetop-bootsier.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-bootsier) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/extensions/pagetop-bootsier#licencia) + +<br> +</div> + +## Sobre PageTop + +[PageTop](https://docs.rs/pagetop) es un entorno de desarrollo que reivindica la esencia de la web +clásica para crear soluciones web SSR (*renderizadas en el servidor*) modulares, extensibles y +configurables, basadas en HTML, CSS y JavaScript. + + +# ⚡️ Guía rápida + +Igual que con otras extensiones, **añade la dependencia** a tu `Cargo.toml`: + +```toml +[dependencies] +pagetop-bootsier = "..." +``` + +**Declara la extensión** en tu aplicación (o extensión que la requiera). Recuerda que el orden en +`dependencies()` determina la prioridad relativa frente a las otras extensiones: + +```rust,no_run +use pagetop::prelude::*; + +struct MyApp; + +impl Extension for MyApp { + fn dependencies(&self) -> Vec<ExtensionRef> { + vec![ + // ... + &pagetop_bootsier::Bootsier, + // ... + ] + } +} + +#[pagetop::main] +async fn main() -> std::io::Result<()> { + Application::prepare(&MyApp).run()?.await +} +``` + +Y **selecciona el tema en la configuración** de la aplicación: + +```toml +[app] +theme = "Bootsier" +``` + +…o **fuerza el tema por código** en una página concreta: + +```rust,no_run +use pagetop::prelude::*; + +async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { + Page::new(request) + .with_theme("Bootsier") + .add_child( + Block::new() + .with_title(L10n::l("sample_title")) + .add_child(Html::with(|cx| html! { + p { (L10n::l("sample_content").using(cx)) } + })), + ) + .render() +} +``` +*/ + +#![doc( + html_favicon_url = "https://git.cillero.es/manuelcillero/pagetop/raw/branch/main/static/favicon.ico" +)] + +use pagetop::prelude::*; + +include_locales!(LOCALES_BOOTSIER); + +// Versión de la librería Bootstrap. +const BOOTSTRAP_VERSION: &str = "5.3.8"; + +pub mod config; + +pub mod theme; + +/// *Prelude* del tema. +pub mod prelude { + pub use crate::config::*; + pub use crate::theme::*; +} + +/// El tema usa las mismas regiones predefinidas por [`DefaultRegions`]. +pub type BootsierRegions = DefaultRegions; + +/// Implementa el tema. +pub struct Bootsier; + +impl Extension for Bootsier { + fn theme(&self) -> Option<ThemeRef> { + Some(&Self) + } + + fn configure_service(&self, scfg: &mut service::web::ServiceConfig) { + static_files_service!(scfg, [bootsier_bs] => "/bootsier/bs"); + static_files_service!(scfg, [bootsier_js] => "/bootsier/js"); + } +} + +impl Theme for Bootsier { + fn after_render_page_body(&self, page: &mut Page) { + page.alter_assets(ContextOp::AddStyleSheet( + StyleSheet::from("/bootsier/bs/bootstrap.min.css") + .with_version(BOOTSTRAP_VERSION) + .with_weight(-90), + )) + .alter_assets(ContextOp::AddJavaScript( + JavaScript::defer("/bootsier/js/bootstrap.bundle.min.js") + .with_version(BOOTSTRAP_VERSION) + .with_weight(-90), + )); + } +} diff --git a/extensions/pagetop-bootsier/src/locale/en-US/bootsier.ftl b/extensions/pagetop-bootsier/src/locale/en-US/bootsier.ftl new file mode 100644 index 0000000..0e8969c --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/en-US/bootsier.ftl @@ -0,0 +1,5 @@ +e404-description = Oops! Page Not Found +e404-message = The page you are looking for may have been removed, had its name changed, or is temporarily unavailable. +e500-description = Oops! Unexpected Error +e500-message = We're having an issue. Please report this error to an administrator. +back-homepage = Back to homepage diff --git a/extensions/pagetop-bootsier/src/locale/en-US/components.ftl b/extensions/pagetop-bootsier/src/locale/en-US/components.ftl new file mode 100644 index 0000000..e3b0d6e --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/en-US/components.ftl @@ -0,0 +1,8 @@ +# Dropdown +dropdown_toggle = Toggle Dropdown + +# Offcanvas +offcanvas_close = Close + +# Navbar +toggle = Toggle navigation diff --git a/extensions/pagetop-bootsier/src/locale/en-US/regions.ftl b/extensions/pagetop-bootsier/src/locale/en-US/regions.ftl new file mode 100644 index 0000000..f3b76e2 --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/en-US/regions.ftl @@ -0,0 +1,9 @@ +header = Header +nav_branding = Navigation branding region +nav_main = Main navigation region +nav_additional = Additional navigation region (eg search form, social icons, etc) +breadcrumb = Breadcrumb +content = Main content +sidebar_first = Sidebar first +sidebar_second = Sidebar second +footer = Footer diff --git a/extensions/pagetop-bootsier/src/locale/es-ES/bootsier.ftl b/extensions/pagetop-bootsier/src/locale/es-ES/bootsier.ftl new file mode 100644 index 0000000..998b54f --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/es-ES/bootsier.ftl @@ -0,0 +1,5 @@ +e404-description = ¡Vaya! Página No Encontrada +e404-message = La página que está buscando puede haber sido eliminada, cambiada de nombre o no está disponible temporalmente. +e500-description = ¡Vaya! Error Inesperado +e500-message = Está ocurriendo una incidencia. Por favor, informe de este error a un administrador. +back-homepage = Volver al inicio diff --git a/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl b/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl new file mode 100644 index 0000000..ab7ff68 --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/es-ES/components.ftl @@ -0,0 +1,8 @@ +# Dropdown +dropdown_toggle = Mostrar/ocultar menú + +# Offcanvas +offcanvas_close = Cerrar + +# Navbar +toggle = Mostrar/ocultar navegación diff --git a/extensions/pagetop-bootsier/src/locale/es-ES/regions.ftl b/extensions/pagetop-bootsier/src/locale/es-ES/regions.ftl new file mode 100644 index 0000000..674fc4b --- /dev/null +++ b/extensions/pagetop-bootsier/src/locale/es-ES/regions.ftl @@ -0,0 +1,9 @@ +header = Cabecera +nav_branding = Navegación y marca +nav_main = Navegación principal +nav_additional = Navegación adicional (p.e. formulario de búsqueda, iconos sociales, etc.) +breadcrumb = Ruta de posicionamiento +content = Contenido principal +sidebar_first = Barra lateral primera +sidebar_second = Barra lateral segunda +footer = Pie diff --git a/extensions/pagetop-bootsier/src/theme.rs b/extensions/pagetop-bootsier/src/theme.rs new file mode 100644 index 0000000..2c6b575 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme.rs @@ -0,0 +1,40 @@ +//! Definiciones y componentes del tema. +//! +//! En esta página, el apartado **Modules** incluye las definiciones necesarias para los componentes +//! que se muestran en el apartado **Structs**, mientras que en **Enums** se listan los elementos +//! auxiliares del tema utilizados en clases y componentes. + +mod aux; +pub use aux::*; + +pub mod classes; + +// Container. +pub mod container; +#[doc(inline)] +pub use container::Container; + +// Dropdown. +pub mod dropdown; +#[doc(inline)] +pub use dropdown::Dropdown; + +// Image. +pub mod image; +#[doc(inline)] +pub use image::Image; + +// Nav. +pub mod nav; +#[doc(inline)] +pub use nav::Nav; + +// Navbar. +pub mod navbar; +#[doc(inline)] +pub use navbar::Navbar; + +// Offcanvas. +pub mod offcanvas; +#[doc(inline)] +pub use offcanvas::Offcanvas; diff --git a/extensions/pagetop-bootsier/src/theme/aux.rs b/extensions/pagetop-bootsier/src/theme/aux.rs new file mode 100644 index 0000000..99431fe --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux.rs @@ -0,0 +1,20 @@ +//! Colección de elementos auxiliares de Bootstrap para Bootsier. + +mod breakpoint; +pub use breakpoint::BreakPoint; + +mod color; +pub use color::{Color, Opacity}; +pub use color::{ColorBg, ColorText}; + +mod layout; +pub use layout::{ScaleSize, Side}; + +mod border; +pub use border::BorderColor; + +mod rounded; +pub use rounded::RoundedRadius; + +mod button; +pub use button::{ButtonColor, ButtonSize}; diff --git a/extensions/pagetop-bootsier/src/theme/aux/border.rs b/extensions/pagetop-bootsier/src/theme/aux/border.rs new file mode 100644 index 0000000..4388276 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/border.rs @@ -0,0 +1,87 @@ +use pagetop::prelude::*; + +use crate::theme::aux::Color; + +/// Colores `border-*` para los bordes ([`classes::Border`](crate::theme::classes::Border)). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum BorderColor { + /// No define ninguna clase. + #[default] + Default, + /// Genera internamente clases `border-{color}`. + Theme(Color), + /// Genera internamente clases `border-{color}-subtle` (un tono suavizado del color). + Subtle(Color), + /// Color negro. + Black, + /// Color blanco. + White, +} + +impl BorderColor { + const BORDER: &str = "border"; + const BORDER_PREFIX: &str = "border-"; + + // Devuelve el sufijo de la clase `border-*`, o `None` si no define ninguna clase. + #[rustfmt::skip] + #[inline] + const fn suffix(self) -> Option<&'static str> { + match self { + Self::Default => None, + Self::Theme(_) => Some(""), + Self::Subtle(_) => Some("-subtle"), + Self::Black => Some("-black"), + Self::White => Some("-white"), + } + } + + // Añade la clase `border-*` a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + match self { + Self::Theme(c) | Self::Subtle(c) => { + classes.push_str(Self::BORDER_PREFIX); + classes.push_str(c.as_str()); + } + _ => classes.push_str(Self::BORDER), + } + classes.push_str(suffix); + } + } + + /// Devuelve la clase `border-*` correspondiente al color de borde. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(BorderColor::Theme(Color::Primary).to_class(), "border-primary"); + /// assert_eq!(BorderColor::Subtle(Color::Warning).to_class(), "border-warning-subtle"); + /// assert_eq!(BorderColor::Black.to_class(), "border-black"); + /// assert_eq!(BorderColor::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + if let Some(suffix) = self.suffix() { + let base_len = match self { + Self::Theme(c) | Self::Subtle(c) => Self::BORDER_PREFIX.len() + c.as_str().len(), + _ => Self::BORDER.len(), + }; + let mut class = String::with_capacity(base_len + suffix.len()); + match self { + Self::Theme(c) | Self::Subtle(c) => { + class.push_str(Self::BORDER_PREFIX); + class.push_str(c.as_str()); + } + _ => class.push_str(Self::BORDER), + } + class.push_str(suffix); + return class; + } + String::new() + } +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs b/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs new file mode 100644 index 0000000..4d9a762 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/breakpoint.rs @@ -0,0 +1,114 @@ +use pagetop::prelude::*; + +/// Define los puntos de ruptura (*breakpoints*) para aplicar diseño *responsive*. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum BreakPoint { + /// **Menos de 576px**. Dispositivos muy pequeños: teléfonos en modo vertical. + #[default] + None, + /// **576px o más** - Dispositivos pequeños: teléfonos en modo horizontal. + SM, + /// **768px o más** - Dispositivos medianos: tabletas. + MD, + /// **992px o más** - Dispositivos grandes: puestos de escritorio. + LG, + /// **1200px o más** - Dispositivos muy grandes: puestos de escritorio grandes. + XL, + /// **1400px o más** - Dispositivos extragrandes: puestos de escritorio más grandes. + XXL, +} + +impl BreakPoint { + // Devuelve la identificación del punto de ruptura. + #[rustfmt::skip] + #[inline] + pub(crate) const fn as_str(self) -> &'static str { + match self { + Self::None => "", + Self::SM => "sm", + Self::MD => "md", + Self::LG => "lg", + Self::XL => "xl", + Self::XXL => "xxl", + } + } + + // Añade el punto de ruptura con un prefijo y un sufijo (opcional) separados por un guion `-` a + // la cadena de clases. + // + // - Para `None` - `prefix` o `prefix-suffix` (si `suffix` no está vacío). + // - Para `SM..XXL` - `prefix-{breakpoint}` o `prefix-{breakpoint}-{suffix}`. + #[inline] + pub(crate) fn push_class(self, classes: &mut String, prefix: &str, suffix: &str) { + if prefix.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + match self { + Self::None => classes.push_str(prefix), + _ => { + classes.push_str(prefix); + classes.push('-'); + classes.push_str(self.as_str()); + } + } + if !suffix.is_empty() { + classes.push('-'); + classes.push_str(suffix); + } + } + + // Devuelve la clase para el punto de ruptura, con un prefijo y un sufijo opcional, separados + // por un guion `-`. + // + // - Para `None` - `prefix` o `prefix-suffix` (si `suffix` no está vacío). + // - Para `SM..XXL` - `prefix-{breakpoint}` o `prefix-{breakpoint}-{suffix}`. + // - Si `prefix` está vacío devuelve `""`. + // + // # Ejemplos + // + // ```rust + // # use pagetop_bootsier::prelude::*; + // let bp = BreakPoint::MD; + // assert_eq!(bp.class_with("col", ""), "col-md"); + // assert_eq!(bp.class_with("col", "6"), "col-md-6"); + // + // let bp = BreakPoint::None; + // assert_eq!(bp.class_with("offcanvas", ""), "offcanvas"); + // assert_eq!(bp.class_with("col", "12"), "col-12"); + // + // let bp = BreakPoint::LG; + // assert_eq!(bp.class_with("", "3"), ""); + // ``` + #[inline] + pub(crate) fn class_with(self, prefix: &str, suffix: &str) -> String { + if prefix.is_empty() { + return String::new(); + } + + let bp = self.as_str(); + let has_bp = !bp.is_empty(); + let has_suffix = !suffix.is_empty(); + + let mut len = prefix.len(); + if has_bp { + len += 1 + bp.len(); + } + if has_suffix { + len += 1 + suffix.len(); + } + let mut class = String::with_capacity(len); + class.push_str(prefix); + if has_bp { + class.push('-'); + class.push_str(bp); + } + if has_suffix { + class.push('-'); + class.push_str(suffix); + } + class + } +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/button.rs b/extensions/pagetop-bootsier/src/theme/aux/button.rs new file mode 100644 index 0000000..0d1df87 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/button.rs @@ -0,0 +1,143 @@ +use pagetop::prelude::*; + +use crate::theme::aux::Color; + +// **< ButtonColor >******************************************************************************** + +/// Variantes de color `btn-*` para botones. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum ButtonColor { + /// No define ninguna clase. + #[default] + Default, + /// Genera internamente clases `btn-{color}` (botón relleno). + Background(Color), + /// Genera `btn-outline-{color}` (fondo transparente y contorno con borde). + Outline(Color), + /// Aplica estilo de los enlaces (`btn-link`), sin caja ni fondo, heredando el color de texto. + Link, +} + +impl ButtonColor { + const BTN_PREFIX: &str = "btn-"; + const BTN_OUTLINE_PREFIX: &str = "btn-outline-"; + const BTN_LINK: &str = "btn-link"; + + // Añade la clase `btn-*` a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if let Self::Default = self { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + match self { + Self::Default => unreachable!(), + Self::Background(c) => { + classes.push_str(Self::BTN_PREFIX); + classes.push_str(c.as_str()); + } + Self::Outline(c) => { + classes.push_str(Self::BTN_OUTLINE_PREFIX); + classes.push_str(c.as_str()); + } + Self::Link => { + classes.push_str(Self::BTN_LINK); + } + } + } + + /// Devuelve la clase `btn-*` correspondiente al color del botón. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!( + /// ButtonColor::Background(Color::Primary).to_class(), + /// "btn-primary" + /// ); + /// assert_eq!( + /// ButtonColor::Outline(Color::Danger).to_class(), + /// "btn-outline-danger" + /// ); + /// assert_eq!(ButtonColor::Link.to_class(), "btn-link"); + /// assert_eq!(ButtonColor::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + match self { + Self::Default => String::new(), + Self::Background(c) => { + let color = c.as_str(); + let mut class = String::with_capacity(Self::BTN_PREFIX.len() + color.len()); + class.push_str(Self::BTN_PREFIX); + class.push_str(color); + class + } + Self::Outline(c) => { + let color = c.as_str(); + let mut class = String::with_capacity(Self::BTN_OUTLINE_PREFIX.len() + color.len()); + class.push_str(Self::BTN_OUTLINE_PREFIX); + class.push_str(color); + class + } + Self::Link => Self::BTN_LINK.to_string(), + } + } +} + +// **< ButtonSize >********************************************************************************* + +/// Tamaño visual de un botón. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum ButtonSize { + /// Tamaño por defecto del tema (no añade clase). + #[default] + Default, + /// Botón compacto. + Small, + /// Botón destacado/grande. + Large, +} + +impl ButtonSize { + const BTN_SM: &str = "btn-sm"; + const BTN_LG: &str = "btn-lg"; + + // Añade la clase de tamaño `btn-sm` o `btn-lg` a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if let Self::Default = self { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + match self { + Self::Default => unreachable!(), + Self::Small => classes.push_str(Self::BTN_SM), + Self::Large => classes.push_str(Self::BTN_LG), + } + } + + /// Devuelve la clase `btn-sm` o `btn-lg` correspondiente al tamaño del botón. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(ButtonSize::Small.to_class(), "btn-sm"); + /// assert_eq!(ButtonSize::Large.to_class(), "btn-lg"); + /// assert_eq!(ButtonSize::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + match self { + Self::Default => String::new(), + Self::Small => Self::BTN_SM.to_string(), + Self::Large => Self::BTN_LG.to_string(), + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/color.rs b/extensions/pagetop-bootsier/src/theme/aux/color.rs new file mode 100644 index 0000000..480ff3d --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/color.rs @@ -0,0 +1,375 @@ +use pagetop::prelude::*; + +// **< Color >************************************************************************************** + +/// Paleta de colores temáticos. +/// +/// Equivalen a los nombres estándar definidos por Bootstrap (`primary`, `secondary`, `success`, +/// etc.). Este tipo enumerado sirve de base para componer las clases de color para fondo +/// ([`classes::Background`](crate::theme::classes::Background)), bordes +/// ([`classes::Border`](crate::theme::classes::Border)) y texto +/// ([`classes::Text`](crate::theme::classes::Text)). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Color { + #[default] + Primary, + Secondary, + Success, + Info, + Warning, + Danger, + Light, + Dark, +} + +impl Color { + // Devuelve el nombre del color. + #[rustfmt::skip] + #[inline] + pub(crate) const fn as_str(self) -> &'static str { + match self { + Self::Primary => "primary", + Self::Secondary => "secondary", + Self::Success => "success", + Self::Info => "info", + Self::Warning => "warning", + Self::Danger => "danger", + Self::Light => "light", + Self::Dark => "dark", + } + } + + /* Añade el nombre del color a la cadena de clases (reservado). + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(self.as_str()); + } */ + + /// Devuelve la clase correspondiente al color. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(Color::Primary.to_class(), "primary"); + /// assert_eq!(Color::Danger.to_class(), "danger"); + /// ``` + #[inline] + pub fn to_class(self) -> String { + self.as_str().to_owned() + } +} + +// **< Opacity >************************************************************************************ + +/// Niveles de opacidad (`opacity-*`). +/// +/// Se usa normalmente para graduar la transparencia del color de fondo `bg-opacity-*` +/// ([`classes::Background`](crate::theme::classes::Background)), de los bordes `border-opacity-*` +/// ([`classes::Border`](crate::theme::classes::Border)) o del texto `text-opacity-*` +/// ([`classes::Text`](crate::theme::classes::Text)). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Opacity { + /// No define ninguna clase. + #[default] + Default, + /// Permite generar clases `*-opacity-100` (100% de opacidad). + Opaque, + /// Permite generar clases `*-opacity-75` (75%). + SemiOpaque, + /// Permite generar clases `*-opacity-50` (50%). + Half, + /// Permite generar clases `*-opacity-25` (25%). + SemiTransparent, + /// Permite generar clases `*-opacity-10` (10%). + AlmostTransparent, + /// Permite generar clases `*-opacity-0` (0%, totalmente transparente). + Transparent, +} + +impl Opacity { + const OPACITY: &str = "opacity"; + const OPACITY_PREFIX: &str = "-opacity"; + + // Devuelve el sufijo para `*opacity-*`, o `None` si no define ninguna clase. + #[rustfmt::skip] + #[inline] + const fn suffix(self) -> Option<&'static str> { + match self { + Self::Default => None, + Self::Opaque => Some("-100"), + Self::SemiOpaque => Some("-75"), + Self::Half => Some("-50"), + Self::SemiTransparent => Some("-25"), + Self::AlmostTransparent => Some("-10"), + Self::Transparent => Some("-0"), + } + } + + // Añade la opacidad a la cadena de clases usando el prefijo dado (`bg`, `border`, `text`, o + // vacío para `opacity-*`). + #[inline] + pub(crate) fn push_class(self, classes: &mut String, prefix: &str) { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + if prefix.is_empty() { + classes.push_str(Self::OPACITY); + } else { + classes.push_str(prefix); + classes.push_str(Self::OPACITY_PREFIX); + } + classes.push_str(suffix); + } + } + + // Devuelve la clase de opacidad con el prefijo dado (`bg`, `border`, `text`, o vacío para + // `opacity-*`). + // + // # Ejemplos + // + // ```rust + // # use pagetop_bootsier::prelude::*; + // assert_eq!(Opacity::Opaque.class_with(""), "opacity-100"); + // assert_eq!(Opacity::Half.class_with("bg"), "bg-opacity-50"); + // assert_eq!(Opacity::SemiTransparent.class_with("text"), "text-opacity-25"); + // assert_eq!(Opacity::Default.class_with("bg"), ""); + // ``` + #[inline] + pub(crate) fn class_with(self, prefix: &str) -> String { + if let Some(suffix) = self.suffix() { + let base_len = if prefix.is_empty() { + Self::OPACITY.len() + } else { + prefix.len() + Self::OPACITY_PREFIX.len() + }; + let mut class = String::with_capacity(base_len + suffix.len()); + if prefix.is_empty() { + class.push_str(Self::OPACITY); + } else { + class.push_str(prefix); + class.push_str(Self::OPACITY_PREFIX); + } + class.push_str(suffix); + return class; + } + String::new() + } + + /// Devuelve la clase de opacidad `opacity-*`. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(Opacity::Opaque.to_class(), "opacity-100"); + /// assert_eq!(Opacity::Half.to_class(), "opacity-50"); + /// assert_eq!(Opacity::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + self.class_with("") + } +} + +// **< ColorBg >************************************************************************************ + +/// Colores `bg-*` para el fondo. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum ColorBg { + /// No define ninguna clase. + #[default] + Default, + /// Fondo predefinido del tema (`bg-body`). + Body, + /// Fondo predefinido del tema (`bg-body-secondary`). + BodySecondary, + /// Fondo predefinido del tema (`bg-body-tertiary`). + BodyTertiary, + /// Genera internamente clases `bg-{color}` (p. ej., `bg-primary`). + Theme(Color), + /// Genera internamente clases `bg-{color}-subtle` (un tono suavizado del color). + Subtle(Color), + /// Color negro. + Black, + /// Color blanco. + White, + /// No aplica ningún color de fondo (`bg-transparent`). + Transparent, +} + +impl ColorBg { + const BG: &str = "bg"; + const BG_PREFIX: &str = "bg-"; + + // Devuelve el sufijo de la clase `bg-*`, o `None` si no define ninguna clase. + #[rustfmt::skip] + #[inline] + const fn suffix(self) -> Option<&'static str> { + match self { + Self::Default => None, + Self::Body => Some("-body"), + Self::BodySecondary => Some("-body-secondary"), + Self::BodyTertiary => Some("-body-tertiary"), + Self::Theme(_) => Some(""), + Self::Subtle(_) => Some("-subtle"), + Self::Black => Some("-black"), + Self::White => Some("-white"), + Self::Transparent => Some("-transparent"), + } + } + + // Añade la clase de fondo `bg-*` a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + match self { + Self::Theme(c) | Self::Subtle(c) => { + classes.push_str(Self::BG_PREFIX); + classes.push_str(c.as_str()); + } + _ => classes.push_str(Self::BG), + } + classes.push_str(suffix); + } + } + + /// Devuelve la clase `bg-*` correspondiente al fondo. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(ColorBg::Body.to_class(), "bg-body"); + /// assert_eq!(ColorBg::Theme(Color::Primary).to_class(), "bg-primary"); + /// assert_eq!(ColorBg::Subtle(Color::Warning).to_class(), "bg-warning-subtle"); + /// assert_eq!(ColorBg::Transparent.to_class(), "bg-transparent"); + /// assert_eq!(ColorBg::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + if let Some(suffix) = self.suffix() { + let base_len = match self { + Self::Theme(c) | Self::Subtle(c) => Self::BG_PREFIX.len() + c.as_str().len(), + _ => Self::BG.len(), + }; + let mut class = String::with_capacity(base_len + suffix.len()); + match self { + Self::Theme(c) | Self::Subtle(c) => { + class.push_str(Self::BG_PREFIX); + class.push_str(c.as_str()); + } + _ => class.push_str(Self::BG), + } + class.push_str(suffix); + return class; + } + String::new() + } +} + +// **< ColorText >********************************************************************************** + +/// Colores `text-*` para el texto. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum ColorText { + /// No define ninguna clase. + #[default] + Default, + /// Color predefinido del tema (`text-body`). + Body, + /// Color predefinido del tema (`text-body-emphasis`). + BodyEmphasis, + /// Color predefinido del tema (`text-body-secondary`). + BodySecondary, + /// Color predefinido del tema (`text-body-tertiary`). + BodyTertiary, + /// Genera internamente clases `text-{color}`. + Theme(Color), + /// Genera internamente clases `text-{color}-emphasis` (mayor contraste acorde al tema). + Emphasis(Color), + /// Color negro. + Black, + /// Color blanco. + White, +} + +impl ColorText { + const TEXT: &str = "text"; + const TEXT_PREFIX: &str = "text-"; + + // Devuelve el sufijo de la clase `text-*`, o `None` si no define ninguna clase. + #[rustfmt::skip] + #[inline] + const fn suffix(self) -> Option<&'static str> { + match self { + Self::Default => None, + Self::Body => Some("-body"), + Self::BodyEmphasis => Some("-body-emphasis"), + Self::BodySecondary => Some("-body-secondary"), + Self::BodyTertiary => Some("-body-tertiary"), + Self::Theme(_) => Some(""), + Self::Emphasis(_) => Some("-emphasis"), + Self::Black => Some("-black"), + Self::White => Some("-white"), + } + } + + // Añade la clase de texto `text-*` a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + match self { + Self::Theme(c) | Self::Emphasis(c) => { + classes.push_str(Self::TEXT_PREFIX); + classes.push_str(c.as_str()); + } + _ => classes.push_str(Self::TEXT), + } + classes.push_str(suffix); + } + } + + /// Devuelve la clase `text-*` correspondiente al color del texto. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(ColorText::Body.to_class(), "text-body"); + /// assert_eq!(ColorText::Theme(Color::Primary).to_class(), "text-primary"); + /// assert_eq!(ColorText::Emphasis(Color::Danger).to_class(), "text-danger-emphasis"); + /// assert_eq!(ColorText::Black.to_class(), "text-black"); + /// assert_eq!(ColorText::Default.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + if let Some(suffix) = self.suffix() { + let base_len = match self { + Self::Theme(c) | Self::Emphasis(c) => Self::TEXT_PREFIX.len() + c.as_str().len(), + _ => Self::TEXT.len(), + }; + let mut class = String::with_capacity(base_len + suffix.len()); + match self { + Self::Theme(c) | Self::Emphasis(c) => { + class.push_str(Self::TEXT_PREFIX); + class.push_str(c.as_str()); + } + _ => class.push_str(Self::TEXT), + } + class.push_str(suffix); + return class; + } + String::new() + } +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/layout.rs b/extensions/pagetop-bootsier/src/theme/aux/layout.rs new file mode 100644 index 0000000..1d35158 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/layout.rs @@ -0,0 +1,104 @@ +use pagetop::prelude::*; + +// **< ScaleSize >********************************************************************************** + +/// Escala discreta de tamaños para definir clases utilitarias. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum ScaleSize { + /// Sin tamaño (no define ninguna clase). + #[default] + None, + /// Tamaño automático. + Auto, + /// Escala cero. + Zero, + /// Escala uno. + One, + /// Escala dos. + Two, + /// Escala tres. + Three, + /// Escala cuatro. + Four, + /// Escala cinco. + Five, +} + +impl ScaleSize { + // Devuelve el sufijo para el tamaño (`"-0"`, `"-1"`, etc.), o `None` si no define ninguna + // clase, o `""` para el tamaño automático. + #[rustfmt::skip] + #[inline] + const fn suffix(self) -> Option<&'static str> { + match self { + Self::None => None, + Self::Auto => Some(""), + Self::Zero => Some("-0"), + Self::One => Some("-1"), + Self::Two => Some("-2"), + Self::Three => Some("-3"), + Self::Four => Some("-4"), + Self::Five => Some("-5"), + } + } + + // Añade el tamaño a la cadena de clases usando el prefijo dado. + #[inline] + pub(crate) fn push_class(self, classes: &mut String, prefix: &str) { + if !prefix.is_empty() { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(prefix); + classes.push_str(suffix); + } + } + } + + /* Devuelve la clase del tamaño para el prefijo, o una cadena vacía si no aplica (reservado). + // + // # Ejemplo + // + // ```rust + // # use pagetop_bootsier::prelude::*; + // assert_eq!(ScaleSize::Auto.class_with("border"), "border"); + // assert_eq!(ScaleSize::Zero.class_with("m"), "m-0"); + // assert_eq!(ScaleSize::Three.class_with("p"), "p-3"); + // assert_eq!(ScaleSize::None.class_with("border"), ""); + // ``` + #[inline] + pub(crate) fn class_with(self, prefix: &str) -> String { + if !prefix.is_empty() { + if let Some(suffix) = self.suffix() { + let mut class = String::with_capacity(prefix.len() + suffix.len()); + class.push_str(prefix); + class.push_str(suffix); + return class; + } + } + String::new() + } */ +} + +// **< Side >*************************************************************************************** + +/// Lados sobre los que aplicar una clase utilitaria (respetando LTR/RTL). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Side { + /// Todos los lados. + #[default] + All, + /// Lado superior. + Top, + /// Lado inferior. + Bottom, + /// Lado lógico de inicio (respetando RTL). + Start, + /// Lado lógico de fin (respetando RTL). + End, + /// Lados lógicos laterales (abreviatura *x*). + LeftAndRight, + /// Lados superior e inferior (abreviatura *y*). + TopAndBottom, +} diff --git a/extensions/pagetop-bootsier/src/theme/aux/rounded.rs b/extensions/pagetop-bootsier/src/theme/aux/rounded.rs new file mode 100644 index 0000000..20e061d --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/aux/rounded.rs @@ -0,0 +1,117 @@ +use pagetop::prelude::*; + +/// Radio para el redondeo de esquinas ([`classes::Rounded`](crate::theme::classes::Rounded)). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum RoundedRadius { + /// No define ninguna clase. + #[default] + None, + /// Genera `rounded` (radio por defecto del tema). + Default, + /// Genera `rounded-0` (sin redondeo). + Zero, + /// Genera `rounded-1`. + Scale1, + /// Genera `rounded-2`. + Scale2, + /// Genera `rounded-3`. + Scale3, + /// Genera `rounded-4`. + Scale4, + /// Genera `rounded-5`. + Scale5, + /// Genera `rounded-circle`. + Circle, + /// Genera `rounded-pill`. + Pill, +} + +impl RoundedRadius { + const ROUNDED: &str = "rounded"; + + // Devuelve el sufijo para `*rounded-*`, o `None` si no define ninguna clase, o `""` para el + // redondeo por defecto. + #[rustfmt::skip] + #[inline] + const fn suffix(self) -> Option<&'static str> { + match self { + Self::None => None, + Self::Default => Some(""), + Self::Zero => Some("-0"), + Self::Scale1 => Some("-1"), + Self::Scale2 => Some("-2"), + Self::Scale3 => Some("-3"), + Self::Scale4 => Some("-4"), + Self::Scale5 => Some("-5"), + Self::Circle => Some("-circle"), + Self::Pill => Some("-pill"), + } + } + + // Añade el redondeo de esquinas a la cadena de clases usando el prefijo dado (`rounded-top`, + // `rounded-bottom-start`, o vacío para `rounded-*`). + #[inline] + pub(crate) fn push_class(self, classes: &mut String, prefix: &str) { + if let Some(suffix) = self.suffix() { + if !classes.is_empty() { + classes.push(' '); + } + if prefix.is_empty() { + classes.push_str(Self::ROUNDED); + } else { + classes.push_str(prefix); + } + classes.push_str(suffix); + } + } + + // Devuelve la clase para el redondeo de esquinas con el prefijo dado (`rounded-top`, + // `rounded-bottom-start`, o vacío para `rounded-*`). + // + // # Ejemplos + // + // ```rust + // # use pagetop_bootsier::prelude::*; + // assert_eq!(RoundedRadius::Scale2.class_with(""), "rounded-2"); + // assert_eq!(RoundedRadius::Zero.class_with("rounded-top"), "rounded-top-0"); + // assert_eq!(RoundedRadius::Scale3.class_with("rounded-top-end"), "rounded-top-end-3"); + // assert_eq!(RoundedRadius::Circle.class_with(""), "rounded-circle"); + // assert_eq!(RoundedRadius::None.class_with("rounded-bottom-start"), ""); + // ``` + #[inline] + pub(crate) fn class_with(self, prefix: &str) -> String { + if let Some(suffix) = self.suffix() { + let base_len = if prefix.is_empty() { + Self::ROUNDED.len() + } else { + prefix.len() + }; + let mut class = String::with_capacity(base_len + suffix.len()); + if prefix.is_empty() { + class.push_str(Self::ROUNDED); + } else { + class.push_str(prefix); + } + class.push_str(suffix); + return class; + } + String::new() + } + + /// Devuelve la clase `rounded-*` para el redondeo de esquinas. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop_bootsier::prelude::*; + /// assert_eq!(RoundedRadius::Default.to_class(), "rounded"); + /// assert_eq!(RoundedRadius::Zero.to_class(), "rounded-0"); + /// assert_eq!(RoundedRadius::Scale3.to_class(), "rounded-3"); + /// assert_eq!(RoundedRadius::Circle.to_class(), "rounded-circle"); + /// assert_eq!(RoundedRadius::None.to_class(), ""); + /// ``` + #[inline] + pub fn to_class(self) -> String { + self.class_with("") + } +} diff --git a/extensions/pagetop-bootsier/src/theme/classes.rs b/extensions/pagetop-bootsier/src/theme/classes.rs new file mode 100644 index 0000000..9e6c234 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/classes.rs @@ -0,0 +1,13 @@ +//! Conjunto de clases para aplicar en componentes del tema. + +mod color; +pub use color::{Background, Text}; + +mod border; +pub use border::Border; + +mod rounded; +pub use rounded::Rounded; + +mod layout; +pub use layout::{Margin, Padding}; diff --git a/extensions/pagetop-bootsier/src/theme/classes/border.rs b/extensions/pagetop-bootsier/src/theme/classes/border.rs new file mode 100644 index 0000000..3095498 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/classes/border.rs @@ -0,0 +1,175 @@ +use pagetop::prelude::*; + +use crate::theme::aux::{BorderColor, Opacity, ScaleSize, Side}; + +/// Clases para crear **bordes**. +/// +/// Permite: +/// +/// - Iniciar un borde sin tamaño inicial (`Border::default()`). +/// - Crear un borde con tamaño por defecto (`Border::new()`). +/// - Ajustar el tamaño de cada **lado lógico** (`side`, respetando LTR/RTL). +/// - Definir un tamaño **global** para todo el borde (`size`). +/// - Aplicar un **color** al borde (`BorderColor`). +/// - Aplicar un nivel de **opacidad** (`Opacity`). +/// +/// # Comportamiento aditivo / sustractivo +/// +/// - **Aditivo**: basta con crear un borde sin tamaño con `classes::Border::default()` para ir +/// añadiendo cada lado lógico con el tamaño deseado usando `ScaleSize::{One..Five}`. +/// +/// - **Sustractivo**: se crea un borde con tamaño predefinido, p. ej. usando +/// `classes::Border::new()` o `classes::Border::with(ScaleSize::Two)` y eliminar los lados +/// deseados con `ScaleSize::Zero`. +/// +/// - **Anchos diferentes por lado**: usando `ScaleSize::{Zero..Five}` en cada lado deseado. +/// +/// # Ejemplos +/// +/// **Borde global:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = classes::Border::with(ScaleSize::Two); +/// assert_eq!(b.to_class(), "border-2"); +/// ``` +/// +/// **Aditivo (solo borde superior):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = classes::Border::default().with_side(Side::Top, ScaleSize::One); +/// assert_eq!(b.to_class(), "border-top-1"); +/// ``` +/// +/// **Sustractivo (borde global menos el superior):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = classes::Border::new().with_side(Side::Top, ScaleSize::Zero); +/// assert_eq!(b.to_class(), "border border-top-0"); +/// ``` +/// +/// **Ancho por lado (lado lógico inicial a 2 y final a 4):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = classes::Border::default() +/// .with_side(Side::Start, ScaleSize::Two) +/// .with_side(Side::End, ScaleSize::Four); +/// assert_eq!(b.to_class(), "border-end-4 border-start-2"); +/// ``` +/// +/// **Combinado (ejemplo completo):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let b = classes::Border::new() // Borde por defecto. +/// .with_side(Side::Top, ScaleSize::Zero) // Quita borde superior. +/// .with_side(Side::End, ScaleSize::Three) // Ancho 3 para el lado lógico final. +/// .with_color(BorderColor::Theme(Color::Primary)) +/// .with_opacity(Opacity::Half); +/// +/// assert_eq!(b.to_class(), "border border-top-0 border-end-3 border-primary border-opacity-50"); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub struct Border { + all : ScaleSize, + top : ScaleSize, + end : ScaleSize, + bottom : ScaleSize, + start : ScaleSize, + color : BorderColor, + opacity: Opacity, +} + +impl Border { + /// Prepara un borde del tamaño predefinido. Equivale a `border` (ancho por defecto del tema). + pub fn new() -> Self { + Self::with(ScaleSize::Auto) + } + + /// Crea un borde **con un tamaño global** (`size`). + pub fn with(size: ScaleSize) -> Self { + Self::default().with_side(Side::All, size) + } + + // **< Border BUILDER >************************************************************************* + + pub fn with_side(mut self, side: Side, size: ScaleSize) -> Self { + match side { + Side::All => self.all = size, + Side::Top => self.top = size, + Side::Bottom => self.bottom = size, + Side::Start => self.start = size, + Side::End => self.end = size, + Side::LeftAndRight => { + self.start = size; + self.end = size; + } + Side::TopAndBottom => { + self.top = size; + self.bottom = size; + } + }; + self + } + + /// Establece el color del borde. + pub fn with_color(mut self, color: BorderColor) -> Self { + self.color = color; + self + } + + /// Establece la opacidad del borde. + pub fn with_opacity(mut self, opacity: Opacity) -> Self { + self.opacity = opacity; + self + } + + // **< Border HELPERS >************************************************************************* + + /// Añade las clases de borde a la cadena de clases. + /// + /// Concatena, en este orden, las clases para *global*, `top`, `end`, `bottom`, `start`, + /// *color* y *opacidad*; respetando LTR/RTL y omitiendo las definiciones vacías. + #[rustfmt::skip] + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + self.all .push_class(classes, "border"); + self.top .push_class(classes, "border-top"); + self.end .push_class(classes, "border-end"); + self.bottom .push_class(classes, "border-bottom"); + self.start .push_class(classes, "border-start"); + self.color .push_class(classes); + self.opacity.push_class(classes, "border"); + } + + /// Devuelve las clases de borde como cadena (`"border-2"`, + /// `"border border-top-0 border-end-3 border-primary border-opacity-50"`, etc.). + /// + /// Si no se define ningún tamaño, color ni opacidad, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let mut classes = String::new(); + self.push_class(&mut classes); + classes + } +} + +/// Atajo para crear un [`classes::Border`](crate::theme::classes::Border) a partir de un tamaño +/// [`ScaleSize`] aplicado a todo el borde. +/// +/// # Ejemplos +/// +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// // Convertir explícitamente con `From::from`: +/// let b = classes::Border::from(ScaleSize::Two); +/// assert_eq!(b.to_class(), "border-2"); +/// +/// // Convertir implícitamente con `into()`: +/// let b: classes::Border = ScaleSize::Auto.into(); +/// assert_eq!(b.to_class(), "border"); +/// ``` +impl From<ScaleSize> for Border { + fn from(size: ScaleSize) -> Self { + Self::with(size) + } +} diff --git a/extensions/pagetop-bootsier/src/theme/classes/color.rs b/extensions/pagetop-bootsier/src/theme/classes/color.rs new file mode 100644 index 0000000..162b784 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/classes/color.rs @@ -0,0 +1,230 @@ +use pagetop::prelude::*; + +use crate::theme::aux::{ColorBg, ColorText, Opacity}; + +// **< Background >********************************************************************************* + +/// Clases para establecer **color/opacidad del fondo**. +/// +/// # Ejemplos +/// +/// ``` +/// # use pagetop_bootsier::prelude::*; +/// // Sin clases. +/// let s = classes::Background::new(); +/// assert_eq!(s.to_class(), ""); +/// +/// // Sólo color de fondo. +/// let s = classes::Background::with(ColorBg::Theme(Color::Primary)); +/// assert_eq!(s.to_class(), "bg-primary"); +/// +/// // Color más opacidad. +/// let s = classes::Background::with(ColorBg::BodySecondary).with_opacity(Opacity::Half); +/// assert_eq!(s.to_class(), "bg-body-secondary bg-opacity-50"); +/// +/// // Usando `From<ColorBg>`. +/// let s: classes::Background = ColorBg::Black.into(); +/// assert_eq!(s.to_class(), "bg-black"); +/// +/// // Usando `From<(ColorBg, Opacity)>`. +/// let s: classes::Background = (ColorBg::White, Opacity::SemiTransparent).into(); +/// assert_eq!(s.to_class(), "bg-white bg-opacity-25"); +/// ``` +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub struct Background { + color: ColorBg, + opacity: Opacity, +} + +impl Background { + /// Prepara un nuevo estilo para aplicar al fondo. + pub fn new() -> Self { + Self::default() + } + + /// Crea un estilo fijando el color de fondo (`bg-*`). + pub fn with(color: ColorBg) -> Self { + Self::default().with_color(color) + } + + // **< Background BUILDER >********************************************************************* + + /// Establece el color de fondo (`bg-*`). + pub fn with_color(mut self, color: ColorBg) -> Self { + self.color = color; + self + } + + /// Establece la opacidad del fondo (`bg-opacity-*`). + pub fn with_opacity(mut self, opacity: Opacity) -> Self { + self.opacity = opacity; + self + } + + // **< Background HELPERS >********************************************************************* + + /// Añade las clases de fondo a la cadena de clases. + /// + /// Concatena, en este orden, color del fondo (`bg-*`) y opacidad (`bg-opacity-*`), + /// omitiendo los fragmentos vacíos. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + self.color.push_class(classes); + self.opacity.push_class(classes, "bg"); + } + + /// Devuelve las clases de fondo como cadena (`"bg-primary"`, `"bg-body-secondary bg-opacity-50"`, etc.). + /// + /// Si no se define ni color ni opacidad, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let mut classes = String::new(); + self.push_class(&mut classes); + classes + } +} + +impl From<(ColorBg, Opacity)> for Background { + /// Atajo para crear un [`classes::Background`](crate::theme::classes::Background) a partir del color de fondo y + /// la opacidad. + /// + /// # Ejemplo + /// + /// ``` + /// # use pagetop_bootsier::prelude::*; + /// let s: classes::Background = (ColorBg::White, Opacity::SemiTransparent).into(); + /// assert_eq!(s.to_class(), "bg-white bg-opacity-25"); + /// ``` + fn from((color, opacity): (ColorBg, Opacity)) -> Self { + Background::with(color).with_opacity(opacity) + } +} + +impl From<ColorBg> for Background { + /// Atajo para crear un [`classes::Background`](crate::theme::classes::Background) a partir del color de fondo. + /// + /// # Ejemplo + /// + /// ``` + /// # use pagetop_bootsier::prelude::*; + /// let s: classes::Background = ColorBg::Black.into(); + /// assert_eq!(s.to_class(), "bg-black"); + /// ``` + fn from(color: ColorBg) -> Self { + Background::with(color) + } +} + +// **< Text >*************************************************************************************** + +/// Clases para establecer **color/opacidad del texto**. +/// +/// # Ejemplos +/// +/// ``` +/// # use pagetop_bootsier::prelude::*; +/// // Sin clases. +/// let s = classes::Text::new(); +/// assert_eq!(s.to_class(), ""); +/// +/// // Sólo color del texto. +/// let s = classes::Text::with(ColorText::Theme(Color::Primary)); +/// assert_eq!(s.to_class(), "text-primary"); +/// +/// // Color del texto y opacidad. +/// let s = classes::Text::new().with_color(ColorText::White).with_opacity(Opacity::SemiTransparent); +/// assert_eq!(s.to_class(), "text-white text-opacity-25"); +/// +/// // Usando `From<ColorText>`. +/// let s: classes::Text = ColorText::Black.into(); +/// assert_eq!(s.to_class(), "text-black"); +/// +/// // Usando `From<(ColorText, Opacity)>`. +/// let s: classes::Text = (ColorText::Theme(Color::Danger), Opacity::Opaque).into(); +/// assert_eq!(s.to_class(), "text-danger text-opacity-100"); +/// ``` +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub struct Text { + color: ColorText, + opacity: Opacity, +} + +impl Text { + /// Prepara un nuevo estilo para aplicar al texto. + pub fn new() -> Self { + Self::default() + } + + /// Crea un estilo fijando el color del texto (`text-*`). + pub fn with(color: ColorText) -> Self { + Self::default().with_color(color) + } + + // **< Text BUILDER >*************************************************************************** + + /// Establece el color del texto (`text-*`). + pub fn with_color(mut self, color: ColorText) -> Self { + self.color = color; + self + } + + /// Establece la opacidad del texto (`text-opacity-*`). + pub fn with_opacity(mut self, opacity: Opacity) -> Self { + self.opacity = opacity; + self + } + + // **< Text HELPERS >*************************************************************************** + + /// Añade las clases de texto a la cadena de clases. + /// + /// Concatena, en este orden, `text-*` y `text-opacity-*`, omitiendo los fragmentos vacíos. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + self.color.push_class(classes); + self.opacity.push_class(classes, "text"); + } + + /// Devuelve las clases de texto como cadena (`"text-primary"`, `"text-white text-opacity-25"`, + /// etc.). + /// + /// Si no se define ni color ni opacidad, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let mut classes = String::new(); + self.push_class(&mut classes); + classes + } +} + +impl From<(ColorText, Opacity)> for Text { + /// Atajo para crear un [`classes::Text`](crate::theme::classes::Text) a partir del color del + /// texto y su opacidad. + /// + /// # Ejemplo + /// + /// ``` + /// # use pagetop_bootsier::prelude::*; + /// let s: classes::Text = (ColorText::Theme(Color::Danger), Opacity::Opaque).into(); + /// assert_eq!(s.to_class(), "text-danger text-opacity-100"); + /// ``` + fn from((color, opacity): (ColorText, Opacity)) -> Self { + Text::with(color).with_opacity(opacity) + } +} + +impl From<ColorText> for Text { + /// Atajo para crear un [`classes::Text`](crate::theme::classes::Text) a partir del color del + /// texto. + /// + /// # Ejemplo + /// + /// ``` + /// # use pagetop_bootsier::prelude::*; + /// let s: classes::Text = ColorText::Black.into(); + /// assert_eq!(s.to_class(), "text-black"); + /// ``` + fn from(color: ColorText) -> Self { + Text::with(color) + } +} diff --git a/extensions/pagetop-bootsier/src/theme/classes/layout.rs b/extensions/pagetop-bootsier/src/theme/classes/layout.rs new file mode 100644 index 0000000..e9d7e24 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/classes/layout.rs @@ -0,0 +1,205 @@ +use pagetop::prelude::*; + +use crate::theme::aux::{ScaleSize, Side}; +use crate::theme::BreakPoint; + +// **< Margin >************************************************************************************* + +/// Clases para establecer **margin** por lado, tamaño y punto de ruptura. +/// +/// # Ejemplos +/// +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let m = classes::Margin::with(Side::Top, ScaleSize::Three); +/// assert_eq!(m.to_class(), "mt-3"); +/// +/// let m = classes::Margin::with(Side::Start, ScaleSize::Auto).with_breakpoint(BreakPoint::LG); +/// assert_eq!(m.to_class(), "ms-lg-auto"); +/// +/// let m = classes::Margin::with(Side::All, ScaleSize::None); +/// assert_eq!(m.to_class(), ""); +/// ``` +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub struct Margin { + side: Side, + size: ScaleSize, + breakpoint: BreakPoint, +} + +impl Margin { + /// Crea un **margin** indicando lado(s) y tamaño. Por defecto no se aplica a ningún punto de + /// ruptura. + pub fn with(side: Side, size: ScaleSize) -> Self { + Margin { + side, + size, + breakpoint: BreakPoint::None, + } + } + + // **< Margin BUILDER >************************************************************************* + + /// Establece el punto de ruptura a partir del cual se empieza a aplicar el **margin**. + pub fn with_breakpoint(mut self, breakpoint: BreakPoint) -> Self { + self.breakpoint = breakpoint; + self + } + + // **< Margin HELPERS >************************************************************************* + + // Devuelve el prefijo `m*` según el lado. + #[rustfmt::skip] + #[inline] + const fn side_prefix(&self) -> &'static str { + match self.side { + Side::All => "m", + Side::Top => "mt", + Side::Bottom => "mb", + Side::Start => "ms", + Side::End => "me", + Side::LeftAndRight => "mx", + Side::TopAndBottom => "my", + } + } + + // Devuelve el sufijo del tamaño (`auto`, `0`..`5`), o `None` si no define clase. + #[rustfmt::skip] + #[inline] + const fn size_suffix(&self) -> Option<&'static str> { + match self.size { + ScaleSize::None => None, + ScaleSize::Auto => Some("auto"), + ScaleSize::Zero => Some("0"), + ScaleSize::One => Some("1"), + ScaleSize::Two => Some("2"), + ScaleSize::Three => Some("3"), + ScaleSize::Four => Some("4"), + ScaleSize::Five => Some("5"), + } + } + + /* Añade la clase de **margin** a la cadena de clases (reservado). + // + // No añade nada si `size` es `ScaleSize::None`. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let Some(size) = self.size_suffix() else { + return; + }; + self.breakpoint + .push_class(classes, self.side_prefix(), size); + } */ + + /// Devuelve la clase de **margin** como cadena (`"mt-3"`, `"ms-lg-auto"`, etc.). + /// + /// Si `size` es `ScaleSize::None`, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let Some(size) = self.size_suffix() else { + return String::new(); + }; + self.breakpoint.class_with(self.side_prefix(), size) + } +} + +// **< Padding >************************************************************************************ + +/// Clases para establecer **padding** por lado, tamaño y punto de ruptura. +/// +/// # Ejemplos +/// +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let p = classes::Padding::with(Side::LeftAndRight, ScaleSize::Two); +/// assert_eq!(p.to_class(), "px-2"); +/// +/// let p = classes::Padding::with(Side::End, ScaleSize::Four).with_breakpoint(BreakPoint::SM); +/// assert_eq!(p.to_class(), "pe-sm-4"); +/// +/// let p = classes::Padding::with(Side::All, ScaleSize::Auto); +/// assert_eq!(p.to_class(), ""); // `Auto` no aplica a padding. +/// ``` +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub struct Padding { + side: Side, + size: ScaleSize, + breakpoint: BreakPoint, +} + +impl Padding { + /// Crea un **padding** indicando lado(s) y tamaño. Por defecto no se aplica a ningún punto de + /// ruptura. + pub fn with(side: Side, size: ScaleSize) -> Self { + Padding { + side, + size, + breakpoint: BreakPoint::None, + } + } + + // **< Padding BUILDER >************************************************************************ + + /// Establece el punto de ruptura a partir del cual se empieza a aplicar el **padding**. + pub fn with_breakpoint(mut self, breakpoint: BreakPoint) -> Self { + self.breakpoint = breakpoint; + self + } + + // **< Padding HELPERS >************************************************************************ + + // Devuelve el prefijo `p*` según el lado. + #[rustfmt::skip] + #[inline] + const fn prefix(&self) -> &'static str { + match self.side { + Side::All => "p", + Side::Top => "pt", + Side::Bottom => "pb", + Side::Start => "ps", + Side::End => "pe", + Side::LeftAndRight => "px", + Side::TopAndBottom => "py", + } + } + + // Devuelve el sufijo del tamaño (`0`..`5`), o `None` si no define clase. + // + // Nota: `ScaleSize::Auto` **no aplica** a padding ⇒ devuelve `None`. + #[rustfmt::skip] + #[inline] + const fn suffix(&self) -> Option<&'static str> { + match self.size { + ScaleSize::None => None, + ScaleSize::Auto => None, + ScaleSize::Zero => Some("0"), + ScaleSize::One => Some("1"), + ScaleSize::Two => Some("2"), + ScaleSize::Three => Some("3"), + ScaleSize::Four => Some("4"), + ScaleSize::Five => Some("5"), + } + } + + /* Añade la clase de **padding** a la cadena de clases (reservado). + // + // No añade nada si `size` es `ScaleSize::None` o `ScaleSize::Auto`. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let Some(size) = self.suffix() else { + return; + }; + self.breakpoint.push_class(classes, self.prefix(), size); + } */ + + // Devuelve la clase de **padding** como cadena (`"px-2"`, `"pe-sm-4"`, etc.). + // + // Si `size` es `ScaleSize::None` o `ScaleSize::Auto`, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let Some(size) = self.suffix() else { + return String::new(); + }; + self.breakpoint.class_with(self.prefix(), size) + } +} diff --git a/extensions/pagetop-bootsier/src/theme/classes/rounded.rs b/extensions/pagetop-bootsier/src/theme/classes/rounded.rs new file mode 100644 index 0000000..58d50b8 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/classes/rounded.rs @@ -0,0 +1,169 @@ +use pagetop::prelude::*; + +use crate::theme::aux::RoundedRadius; + +/// Clases para definir **esquinas redondeadas**. +/// +/// Permite: +/// +/// - Definir un radio **global para todas las esquinas** (`radius`). +/// - Ajustar el radio asociado a las **esquinas de cada lado lógico** (`top`, `end`, `bottom`, +/// `start`, **en este orden**, respetando LTR/RTL). +/// - Ajustar el radio de las **esquinas concretas** (`top-start`, `top-end`, `bottom-start`, +/// `bottom-end`, **en este orden**, respetando LTR/RTL). +/// +/// # Ejemplos +/// +/// **Radio global:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = classes::Rounded::with(RoundedRadius::Default); +/// assert_eq!(r.to_class(), "rounded"); +/// ``` +/// +/// **Sin redondeo:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = classes::Rounded::new(); +/// assert_eq!(r.to_class(), ""); +/// ``` +/// +/// **Radio en las esquinas de un lado lógico:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = classes::Rounded::new().with_end(RoundedRadius::Scale2); +/// assert_eq!(r.to_class(), "rounded-end-2"); +/// ``` +/// +/// **Radio en una esquina concreta:** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = classes::Rounded::new().with_top_start(RoundedRadius::Scale3); +/// assert_eq!(r.to_class(), "rounded-top-start-3"); +/// ``` +/// +/// **Combinado (ejemplo completo):** +/// ```rust +/// # use pagetop_bootsier::prelude::*; +/// let r = classes::Rounded::new() +/// .with_top(RoundedRadius::Default) // Añade redondeo arriba. +/// .with_bottom_start(RoundedRadius::Scale4) // Añade una esquina redondeada concreta. +/// .with_bottom_end(RoundedRadius::Circle); // Añade redondeo extremo en otra esquina. +/// +/// assert_eq!(r.to_class(), "rounded-top rounded-bottom-start-4 rounded-bottom-end-circle"); +/// ``` +#[rustfmt::skip] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub struct Rounded { + radius : RoundedRadius, + top : RoundedRadius, + end : RoundedRadius, + bottom : RoundedRadius, + start : RoundedRadius, + top_start : RoundedRadius, + top_end : RoundedRadius, + bottom_start: RoundedRadius, + bottom_end : RoundedRadius, +} + +impl Rounded { + /// Prepara las esquinas **sin redondeo global** de partida. + pub fn new() -> Self { + Self::default() + } + + /// Crea las esquinas **con redondeo global** (`radius`). + pub fn with(radius: RoundedRadius) -> Self { + Self::default().with_radius(radius) + } + + // **< Rounded BUILDER >************************************************************************ + + /// Establece el radio global de las esquinas (`rounded*`). + pub fn with_radius(mut self, radius: RoundedRadius) -> Self { + self.radius = radius; + self + } + + /// Establece el radio en las esquinas del lado superior (`rounded-top-*`). + pub fn with_top(mut self, radius: RoundedRadius) -> Self { + self.top = radius; + self + } + + /// Establece el radio en las esquinas del lado lógico final (`rounded-end-*`). Respeta LTR/RTL. + pub fn with_end(mut self, radius: RoundedRadius) -> Self { + self.end = radius; + self + } + + /// Establece el radio en las esquinas del lado inferior (`rounded-bottom-*`). + pub fn with_bottom(mut self, radius: RoundedRadius) -> Self { + self.bottom = radius; + self + } + + /// Establece el radio en las esquinas del lado lógico inicial (`rounded-start-*`). Respeta + /// LTR/RTL. + pub fn with_start(mut self, radius: RoundedRadius) -> Self { + self.start = radius; + self + } + + /// Establece el radio en la esquina superior-inicial (`rounded-top-start-*`). Respeta LTR/RTL. + pub fn with_top_start(mut self, radius: RoundedRadius) -> Self { + self.top_start = radius; + self + } + + /// Establece el radio en la esquina superior-final (`rounded-top-end-*`). Respeta LTR/RTL. + pub fn with_top_end(mut self, radius: RoundedRadius) -> Self { + self.top_end = radius; + self + } + + /// Establece el radio en la esquina inferior-inicial (`rounded-bottom-start-*`). Respeta + /// LTR/RTL. + pub fn with_bottom_start(mut self, radius: RoundedRadius) -> Self { + self.bottom_start = radius; + self + } + + /// Establece el radio en la esquina inferior-final (`rounded-bottom-end-*`). Respeta LTR/RTL. + pub fn with_bottom_end(mut self, radius: RoundedRadius) -> Self { + self.bottom_end = radius; + self + } + + // **< Rounded HELPERS >************************************************************************ + + /// Añade las clases de redondeo a la cadena de clases. + /// + /// Concatena, en este orden, las clases para *global*, `top`, `end`, `bottom`, `start`, + /// `top-start`, `top-end`, `bottom-start` y `bottom-end`; respetando LTR/RTL y omitiendo las + /// definiciones vacías. + #[rustfmt::skip] + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + self.radius .push_class(classes, ""); + self.top .push_class(classes, "rounded-top"); + self.end .push_class(classes, "rounded-end"); + self.bottom .push_class(classes, "rounded-bottom"); + self.start .push_class(classes, "rounded-start"); + self.top_start .push_class(classes, "rounded-top-start"); + self.top_end .push_class(classes, "rounded-top-end"); + self.bottom_start.push_class(classes, "rounded-bottom-start"); + self.bottom_end .push_class(classes, "rounded-bottom-end"); + } + + /// Devuelve las clases de redondeo como cadena (`"rounded"`, + /// `"rounded-top rounded-bottom-start-4 rounded-bottom-end-circle"`, etc.). + /// + /// Si no se define ningún radio, devuelve `""`. + #[inline] + pub fn to_class(self) -> String { + let mut classes = String::new(); + self.push_class(&mut classes); + classes + } +} diff --git a/extensions/pagetop-bootsier/src/theme/container.rs b/extensions/pagetop-bootsier/src/theme/container.rs new file mode 100644 index 0000000..a860110 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/container.rs @@ -0,0 +1,24 @@ +//! Definiciones para crear contenedores de componentes ([`Container`]). +//! +//! Cada contenedor envuelve contenido usando la etiqueta semántica indicada por +//! [`container::Kind`](crate::theme::container::Kind). +//! +//! Con [`container::Width`](crate::theme::container::Width) se puede definir el ancho y el +//! comportamiento *responsive* del contenedor. También permite aplicar utilidades de estilo para el +//! fondo, texto, borde o esquinas redondeadas. +//! +//! # Ejemplo +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let main = Container::main() +//! .with_id("main-page") +//! .with_width(container::Width::From(BreakPoint::LG)); +//! ``` + +mod props; +pub use props::{Kind, Width}; + +mod component; +pub use component::Container; diff --git a/extensions/pagetop-bootsier/src/theme/container/component.rs b/extensions/pagetop-bootsier/src/theme/container/component.rs new file mode 100644 index 0000000..068d24a --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/container/component.rs @@ -0,0 +1,184 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +/// Componente para crear un **contenedor de componentes**. +/// +/// Envuelve un contenido con la etiqueta HTML indicada por [`container::Kind`]. Sólo se renderiza +/// si existen componentes hijos (*children*). +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Container { + id : AttrId, + classes : AttrClasses, + container_kind : container::Kind, + container_width: container::Width, + children : Children, +} + +impl Component for Container { + fn new() -> Self { + Container::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes(ClassesOp::Prepend, self.width().to_class()); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let output = self.children().render(cx); + if output.is_empty() { + return PrepareMarkup::None; + } + let style = match self.width() { + container::Width::FluidMax(w) if w.is_measurable() => { + Some(join!("max-width: ", w.to_string(), ";")) + } + _ => None, + }; + match self.container_kind() { + container::Kind::Default => PrepareMarkup::With(html! { + div id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + container::Kind::Main => PrepareMarkup::With(html! { + main id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + container::Kind::Header => PrepareMarkup::With(html! { + header id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + container::Kind::Footer => PrepareMarkup::With(html! { + footer id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + container::Kind::Section => PrepareMarkup::With(html! { + section id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + container::Kind::Article => PrepareMarkup::With(html! { + article id=[self.id()] class=[self.classes().get()] style=[style] { + (output) + } + }), + } + } +} + +impl Container { + /// Crea un contenedor de tipo `Main` (`<main>`). + pub fn main() -> Self { + Container { + container_kind: container::Kind::Main, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Header` (`<header>`). + pub fn header() -> Self { + Container { + container_kind: container::Kind::Header, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Footer` (`<footer>`). + pub fn footer() -> Self { + Container { + container_kind: container::Kind::Footer, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Section` (`<section>`). + pub fn section() -> Self { + Container { + container_kind: container::Kind::Section, + ..Default::default() + } + } + + /// Crea un contenedor de tipo `Article` (`<article>`). + pub fn article() -> Self { + Container { + container_kind: container::Kind::Article, + ..Default::default() + } + } + + // **< Container BUILDER >********************************************************************** + + /// Establece el identificador único (`id`) del contenedor. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + /// Modifica la lista de clases CSS aplicadas al contenedor. + /// + /// También acepta clases predefinidas para: + /// + /// - Modificar el color de fondo ([`classes::Background`]). + /// - Definir la apariencia del texto ([`classes::Text`]). + /// - Establecer bordes ([`classes::Border`]). + /// - Redondear las esquinas ([`classes::Rounded`]). + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Establece el comportamiento del ancho para el contenedor. + #[builder_fn] + pub fn with_width(mut self, width: container::Width) -> Self { + self.container_width = width; + self + } + + /// Añade un nuevo componente hijo al contenedor. + #[inline] + pub fn add_child(mut self, component: impl Component) -> Self { + self.children.add(Child::with(component)); + self + } + + /// Modifica la lista de componentes (`children`) aplicando una operación [`ChildOp`]. + #[builder_fn] + pub fn with_child(mut self, op: ChildOp) -> Self { + self.children.alter_child(op); + self + } + + // **< Container GETTERS >********************************************************************** + + /// Devuelve las clases CSS asociadas al contenedor. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el tipo semántico del contenedor. + pub fn container_kind(&self) -> &container::Kind { + &self.container_kind + } + + /// Devuelve el comportamiento para el ancho del contenedor. + pub fn width(&self) -> &container::Width { + &self.container_width + } + + /// Devuelve la lista de componentes (`children`) del contenedor. + pub fn children(&self) -> &Children { + &self.children + } +} diff --git a/extensions/pagetop-bootsier/src/theme/container/props.rs b/extensions/pagetop-bootsier/src/theme/container/props.rs new file mode 100644 index 0000000..2010ba8 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/container/props.rs @@ -0,0 +1,72 @@ +use pagetop::prelude::*; + +use crate::theme::aux::BreakPoint; + +// **< Kind >*************************************************************************************** + +/// Tipo de contenedor ([`Container`](crate::theme::Container)). +/// +/// Permite aplicar la etiqueta HTML apropiada (`<main>`, `<header>`, etc.) manteniendo una API +/// común a todos los contenedores. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Kind { + /// Contenedor genérico (`<div>`). + #[default] + Default, + /// Contenido principal de la página (`<main>`). + Main, + /// Encabezado de la página o de sección (`<header>`). + Header, + /// Pie de la página o de sección (`<footer>`). + Footer, + /// Sección de contenido (`<section>`). + Section, + /// Artículo de contenido (`<article>`). + Article, +} + +// **< Width >************************************************************************************** + +/// Define cómo se comporta el ancho de un contenedor ([`Container`](crate::theme::Container)). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Width { + /// Comportamiento por defecto, aplica los anchos máximos predefinidos para cada punto de + /// ruptura. Por debajo del menor punto de ruptura ocupa el 100% del ancho disponible. + #[default] + Default, + /// Aplica los anchos máximos predefinidos a partir del punto de ruptura indicado. Por debajo de + /// ese punto de ruptura ocupa el 100% del ancho disponible. + From(BreakPoint), + /// Ocupa el 100% del ancho disponible siempre. + Fluid, + /// Ocupa el 100% del ancho disponible hasta un ancho máximo explícito. + FluidMax(UnitValue), +} + +impl Width { + const CONTAINER: &str = "container"; + + /* Añade el comportamiento del contenedor a la cadena de clases según ancho (reservado). + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + match self { + Self::Default => BreakPoint::None.push_class(classes, Self::CONTAINER, ""), + Self::From(bp) => bp.push_class(classes, Self::CONTAINER, ""), + Self::Fluid | Self::FluidMax(_) => { + BreakPoint::None.push_class(classes, Self::CONTAINER, "fluid") + } + } + } */ + + /// Devuelve la clase asociada al comportamiento del contenedor según el ajuste de su ancho. + #[inline] + pub fn to_class(self) -> String { + match self { + Self::Default => BreakPoint::None.class_with(Self::CONTAINER, ""), + Self::From(bp) => bp.class_with(Self::CONTAINER, ""), + Self::Fluid | Self::FluidMax(_) => { + BreakPoint::None.class_with(Self::CONTAINER, "fluid") + } + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/dropdown.rs b/extensions/pagetop-bootsier/src/theme/dropdown.rs new file mode 100644 index 0000000..ed4cbec --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/dropdown.rs @@ -0,0 +1,34 @@ +//! Definiciones para crear menús desplegables [`Dropdown`]. +//! +//! Cada [`dropdown::Item`](crate::theme::dropdown::Item) representa un elemento individual del +//! desplegable [`Dropdown`], con distintos comportamientos según su finalidad, como enlaces de +//! navegación, botones de acción, encabezados o divisores visuales. +//! +//! Los ítems pueden estar activos, deshabilitados o abrirse en nueva ventana según su contexto y +//! configuración, y permiten incluir etiquetas localizables usando [`L10n`](pagetop::locale::L10n). +//! +//! # Ejemplo +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let dd = Dropdown::new() +//! .with_title(L10n::n("Menu")) +//! .with_button_color(ButtonColor::Background(Color::Secondary)) +//! .with_auto_close(dropdown::AutoClose::ClickableInside) +//! .with_direction(dropdown::Direction::Dropend) +//! .add_item(dropdown::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(dropdown::Item::link_blank(L10n::n("External"), |_| "https://www.google.es")) +//! .add_item(dropdown::Item::divider()) +//! .add_item(dropdown::Item::header(L10n::n("User session"))) +//! .add_item(dropdown::Item::button(L10n::n("Sign out"))); +//! ``` + +mod props; +pub use props::{AutoClose, Direction, MenuAlign, MenuPosition}; + +mod component; +pub use component::Dropdown; + +mod item; +pub use item::{Item, ItemKind}; diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/component.rs b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs new file mode 100644 index 0000000..5d27daf --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/dropdown/component.rs @@ -0,0 +1,302 @@ +use pagetop::prelude::*; + +use crate::prelude::*; +use crate::LOCALES_BOOTSIER; + +/// Componente para crear un **menú desplegable**. +/// +/// Renderiza un botón (único o desdoblado, ver [`with_button_split()`](Self::with_button_split)) +/// para mostrar un menú desplegable de elementos [`dropdown::Item`], que se muestra/oculta según la +/// interacción del usuario. Admite variaciones de tamaño/color del botón, también dirección de +/// apertura, alineación o política de cierre. +/// +/// Si no tiene título (ver [`with_title()`](Self::with_title)) se muestra únicamente la lista de +/// elementos sin ningún botón para interactuar. +/// +/// Si este componente se usa en un menú [`Nav`] (ver [`nav::Item::dropdown()`]) sólo se tendrán en +/// cuenta **el título** (si no existe le asigna uno por defecto) y **la lista de elementos**; el +/// resto de propiedades no afectarán a su representación en [`Nav`]. +/// +/// Ver ejemplo en el módulo [`dropdown`]. +/// Si no contiene elementos, el componente **no se renderiza**. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Dropdown { + id : AttrId, + classes : AttrClasses, + title : L10n, + button_size : ButtonSize, + button_color : ButtonColor, + button_split : bool, + button_grouped: bool, + auto_close : dropdown::AutoClose, + direction : dropdown::Direction, + menu_align : dropdown::MenuAlign, + menu_position : dropdown::MenuPosition, + items : Children, +} + +impl Component for Dropdown { + fn new() -> Self { + Dropdown::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes( + ClassesOp::Prepend, + self.direction().class_with(self.button_grouped()), + ); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + // Si no hay elementos en el menú, no se prepara. + let items = self.items().render(cx); + if items.is_empty() { + return PrepareMarkup::None; + } + + // Título opcional para el menú desplegable. + let title = self.title().using(cx); + + PrepareMarkup::With(html! { + div id=[self.id()] class=[self.classes().get()] { + @if !title.is_empty() { + @let mut btn_classes = AttrClasses::new({ + let mut classes = "btn".to_string(); + self.button_size().push_class(&mut classes); + self.button_color().push_class(&mut classes); + classes + }); + @let pos = self.menu_position(); + @let offset = pos.data_offset(); + @let reference = pos.data_reference(); + @let auto_close = self.auto_close.as_str(); + @let menu_classes = AttrClasses::new({ + let mut classes = "dropdown-menu".to_string(); + self.menu_align().push_class(&mut classes); + classes + }); + + // Renderizado en modo split (dos botones) o simple (un botón). + @if self.button_split() { + // Botón principal (acción/etiqueta). + @let btn = html! { + button + type="button" + class=[btn_classes.get()] + { + (title) + } + }; + // Botón *toggle* que abre/cierra el menú asociado. + @let btn_toggle = html! { + button + type="button" + class=[btn_classes.alter_value( + ClassesOp::Add, "dropdown-toggle dropdown-toggle-split" + ).get()] + data-bs-toggle="dropdown" + data-bs-offset=[offset] + data-bs-reference=[reference] + data-bs-auto-close=[auto_close] + aria-expanded="false" + { + span class="visually-hidden" { + (L10n::t("dropdown_toggle", &LOCALES_BOOTSIER).using(cx)) + } + } + }; + // Orden según dirección (en `dropstart` el *toggle* se sitúa antes). + @match self.direction() { + dropdown::Direction::Dropstart => { + (btn_toggle) + ul class=[menu_classes.get()] { (items) } + (btn) + } + _ => { + (btn) + (btn_toggle) + ul class=[menu_classes.get()] { (items) } + } + } + } @else { + // Botón único con funcionalidad de *toggle*. + button + type="button" + class=[btn_classes.alter_value( + ClassesOp::Add, "dropdown-toggle" + ).get()] + data-bs-toggle="dropdown" + data-bs-offset=[offset] + data-bs-reference=[reference] + data-bs-auto-close=[auto_close] + aria-expanded="false" + { + (title) + } + ul class=[menu_classes.get()] { (items) } + } + } @else { + // Sin botón: sólo el listado como menú contextual. + ul class="dropdown-menu" { (items) } + } + } + }) + } +} + +impl Dropdown { + // **< Dropdown BUILDER >*********************************************************************** + + /// Establece el identificador único (`id`) del menú desplegable. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + /// Modifica la lista de clases CSS aplicadas al menú desplegable. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Establece el título del menú desplegable. + #[builder_fn] + pub fn with_title(mut self, title: L10n) -> Self { + self.title = title; + self + } + + /// Ajusta el tamaño del botón. + #[builder_fn] + pub fn with_button_size(mut self, size: ButtonSize) -> Self { + self.button_size = size; + self + } + + /// Define el color/estilo del botón. + #[builder_fn] + pub fn with_button_color(mut self, color: ButtonColor) -> Self { + self.button_color = color; + self + } + + /// Activa/desactiva el modo *split* (botón de acción + *toggle*). + #[builder_fn] + pub fn with_button_split(mut self, split: bool) -> Self { + self.button_split = split; + self + } + + /// Indica si el botón del menú está integrado en un grupo de botones. + #[builder_fn] + pub fn with_button_grouped(mut self, grouped: bool) -> Self { + self.button_grouped = grouped; + self + } + + /// Establece la política de cierre automático del menú desplegable. + #[builder_fn] + pub fn with_auto_close(mut self, auto_close: dropdown::AutoClose) -> Self { + self.auto_close = auto_close; + self + } + + /// Establece la dirección de despliegue del menú. + #[builder_fn] + pub fn with_direction(mut self, direction: dropdown::Direction) -> Self { + self.direction = direction; + self + } + + /// Configura la alineación horizontal (con posible comportamiento *responsive* adicional). + #[builder_fn] + pub fn with_menu_align(mut self, align: dropdown::MenuAlign) -> Self { + self.menu_align = align; + self + } + + /// Configura la posición del menú. + #[builder_fn] + pub fn with_menu_position(mut self, position: dropdown::MenuPosition) -> Self { + self.menu_position = position; + self + } + + /// Añade un nuevo elemento hijo al menú. + #[inline] + pub fn add_item(mut self, item: dropdown::Item) -> Self { + self.items.add(Child::with(item)); + self + } + + /// Modifica la lista de elementos (`children`) aplicando una operación [`TypedOp`]. + #[builder_fn] + pub fn with_items(mut self, op: TypedOp<dropdown::Item>) -> Self { + self.items.alter_typed(op); + self + } + + // **< Dropdown GETTERS >*********************************************************************** + + /// Devuelve las clases CSS asociadas al menú desplegable. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el título del menú desplegable. + pub fn title(&self) -> &L10n { + &self.title + } + + /// Devuelve el tamaño configurado del botón. + pub fn button_size(&self) -> &ButtonSize { + &self.button_size + } + + /// Devuelve el color/estilo configurado del botón. + pub fn button_color(&self) -> &ButtonColor { + &self.button_color + } + + /// Devuelve si se debe desdoblar (*split*) el botón (botón de acción + *toggle*). + pub fn button_split(&self) -> bool { + self.button_split + } + + /// Devuelve si el botón del menú está integrado en un grupo de botones. + pub fn button_grouped(&self) -> bool { + self.button_grouped + } + + /// Devuelve la política de cierre automático del menú desplegado. + pub fn auto_close(&self) -> &dropdown::AutoClose { + &self.auto_close + } + + /// Devuelve la dirección de despliegue configurada. + pub fn direction(&self) -> &dropdown::Direction { + &self.direction + } + + /// Devuelve la configuración de alineación horizontal del menú desplegable. + pub fn menu_align(&self) -> &dropdown::MenuAlign { + &self.menu_align + } + + /// Devuelve la posición configurada para el menú desplegable. + pub fn menu_position(&self) -> &dropdown::MenuPosition { + &self.menu_position + } + + /// Devuelve la lista de elementos (`children`) del menú. + pub fn items(&self) -> &Children { + &self.items + } +} diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/item.rs b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs new file mode 100644 index 0000000..2f62f28 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/dropdown/item.rs @@ -0,0 +1,281 @@ +use pagetop::prelude::*; + +// **< ItemKind >*********************************************************************************** + +/// Tipos de [`dropdown::Item`](crate::theme::dropdown::Item) disponibles en un menú desplegable +/// [`Dropdown`](crate::theme::Dropdown). +/// +/// Define internamente la naturaleza del elemento y su comportamiento al mostrarse o interactuar +/// con él. +#[derive(AutoDefault)] +pub enum ItemKind { + /// Elemento vacío, no produce salida. + #[default] + Void, + /// Etiqueta sin comportamiento interactivo. + Label(L10n), + /// Elemento de navegación. Opcionalmente puede abrirse en una nueva ventana y estar + /// inicialmente deshabilitado. + Link { + label: L10n, + path: FnPathByContext, + blank: bool, + disabled: bool, + }, + /// Acción ejecutable en la propia página, sin navegación asociada. Inicialmente puede estar + /// deshabilitado. + Button { label: L10n, disabled: bool }, + /// Título o encabezado que separa grupos de opciones. + Header(L10n), + /// Separador visual entre bloques de elementos. + Divider, +} + +// **< Item >*************************************************************************************** + +/// Representa un **elemento individual** de un menú desplegable +/// [`Dropdown`](crate::theme::Dropdown). +/// +/// Cada instancia de [`dropdown::Item`](crate::theme::dropdown::Item) se traduce en un componente +/// visible que puede comportarse como texto, enlace, botón, encabezado o separador, según su +/// [`ItemKind`]. +/// +/// Permite definir identificador, clases de estilo adicionales o tipo de interacción asociada, +/// manteniendo una interfaz común para renderizar todos los elementos del menú. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Item { + id : AttrId, + classes : AttrClasses, + item_kind: ItemKind, +} + +impl Component for Item { + fn new() -> Self { + Item::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + match self.item_kind() { + ItemKind::Void => PrepareMarkup::None, + + ItemKind::Label(label) => PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + span class="dropdown-item-text" { + (label.using(cx)) + } + } + }), + + ItemKind::Link { + label, + path, + blank, + disabled, + } => { + let path = path(cx); + let current_path = cx.request().map(|request| request.path()); + let is_current = !*disabled && (current_path == Some(path)); + + let mut classes = "dropdown-item".to_string(); + if is_current { + classes.push_str(" active"); + } + if *disabled { + classes.push_str(" disabled"); + } + + let href = (!disabled).then_some(path); + let target = (!disabled && *blank).then_some("_blank"); + let rel = (!disabled && *blank).then_some("noopener noreferrer"); + + let aria_current = (href.is_some() && is_current).then_some("page"); + let aria_disabled = disabled.then_some("true"); + let tabindex = disabled.then_some("-1"); + + PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + a + class=(classes) + href=[href] + target=[target] + rel=[rel] + aria-current=[aria_current] + aria-disabled=[aria_disabled] + tabindex=[tabindex] + { + (label.using(cx)) + } + } + }) + } + + ItemKind::Button { label, disabled } => { + let mut classes = "dropdown-item".to_string(); + if *disabled { + classes.push_str(" disabled"); + } + + let aria_disabled = disabled.then_some("true"); + let disabled_attr = disabled.then_some("disabled"); + + PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + button + class=(classes) + type="button" + aria-disabled=[aria_disabled] + disabled=[disabled_attr] + { + (label.using(cx)) + } + } + }) + } + + ItemKind::Header(label) => PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + h6 class="dropdown-header" { + (label.using(cx)) + } + } + }), + + ItemKind::Divider => PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { hr class="dropdown-divider" {} } + }), + } + } +} + +impl Item { + /// Crea un elemento de tipo texto, mostrado sin interacción. + pub fn label(label: L10n) -> Self { + Item { + item_kind: ItemKind::Label(label), + ..Default::default() + } + } + + /// Crea un enlace para la navegación. + pub fn link(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: false, + disabled: false, + }, + ..Default::default() + } + } + + /// Crea un enlace deshabilitado que no permite la interacción. + pub fn link_disabled(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: false, + disabled: true, + }, + ..Default::default() + } + } + + /// Crea un enlace que se abre en una nueva ventana o pestaña. + pub fn link_blank(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: true, + disabled: false, + }, + ..Default::default() + } + } + + /// Crea un enlace inicialmente deshabilitado que se abriría en una nueva ventana. + pub fn link_blank_disabled(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: true, + disabled: true, + }, + ..Default::default() + } + } + + /// Crea un botón de acción local, sin navegación asociada. + pub fn button(label: L10n) -> Self { + Item { + item_kind: ItemKind::Button { + label, + disabled: false, + }, + ..Default::default() + } + } + + /// Crea un botón deshabilitado. + pub fn button_disabled(label: L10n) -> Self { + Item { + item_kind: ItemKind::Button { + label, + disabled: true, + }, + ..Default::default() + } + } + + /// Crea un encabezado para un grupo de elementos dentro del menú. + pub fn header(label: L10n) -> Self { + Item { + item_kind: ItemKind::Header(label), + ..Default::default() + } + } + + /// Crea un separador visual entre bloques de elementos. + pub fn divider() -> Self { + Item { + item_kind: ItemKind::Divider, + ..Default::default() + } + } + + // **< Item BUILDER >*************************************************************************** + + /// Establece el identificador único (`id`) del elemento. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + /// Modifica la lista de clases CSS aplicadas al elemento. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + // **< Item GETTERS >*************************************************************************** + + /// Devuelve las clases CSS asociadas al elemento. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el tipo de elemento representado. + pub fn item_kind(&self) -> &ItemKind { + &self.item_kind + } +} diff --git a/extensions/pagetop-bootsier/src/theme/dropdown/props.rs b/extensions/pagetop-bootsier/src/theme/dropdown/props.rs new file mode 100644 index 0000000..7571332 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/dropdown/props.rs @@ -0,0 +1,226 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +// **< AutoClose >********************************************************************************** + +/// Estrategia para el cierre automático de un menú [`Dropdown`]. +/// +/// Define cuándo se cierra el menú desplegado según la interacción del usuario. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum AutoClose { + /// Comportamiento por defecto, se cierra con clics dentro y fuera del menú, o pulsando `Esc`. + #[default] + Default, + /// Sólo se cierra con clics dentro del menú. + ClickableInside, + /// Sólo se cierra con clics fuera del menú. + ClickableOutside, + /// Cierre manual, no se cierra con clics; sólo al pulsar nuevamente el botón del menú + /// (*toggle*), o pulsando `Esc`. + ManualClose, +} + +impl AutoClose { + // Devuelve el valor para `data-bs-auto-close`, o `None` si es el comportamiento por defecto. + #[rustfmt::skip] + #[inline] + pub(crate) const fn as_str(self) -> Option<&'static str> { + match self { + Self::Default => None, + Self::ClickableInside => Some("inside"), + Self::ClickableOutside => Some("outside"), + Self::ManualClose => Some("false"), + } + } +} + +// **< Direction >********************************************************************************** + +/// Dirección de despliegue de un menú [`Dropdown`]. +/// +/// Controla desde qué posición se muestra el menú respecto al botón. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Direction { + /// Comportamiento por defecto (despliega el menú hacia abajo desde la posición inicial, + /// respetando LTR/RTL). + #[default] + Default, + /// Centra horizontalmente el menú respecto al botón. + Centered, + /// Despliega el menú hacia arriba. + Dropup, + /// Despliega el menú hacia arriba y centrado. + DropupCentered, + /// Despliega el menú desde el lateral final, respetando LTR/RTL. + Dropend, + /// Despliega el menú desde el lateral inicial, respetando LTR/RTL. + Dropstart, +} + +impl Direction { + // Mapea la dirección teniendo en cuenta si se agrupa con otros menús [`Dropdown`]. + #[rustfmt::skip ] + #[inline] + const fn as_str(self, grouped: bool) -> &'static str { + match self { + Self::Default if grouped => "", + Self::Default => "dropdown", + Self::Centered => "dropdown-center", + Self::Dropup => "dropup", + Self::DropupCentered => "dropup-center", + Self::Dropend => "dropend", + Self::Dropstart => "dropstart", + } + } + + // Añade la dirección de despliegue a la cadena de clases teniendo en cuenta si se agrupa con + // otros menús [`Dropdown`]. + #[inline] + pub(crate) fn push_class(self, classes: &mut String, grouped: bool) { + if grouped { + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str("btn-group"); + } + let class = self.as_str(grouped); + if !class.is_empty() { + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + } + + // Devuelve la clase asociada a la dirección teniendo en cuenta si se agrupa con otros menús + // [`Dropdown`], o `""` si no corresponde ninguna. + #[inline] + pub(crate) fn class_with(self, grouped: bool) -> String { + let mut classes = String::new(); + self.push_class(&mut classes, grouped); + classes + } +} + +// **< MenuAlign >********************************************************************************** + +/// Alineación horizontal del menú desplegable [`Dropdown`]. +/// +/// Permite alinear el menú al inicio o al final del botón (respetando LTR/RTL) y añadirle una +/// alineación diferente a partir de un punto de ruptura ([`BreakPoint`]). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum MenuAlign { + /// Alineación al inicio (comportamiento por defecto). + #[default] + Start, + /// Alineación al inicio a partir del punto de ruptura indicado. + StartAt(BreakPoint), + /// Alineación al inicio por defecto, y al final a partir de un punto de ruptura válido. + StartAndEnd(BreakPoint), + /// Alineación al final. + End, + /// Alineación al final a partir del punto de ruptura indicado. + EndAt(BreakPoint), + /// Alineación al final por defecto, y al inicio a partir de un punto de ruptura válido. + EndAndStart(BreakPoint), +} + +impl MenuAlign { + #[inline] + fn push_one(classes: &mut String, class: &str) { + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + + // Añade las clases de alineación a `classes` (sin incluir la base `dropdown-menu`). + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + match self { + // Alineación por defecto (start), no añade clases extra. + Self::Start => {} + + // `dropdown-menu-{bp}-start` + Self::StartAt(bp) => { + let class = bp.class_with("dropdown-menu", "start"); + Self::push_one(classes, &class); + } + + // `dropdown-menu-start` + `dropdown-menu-{bp}-end` + Self::StartAndEnd(bp) => { + Self::push_one(classes, "dropdown-menu-start"); + let bp_class = bp.class_with("dropdown-menu", "end"); + Self::push_one(classes, &bp_class); + } + + // `dropdown-menu-end` + Self::End => { + Self::push_one(classes, "dropdown-menu-end"); + } + + // `dropdown-menu-{bp}-end` + Self::EndAt(bp) => { + let class = bp.class_with("dropdown-menu", "end"); + Self::push_one(classes, &class); + } + + // `dropdown-menu-end` + `dropdown-menu-{bp}-start` + Self::EndAndStart(bp) => { + Self::push_one(classes, "dropdown-menu-end"); + let bp_class = bp.class_with("dropdown-menu", "start"); + Self::push_one(classes, &bp_class); + } + } + } + + /* Devuelve las clases de alineación sin incluir `dropdown-menu` (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + let mut classes = String::new(); + self.push_class(&mut classes); + classes + } */ +} + +// **< MenuPosition >******************************************************************************* + +/// Posición relativa del menú desplegable [`Dropdown`]. +/// +/// Permite indicar un desplazamiento (*offset*) manual o referenciar al elemento padre para el +/// cálculo de la posición. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum MenuPosition { + /// Posicionamiento automático por defecto. + #[default] + Default, + /// Desplazamiento manual en píxeles `(x, y)` aplicado al menú. Se admiten valores negativos. + Offset(i8, i8), + /// Posiciona el menú tomando como referencia el botón padre. Especialmente útil cuando + /// [`button_split()`](crate::theme::Dropdown::button_split) es `true`. + Parent, +} + +impl MenuPosition { + // Devuelve el valor para `data-bs-offset` o `None` si no aplica. + #[inline] + pub(crate) fn data_offset(self) -> Option<String> { + match self { + Self::Offset(x, y) => Some(format!("{x},{y}")), + _ => None, + } + } + + // Devuelve el valor para `data-bs-reference` o `None` si no aplica. + #[inline] + pub(crate) fn data_reference(self) -> Option<&'static str> { + match self { + Self::Parent => Some("parent"), + _ => None, + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/image.rs b/extensions/pagetop-bootsier/src/theme/image.rs new file mode 100644 index 0000000..837d25a --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/image.rs @@ -0,0 +1,7 @@ +//! Definiciones para renderizar imágenes ([`Image`]). + +mod props; +pub use props::{Size, Source}; + +mod component; +pub use component::Image; diff --git a/extensions/pagetop-bootsier/src/theme/image/component.rs b/extensions/pagetop-bootsier/src/theme/image/component.rs new file mode 100644 index 0000000..bc3f2c9 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/image/component.rs @@ -0,0 +1,141 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +/// Componente para renderizar una **imagen**. +/// +/// - Ajusta su disposición según el origen definido en [`image::Source`]. +/// - Permite configurar **dimensiones** ([`with_size()`](Self::with_size)), **borde** +/// ([`classes::Border`](crate::theme::classes::Border)) y **redondeo de esquinas** +/// ([`classes::Rounded`](crate::theme::classes::Rounded)). +/// - Resuelve el texto alternativo `alt` con **localización** mediante [`L10n`]. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Image { + id : AttrId, + classes: AttrClasses, + size : image::Size, + source : image::Source, + alt : AttrL10n, +} + +impl Component for Image { + fn new() -> Self { + Image::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes(ClassesOp::Prepend, self.source().to_class()); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let dimensions = self.size().to_style(); + let alt_text = self.alternative().lookup(cx).unwrap_or_default(); + let is_decorative = alt_text.is_empty(); + let source = match self.source() { + image::Source::Logo(logo) => { + return PrepareMarkup::With(html! { + span + id=[self.id()] + class=[self.classes().get()] + style=[dimensions] + role=[(!is_decorative).then_some("img")] + aria-label=[(!is_decorative).then_some(alt_text)] + aria-hidden=[is_decorative.then_some("true")] + { + (logo.render(cx)) + } + }) + } + image::Source::Responsive(source) => Some(source), + image::Source::Thumbnail(source) => Some(source), + image::Source::Plain(source) => Some(source), + }; + PrepareMarkup::With(html! { + img + src=[source] + alt=(alt_text) + id=[self.id()] + class=[self.classes().get()] + style=[dimensions] {} + }) + } +} + +impl Image { + /// Crea rápidamente una imagen especificando su origen. + pub fn with(source: image::Source) -> Self { + Image::default().with_source(source) + } + + // **< Image BUILDER >************************************************************************** + + /// Establece el identificador único (`id`) de la imagen. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + /// Modifica la lista de clases CSS aplicadas a la imagen. + /// + /// También acepta clases predefinidas para: + /// + /// - Establecer bordes ([`classes::Border`]). + /// - Redondear las esquinas ([`classes::Rounded`]). + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Define las dimensiones de la imagen (auto, ancho/alto, ambos). + #[builder_fn] + pub fn with_size(mut self, size: image::Size) -> Self { + self.size = size; + self + } + + /// Establece el origen de la imagen, influyendo en su disposición en el contenido. + #[builder_fn] + pub fn with_source(mut self, source: image::Source) -> Self { + self.source = source; + self + } + + /// Define el texto alternativo localizado ([`L10n`]) para la imagen. + /// + /// Se recomienda siempre aportar un texto alternativo salvo que la imagen sea puramente + /// decorativa. + #[builder_fn] + pub fn with_alternative(mut self, alt: L10n) -> Self { + self.alt.alter_value(alt); + self + } + + // **< Image GETTERS >************************************************************************** + + /// Devuelve las clases CSS asociadas a la imagen. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve las dimensiones de la imagen. + pub fn size(&self) -> &image::Size { + &self.size + } + + /// Devuelve el origen de la imagen. + pub fn source(&self) -> &image::Source { + &self.source + } + + /// Devuelve el texto alternativo localizado. + pub fn alternative(&self) -> &AttrL10n { + &self.alt + } +} diff --git a/extensions/pagetop-bootsier/src/theme/image/props.rs b/extensions/pagetop-bootsier/src/theme/image/props.rs new file mode 100644 index 0000000..e9b1286 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/image/props.rs @@ -0,0 +1,108 @@ +use pagetop::prelude::*; + +// **< Size >*************************************************************************************** + +/// Define las **dimensiones** de una imagen ([`Image`](crate::theme::Image)). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Size { + /// Ajuste automático por defecto. + /// + /// La imagen usa su tamaño natural o se ajusta al contenedor donde se publica. + #[default] + Auto, + /// Establece explícitamente el **ancho y alto** de la imagen. + /// + /// Útil cuando se desea fijar ambas dimensiones de forma exacta. Ten en cuenta que la imagen + /// puede distorsionarse si no se mantiene la proporción original. + Dimensions(UnitValue, UnitValue), + /// Establece sólo el **ancho** de la imagen. + /// + /// La altura se ajusta proporcionalmente de manera automática. + Width(UnitValue), + /// Establece sólo la **altura** de la imagen. + /// + /// El ancho se ajusta proporcionalmente de manera automática. + Height(UnitValue), + /// Establece **el mismo valor** para el ancho y el alto de la imagen. + /// + /// Práctico para forzar rápidamente un área cuadrada. Ten en cuenta que la imagen puede + /// distorsionarse si la original no es cuadrada. + Both(UnitValue), +} + +impl Size { + // Devuelve el valor del atributo `style` en función del tamaño, o `None` si no aplica. + #[inline] + pub(crate) fn to_style(self) -> Option<String> { + match self { + Self::Auto => None, + Self::Dimensions(w, h) => Some(format!("width: {w}; height: {h};")), + Self::Width(w) => Some(format!("width: {w};")), + Self::Height(h) => Some(format!("height: {h};")), + Self::Both(v) => Some(format!("width: {v}; height: {v};")), + } + } +} + +// **< Source >************************************************************************************* + +/// Especifica la **fuente** para publicar una imagen ([`Image`](crate::theme::Image)). +#[derive(AutoDefault, Clone, Debug, PartialEq)] +pub enum Source { + /// Imagen con el logotipo de PageTop. + #[default] + Logo(PageTopSvg), + /// Imagen que se adapta automáticamente a su contenedor. + /// + /// El `String` asociado es la URL (o ruta) de la imagen. + Responsive(String), + /// Imagen que aplica el estilo **miniatura** de Bootstrap. + /// + /// El `String` asociado es la URL (o ruta) de la imagen. + Thumbnail(String), + /// Imagen sin clases específicas de Bootstrap, útil para controlar con CSS propio. + /// + /// El `String` asociado es la URL (o ruta) de la imagen. + Plain(String), +} + +impl Source { + const IMG_FLUID: &str = "img-fluid"; + const IMG_THUMBNAIL: &str = "img-thumbnail"; + + // Devuelve la clase base asociada a la imagen según la fuente. + #[inline] + fn as_str(&self) -> &'static str { + match self { + Source::Logo(_) | Source::Responsive(_) => Self::IMG_FLUID, + Source::Thumbnail(_) => Self::IMG_THUMBNAIL, + Source::Plain(_) => "", + } + } + + /* Añade la clase base asociada a la imagen según la fuente a la cadena de clases (reservado). + #[inline] + pub(crate) fn push_class(&self, classes: &mut String) { + let s = self.as_str(); + if s.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(s); + } */ + + // Devuelve la clase asociada a la imagen según la fuente. + #[inline] + pub(crate) fn to_class(&self) -> String { + let s = self.as_str(); + if s.is_empty() { + String::new() + } else { + let mut class = String::with_capacity(s.len()); + class.push_str(s); + class + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/nav.rs b/extensions/pagetop-bootsier/src/theme/nav.rs new file mode 100644 index 0000000..c74ab3b --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/nav.rs @@ -0,0 +1,37 @@ +//! Definiciones para crear menús [`Nav`] o alguna de sus variantes de presentación. +//! +//! Cada [`nav::Item`](crate::theme::nav::Item) representa un elemento individual del menú [`Nav`], +//! con distintos comportamientos según su finalidad, como enlaces de navegación o menús +//! desplegables [`Dropdown`](crate::theme::Dropdown). +//! +//! Los ítems pueden estar activos, deshabilitados o abrirse en nueva ventana según su contexto y +//! configuración, y permiten incluir etiquetas localizables usando [`L10n`](pagetop::locale::L10n). +//! +//! # Ejemplo +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let nav = Nav::tabs() +//! .with_layout(nav::Layout::End) +//! .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(nav::Item::link_blank(L10n::n("External"), |_| "https://www.google.es")) +//! .add_item(nav::Item::dropdown( +//! Dropdown::new() +//! .with_title(L10n::n("Options")) +//! .with_items(TypedOp::AddMany(vec![ +//! Typed::with(dropdown::Item::link(L10n::n("Action"), |_| "/action")), +//! Typed::with(dropdown::Item::link(L10n::n("Another action"), |_| "/another")), +//! ])), +//! )) +//! .add_item(nav::Item::link_disabled(L10n::n("Disabled"), |_| "#")); +//! ``` + +mod props; +pub use props::{Kind, Layout}; + +mod component; +pub use component::Nav; + +mod item; +pub use item::{Item, ItemKind}; diff --git a/extensions/pagetop-bootsier/src/theme/nav/component.rs b/extensions/pagetop-bootsier/src/theme/nav/component.rs new file mode 100644 index 0000000..2bd4377 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/nav/component.rs @@ -0,0 +1,135 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +/// Componente para crear un **menú** o alguna de sus variantes ([`nav::Kind`]). +/// +/// Presenta un menú con una lista de elementos usando una vista básica, o alguna de sus variantes +/// como *pestañas* (`Tabs`), *botones* (`Pills`) o *subrayado* (`Underline`). También permite +/// controlar su distribución y orientación ([`nav::Layout`](crate::theme::nav::Layout)). +/// +/// Ver ejemplo en el módulo [`nav`]. +/// Si no contiene elementos, el componente **no se renderiza**. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Nav { + id : AttrId, + classes : AttrClasses, + items : Children, + nav_kind : nav::Kind, + nav_layout: nav::Layout, +} + +impl Component for Nav { + fn new() -> Self { + Nav::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes(ClassesOp::Prepend, { + let mut classes = "nav".to_string(); + self.nav_kind().push_class(&mut classes); + self.nav_layout().push_class(&mut classes); + classes + }); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let items = self.items().render(cx); + if items.is_empty() { + return PrepareMarkup::None; + } + + PrepareMarkup::With(html! { + ul id=[self.id()] class=[self.classes().get()] { + (items) + } + }) + } +} + +impl Nav { + /// Crea un `Nav` usando pestañas para los elementos (*Tabs*). + pub fn tabs() -> Self { + Nav::default().with_kind(nav::Kind::Tabs) + } + + /// Crea un `Nav` usando botones para los elementos (*Pills*). + pub fn pills() -> Self { + Nav::default().with_kind(nav::Kind::Pills) + } + + /// Crea un `Nav` usando elementos subrayados (*Underline*). + pub fn underline() -> Self { + Nav::default().with_kind(nav::Kind::Underline) + } + + // **< Nav BUILDER >**************************************************************************** + + /// Establece el identificador único (`id`) del menú. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + /// Modifica la lista de clases CSS aplicadas al menú. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Cambia el estilo del menú (*Tabs*, *Pills*, *Underline* o *Default*). + #[builder_fn] + pub fn with_kind(mut self, kind: nav::Kind) -> Self { + self.nav_kind = kind; + self + } + + /// Selecciona la distribución y orientación del menú. + #[builder_fn] + pub fn with_layout(mut self, layout: nav::Layout) -> Self { + self.nav_layout = layout; + self + } + + /// Añade un nuevo elemento hijo al menú. + pub fn add_item(mut self, item: nav::Item) -> Self { + self.items.add(Child::with(item)); + self + } + + /// Modifica la lista de elementos (`children`) aplicando una operación [`TypedOp`]. + #[builder_fn] + pub fn with_items(mut self, op: TypedOp<nav::Item>) -> Self { + self.items.alter_typed(op); + self + } + + // **< Nav GETTERS >**************************************************************************** + + /// Devuelve las clases CSS asociadas al menú. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el estilo visual seleccionado. + pub fn nav_kind(&self) -> &nav::Kind { + &self.nav_kind + } + + /// Devuelve la distribución y orientación seleccionada. + pub fn nav_layout(&self) -> &nav::Layout { + &self.nav_layout + } + + /// Devuelve la lista de elementos (`children`) del menú. + pub fn items(&self) -> &Children { + &self.items + } +} diff --git a/extensions/pagetop-bootsier/src/theme/nav/item.rs b/extensions/pagetop-bootsier/src/theme/nav/item.rs new file mode 100644 index 0000000..a79947c --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/nav/item.rs @@ -0,0 +1,284 @@ +use pagetop::prelude::*; + +use crate::prelude::*; +use crate::LOCALES_BOOTSIER; + +// **< ItemKind >*********************************************************************************** + +/// Tipos de [`nav::Item`](crate::theme::nav::Item) disponibles en un menú +/// [`Nav`](crate::theme::Nav). +/// +/// Define internamente la naturaleza del elemento y su comportamiento al mostrarse o interactuar +/// con él. +#[derive(AutoDefault)] +pub enum ItemKind { + /// Elemento vacío, no produce salida. + #[default] + Void, + /// Etiqueta sin comportamiento interactivo. + Label(L10n), + /// Elemento de navegación. Opcionalmente puede abrirse en una nueva ventana y estar + /// inicialmente deshabilitado. + Link { + label: L10n, + path: FnPathByContext, + blank: bool, + disabled: bool, + }, + /// Elemento que despliega un menú [`Dropdown`]. + Dropdown(Typed<Dropdown>), +} + +impl ItemKind { + const ITEM: &str = "nav-item"; + const DROPDOWN: &str = "nav-item dropdown"; + + // Devuelve las clases base asociadas al tipo de elemento. + #[inline] + const fn as_str(&self) -> &'static str { + match self { + Self::Void => "", + Self::Dropdown(_) => Self::DROPDOWN, + _ => Self::ITEM, + } + } + + /* Añade las clases asociadas al tipo de elemento a la cadena de clases (reservado). + #[inline] + pub(crate) fn push_class(&self, classes: &mut String) { + let class = self.as_str(); + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } */ + + // Devuelve las clases asociadas al tipo de elemento. + #[inline] + pub(crate) fn to_class(&self) -> String { + self.as_str().to_owned() + } +} + +// **< Item >*************************************************************************************** + +/// Representa un **elemento individual** de un menú [`Nav`](crate::theme::Nav). +/// +/// Cada instancia de [`nav::Item`](crate::theme::nav::Item) se traduce en un componente visible que +/// puede comportarse como texto, enlace, botón o menú desplegable según su [`ItemKind`]. +/// +/// Permite definir identificador, clases de estilo adicionales o tipo de interacción asociada, +/// manteniendo una interfaz común para renderizar todos los elementos del menú. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Item { + id : AttrId, + classes : AttrClasses, + item_kind: ItemKind, +} + +impl Component for Item { + fn new() -> Self { + Item::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes(ClassesOp::Prepend, self.item_kind().to_class()); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + match self.item_kind() { + ItemKind::Void => PrepareMarkup::None, + + ItemKind::Label(label) => PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + span class="nav-link disabled" aria-disabled="true" { + (label.using(cx)) + } + } + }), + + ItemKind::Link { + label, + path, + blank, + disabled, + } => { + let path = path(cx); + let current_path = cx.request().map(|request| request.path()); + let is_current = !*disabled && (current_path == Some(path)); + + let mut classes = "nav-link".to_string(); + if is_current { + classes.push_str(" active"); + } + if *disabled { + classes.push_str(" disabled"); + } + + let href = (!*disabled).then_some(path); + let target = (!*disabled && *blank).then_some("_blank"); + let rel = (!*disabled && *blank).then_some("noopener noreferrer"); + + let aria_current = (href.is_some() && is_current).then_some("page"); + let aria_disabled = (*disabled).then_some("true"); + + PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + a + class=(classes) + href=[href] + target=[target] + rel=[rel] + aria-current=[aria_current] + aria-disabled=[aria_disabled] + { + (label.using(cx)) + } + } + }) + } + + ItemKind::Dropdown(menu) => { + if let Some(dd) = menu.borrow() { + let items = dd.items().render(cx); + if items.is_empty() { + return PrepareMarkup::None; + } + let title = dd.title().lookup(cx).unwrap_or_else(|| { + L10n::t("dropdown", &LOCALES_BOOTSIER) + .lookup(cx) + .unwrap_or_else(|| "Dropdown".to_string()) + }); + PrepareMarkup::With(html! { + li id=[self.id()] class=[self.classes().get()] { + a + class="nav-link dropdown-toggle" + data-bs-toggle="dropdown" + href="#" + role="button" + aria-expanded="false" + { + (title) + } + ul class="dropdown-menu" { + (items) + } + } + }) + } else { + PrepareMarkup::None + } + } + } + } +} + +impl Item { + /// Crea un elemento de tipo texto, mostrado sin interacción. + pub fn label(label: L10n) -> Self { + Item { + item_kind: ItemKind::Label(label), + ..Default::default() + } + } + + /// Crea un enlace para la navegación. + pub fn link(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: false, + disabled: false, + }, + ..Default::default() + } + } + + /// Crea un enlace deshabilitado que no permite la interacción. + pub fn link_disabled(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: false, + disabled: true, + }, + ..Default::default() + } + } + + /// Crea un enlace que se abre en una nueva ventana o pestaña. + pub fn link_blank(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: true, + disabled: false, + }, + ..Default::default() + } + } + + /// Crea un enlace inicialmente deshabilitado que se abriría en una nueva ventana. + pub fn link_blank_disabled(label: L10n, path: FnPathByContext) -> Self { + Item { + item_kind: ItemKind::Link { + label, + path, + blank: true, + disabled: true, + }, + ..Default::default() + } + } + + /// Crea un elemento de navegación que contiene un menú desplegable [`Dropdown`]. + /// + /// Sólo se tienen en cuenta **el título** (si no existe le asigna uno por defecto) y **la lista + /// de elementos** del [`Dropdown`]; el resto de propiedades del componente no afectarán a su + /// representación en [`Nav`]. + pub fn dropdown(menu: Dropdown) -> Self { + Item { + item_kind: ItemKind::Dropdown(Typed::with(menu)), + ..Default::default() + } + } + + // **< Item BUILDER >*************************************************************************** + + /// Establece el identificador único (`id`) del elemento. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + /// Modifica la lista de clases CSS aplicadas al elemento. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + // **< Item GETTERS >*************************************************************************** + + /// Devuelve las clases CSS asociadas al elemento. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el tipo de elemento representado. + pub fn item_kind(&self) -> &ItemKind { + &self.item_kind + } +} diff --git a/extensions/pagetop-bootsier/src/theme/nav/props.rs b/extensions/pagetop-bootsier/src/theme/nav/props.rs new file mode 100644 index 0000000..46a4e2b --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/nav/props.rs @@ -0,0 +1,120 @@ +use pagetop::prelude::*; + +// **< Kind >*************************************************************************************** + +/// Define la variante de presentación de un menú [`Nav`](crate::theme::Nav). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Kind { + /// Estilo por defecto, lista de enlaces flexible y minimalista. + #[default] + Default, + /// Pestañas con borde para cambiar entre secciones. + Tabs, + /// Botones con fondo que resaltan el elemento activo. + Pills, + /// Variante con subrayado del elemento activo, estética ligera. + Underline, +} + +impl Kind { + const TABS: &str = "nav-tabs"; + const PILLS: &str = "nav-pills"; + const UNDERLINE: &str = "nav-underline"; + + // Devuelve la clase base asociada al tipo de menú, o una cadena vacía si no aplica. + #[rustfmt::skip] + #[inline] + const fn as_str(self) -> &'static str { + match self { + Self::Default => "", + Self::Tabs => Self::TABS, + Self::Pills => Self::PILLS, + Self::Underline => Self::UNDERLINE, + } + } + + // Añade la clase asociada al tipo de menú a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let class = self.as_str(); + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + + /* Devuelve la clase asociada al tipo de menú, o una cadena vacía si no aplica (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + self.as_str().to_owned() + } */ +} + +// **< Layout >************************************************************************************* + +/// Distribución y orientación de un menú [`Nav`](crate::theme::Nav). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Layout { + /// Comportamiento por defecto, ancho definido por el contenido y sin alineación forzada. + #[default] + Default, + /// Alinea los elementos al inicio de la fila. + Start, + /// Centra horizontalmente los elementos. + Center, + /// Alinea los elementos al final de la fila. + End, + /// Apila los elementos en columna. + Vertical, + /// Los elementos se expanden para rellenar la fila. + Fill, + /// Todos los elementos ocupan el mismo ancho rellenando la fila. + Justified, +} + +impl Layout { + const START: &str = "justify-content-start"; + const CENTER: &str = "justify-content-center"; + const END: &str = "justify-content-end"; + const VERTICAL: &str = "flex-column"; + const FILL: &str = "nav-fill"; + const JUSTIFIED: &str = "nav-justified"; + + // Devuelve la clase base asociada a la distribución y orientación del menú. + #[rustfmt::skip] + #[inline] + const fn as_str(self) -> &'static str { + match self { + Self::Default => "", + Self::Start => Self::START, + Self::Center => Self::CENTER, + Self::End => Self::END, + Self::Vertical => Self::VERTICAL, + Self::Fill => Self::FILL, + Self::Justified => Self::JUSTIFIED, + } + } + + // Añade la clase asociada a la distribución y orientación del menú a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let class = self.as_str(); + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + + /* Devuelve la clase asociada a la distribución y orientación del menú, o una cadena vacía si no + // aplica (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + self.as_str().to_owned() + } */ +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar.rs b/extensions/pagetop-bootsier/src/theme/navbar.rs new file mode 100644 index 0000000..7b958d7 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar.rs @@ -0,0 +1,136 @@ +//! Definiciones para crear barras de navegación [`Navbar`]. +//! +//! Cada [`navbar::Item`](crate::theme::navbar::Item) representa un elemento individual de la barra +//! de navegación [`Navbar`], con distintos comportamientos según su finalidad, como menús +//! [`Nav`](crate::theme::Nav) o textos localizados usando [`L10n`](pagetop::locale::L10n). +//! +//! También puede mostrar una marca de identidad ([`navbar::Brand`](crate::theme::navbar::Brand)) +//! que identifique la compañía, producto o nombre del proyecto asociado a la solución web. +//! +//! # Ejemplos +//! +//! Barra **simple**, sólo con un menú horizontal: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let navbar = Navbar::simple() +//! .add_item(navbar::Item::nav( +//! Nav::new() +//! .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(nav::Item::link(L10n::n("About"), |_| "/about")) +//! .add_item(nav::Item::link(L10n::n("Contact"), |_| "/contact")) +//! )); +//! ``` +//! +//! Barra **colapsable**, con botón de despliegue y contenido en el desplegable cuando colapsa: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let navbar = Navbar::simple_toggle() +//! .with_expand(BreakPoint::MD) +//! .add_item(navbar::Item::nav( +//! Nav::new() +//! .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(nav::Item::link_blank(L10n::n("Docs"), |_| "https://docs.example.com")) +//! .add_item(nav::Item::link(L10n::n("Support"), |_| "/support")) +//! )); +//! ``` +//! +//! Barra con **marca de identidad a la izquierda** y menú a la derecha, típica de una cabecera: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let brand = navbar::Brand::new() +//! .with_title(L10n::n("PageTop")) +//! .with_path(Some(|_| "/")); +//! +//! let navbar = Navbar::brand_left(brand) +//! .add_item(navbar::Item::nav( +//! Nav::new() +//! .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(nav::Item::dropdown( +//! Dropdown::new() +//! .with_title(L10n::n("Tools")) +//! .add_item(dropdown::Item::link(L10n::n("Generator"), |_| "/tools/gen")) +//! .add_item(dropdown::Item::link(L10n::n("Reports"), |_| "/tools/reports")) +//! )) +//! .add_item(nav::Item::link_disabled(L10n::n("Disabled"), |_| "#")) +//! )); +//! ``` +//! +//! Barra con **botón de despliegue a la izquierda** y **marca de identidad a la derecha**: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let brand = navbar::Brand::new() +//! .with_title(L10n::n("Intranet")) +//! .with_path(Some(|_| "/")); +//! +//! let navbar = Navbar::brand_right(brand) +//! .with_expand(BreakPoint::LG) +//! .add_item(navbar::Item::nav( +//! Nav::pills() +//! .add_item(nav::Item::link(L10n::n("Dashboard"), |_| "/dashboard")) +//! .add_item(nav::Item::link(L10n::n("Users"), |_| "/users")) +//! )); +//! ``` +//! +//! Barra con el **contenido en un *offcanvas***, ideal para dispositivos móviles o menús largos: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let oc = Offcanvas::new() +//! .with_id("main_offcanvas") +//! .with_title(L10n::n("Main menu")) +//! .with_placement(offcanvas::Placement::Start) +//! .with_backdrop(offcanvas::Backdrop::Enabled); +//! +//! let navbar = Navbar::offcanvas(oc) +//! .add_item(navbar::Item::nav( +//! Nav::new() +//! .add_item(nav::Item::link(L10n::n("Home"), |_| "/")) +//! .add_item(nav::Item::link(L10n::n("Profile"), |_| "/profile")) +//! .add_item(nav::Item::dropdown( +//! Dropdown::new() +//! .with_title(L10n::n("More")) +//! .add_item(dropdown::Item::link(L10n::n("Settings"), |_| "/settings")) +//! .add_item(dropdown::Item::link(L10n::n("Help"), |_| "/help")) +//! )) +//! )); +//! ``` +//! +//! Barra **fija arriba**: +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let brand = navbar::Brand::new() +//! .with_title(L10n::n("Main App")) +//! .with_path(Some(|_| "/")); +//! +//! let navbar = Navbar::brand_left(brand) +//! .with_position(navbar::Position::FixedTop) +//! .add_item(navbar::Item::nav( +//! Nav::new() +//! .add_item(nav::Item::link(L10n::n("Dashboard"), |_| "/")) +//! .add_item(nav::Item::link(L10n::n("Donors"), |_| "/donors")) +//! .add_item(nav::Item::link(L10n::n("Stock"), |_| "/stock")) +//! )); +//! ``` + +mod props; +pub use props::{Layout, Position}; + +mod brand; +pub use brand::Brand; + +mod component; +pub use component::Navbar; + +mod item; +pub use item::Item; diff --git a/extensions/pagetop-bootsier/src/theme/navbar/brand.rs b/extensions/pagetop-bootsier/src/theme/navbar/brand.rs new file mode 100644 index 0000000..e969b0e --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/brand.rs @@ -0,0 +1,111 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +/// Marca de identidad para mostrar en una barra de navegación [`Navbar`]. +/// +/// Representa la identidad del sitio con una imagen, título y eslogan: +/// +/// - Si hay URL ([`with_path()`](Self::with_path)), el bloque completo actúa como enlace. Por +/// defecto enlaza a la raíz del sitio (`/`). +/// - Si no hay imagen ([`with_image()`](Self::with_image)) ni título +/// ([`with_title()`](Self::with_title)), la marca de identidad no se renderiza. +/// - El eslogan ([`with_slogan()`](Self::with_slogan)) es opcional; por defecto no tiene contenido. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Brand { + id : AttrId, + image : Typed<Image>, + #[default(_code = "L10n::n(&global::SETTINGS.app.name)")] + title : L10n, + slogan: L10n, + #[default(_code = "Some(|_| \"/\")")] + path : Option<FnPathByContext>, +} + +impl Component for Brand { + fn new() -> Self { + Brand::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + let image = self.image().render(cx); + let title = self.title().using(cx); + if title.is_empty() && image.is_empty() { + return PrepareMarkup::None; + } + let slogan = self.slogan().using(cx); + PrepareMarkup::With(html! { + @if let Some(path) = self.path() { + a class="navbar-brand" href=(path(cx)) { (image) (title) (slogan) } + } @else { + span class="navbar-brand" { (image) (title) (slogan) } + } + }) + } +} + +impl Brand { + // **< Brand BUILDER >************************************************************************** + + /// Establece el identificador único (`id`) de la marca. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + /// Asigna o quita la imagen de marca. Si se pasa `None`, no se mostrará. + #[builder_fn] + pub fn with_image(mut self, image: Option<Image>) -> Self { + self.image.alter_component(image); + self + } + + /// Establece el título de la identidad de marca. + #[builder_fn] + pub fn with_title(mut self, title: L10n) -> Self { + self.title = title; + self + } + + /// Define el eslogan de la marca. + #[builder_fn] + pub fn with_slogan(mut self, slogan: L10n) -> Self { + self.slogan = slogan; + self + } + + /// Define la URL de destino. Si es `None`, la marca no será un enlace. + #[builder_fn] + pub fn with_path(mut self, path: Option<FnPathByContext>) -> Self { + self.path = path; + self + } + + // **< Brand GETTERS >************************************************************************** + + /// Devuelve la imagen de marca (si la hay). + pub fn image(&self) -> &Typed<Image> { + &self.image + } + + /// Devuelve el título de la identidad de marca. + pub fn title(&self) -> &L10n { + &self.title + } + + /// Devuelve el eslogan de la marca. + pub fn slogan(&self) -> &L10n { + &self.slogan + } + + /// Devuelve la función que resuelve la URL asociada a la marca (si existe). + pub fn path(&self) -> &Option<FnPathByContext> { + &self.path + } +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/component.rs b/extensions/pagetop-bootsier/src/theme/navbar/component.rs new file mode 100644 index 0000000..b40d06c --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/component.rs @@ -0,0 +1,293 @@ +use pagetop::prelude::*; + +use crate::prelude::*; +use crate::LOCALES_BOOTSIER; + +const TOGGLE_COLLAPSE: &str = "collapse"; +const TOGGLE_OFFCANVAS: &str = "offcanvas"; + +/// Componente para crear una **barra de navegación**. +/// +/// Permite mostrar enlaces, menús y una marca de identidad en distintas disposiciones (simples, con +/// botón de despliegue o dentro de un [`offcanvas`]), controladas por [`navbar::Layout`]. También +/// puede fijarse en la parte superior o inferior del documento mediante [`navbar::Position`]. +/// +/// Ver ejemplos en el módulo [`navbar`]. +/// Si no contiene elementos, el componente **no se renderiza**. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Navbar { + id : AttrId, + classes : AttrClasses, + expand : BreakPoint, + layout : navbar::Layout, + position : navbar::Position, + items : Children, +} + +impl Component for Navbar { + fn new() -> Self { + Navbar::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes(ClassesOp::Prepend, { + let mut classes = "navbar".to_string(); + self.expand().push_class(&mut classes, "navbar-expand", ""); + self.position().push_class(&mut classes); + classes + }); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + // Botón de despliegue (colapso u offcanvas) para la barra. + fn button(cx: &mut Context, data_bs_toggle: &str, id_content: &str) -> Markup { + let id_content_target = join!("#", id_content); + let aria_expanded = if data_bs_toggle == TOGGLE_COLLAPSE { + Some("false") + } else { + None + }; + html! { + button + type="button" + class="navbar-toggler" + data-bs-toggle=(data_bs_toggle) + data-bs-target=(id_content_target) + aria-controls=(id_content) + aria-expanded=[aria_expanded] + aria-label=[L10n::t("toggle", &LOCALES_BOOTSIER).lookup(cx)] + { + span class="navbar-toggler-icon" {} + } + } + } + + // Si no hay contenidos, no tiene sentido mostrar una barra vacía. + let items = self.items().render(cx); + if items.is_empty() { + return PrepareMarkup::None; + } + + // Asegura que la barra tiene un id estable para poder asociarlo al colapso/offcanvas. + let id = cx.required_id::<Self>(self.id()); + + PrepareMarkup::With(html! { + nav id=(id) class=[self.classes().get()] { + div class="container-fluid" { + @match self.layout() { + // Barra más sencilla: sólo contenido. + navbar::Layout::Simple => { + (items) + }, + + // Barra sencilla que se puede contraer/expandir. + navbar::Layout::SimpleToggle => { + @let id_content = join!(id, "-content"); + + (button(cx, TOGGLE_COLLAPSE, &id_content)) + div id=(id_content) class="collapse navbar-collapse" { + (items) + } + }, + + // Barra con marca a la izquierda, siempre visible. + navbar::Layout::SimpleBrandLeft(brand) => { + (brand.render(cx)) + (items) + }, + + // Barra con marca a la izquierda y botón a la derecha. + navbar::Layout::BrandLeft(brand) => { + @let id_content = join!(id, "-content"); + + (brand.render(cx)) + (button(cx, TOGGLE_COLLAPSE, &id_content)) + div id=(id_content) class="collapse navbar-collapse" { + (items) + } + }, + + // Barra con botón a la izquierda y marca a la derecha. + navbar::Layout::BrandRight(brand) => { + @let id_content = join!(id, "-content"); + + (button(cx, TOGGLE_COLLAPSE, &id_content)) + (brand.render(cx)) + div id=(id_content) class="collapse navbar-collapse" { + (items) + } + }, + + // Barra cuyo contenido se muestra en un offcanvas, sin marca. + navbar::Layout::Offcanvas(offcanvas) => { + @let id_content = offcanvas.id().unwrap_or_default(); + + (button(cx, TOGGLE_OFFCANVAS, &id_content)) + @if let Some(oc) = offcanvas.borrow() { + (oc.render_offcanvas(cx, Some(self.items()))) + } + }, + + // Barra con marca a la izquierda y contenido en offcanvas. + navbar::Layout::OffcanvasBrandLeft(brand, offcanvas) => { + @let id_content = offcanvas.id().unwrap_or_default(); + + (brand.render(cx)) + (button(cx, TOGGLE_OFFCANVAS, &id_content)) + @if let Some(oc) = offcanvas.borrow() { + (oc.render_offcanvas(cx, Some(self.items()))) + } + }, + + // Barra con contenido en offcanvas y marca a la derecha. + navbar::Layout::OffcanvasBrandRight(brand, offcanvas) => { + @let id_content = offcanvas.id().unwrap_or_default(); + + (button(cx, TOGGLE_OFFCANVAS, &id_content)) + (brand.render(cx)) + @if let Some(oc) = offcanvas.borrow() { + (oc.render_offcanvas(cx, Some(self.items()))) + } + }, + } + } + } + }) + } +} + +impl Navbar { + /// Crea una barra de navegación **simple**, sin marca y sin botón. + pub fn simple() -> Self { + Navbar::default().with_layout(navbar::Layout::Simple) + } + + /// Crea una barra de navegación **simple pero colapsable**, con botón a la izquierda. + pub fn simple_toggle() -> Self { + Navbar::default().with_layout(navbar::Layout::SimpleToggle) + } + + /// Crea una barra de navegación **con marca a la izquierda**, siempre visible. + pub fn simple_brand_left(brand: navbar::Brand) -> Self { + Navbar::default().with_layout(navbar::Layout::SimpleBrandLeft(Typed::with(brand))) + } + + /// Crea una barra de navegación con **marca a la izquierda** y **botón a la derecha**. + pub fn brand_left(brand: navbar::Brand) -> Self { + Navbar::default().with_layout(navbar::Layout::BrandLeft(Typed::with(brand))) + } + + /// Crea una barra de navegación con **botón a la izquierda** y **marca a la derecha**. + pub fn brand_right(brand: navbar::Brand) -> Self { + Navbar::default().with_layout(navbar::Layout::BrandRight(Typed::with(brand))) + } + + /// Crea una barra de navegación cuyo contenido se muestra en un **offcanvas**. + pub fn offcanvas(oc: Offcanvas) -> Self { + Navbar::default().with_layout(navbar::Layout::Offcanvas(Typed::with(oc))) + } + + /// Crea una barra de navegación con **marca a la izquierda** y contenido en **offcanvas**. + pub fn offcanvas_brand_left(brand: navbar::Brand, oc: Offcanvas) -> Self { + Navbar::default().with_layout(navbar::Layout::OffcanvasBrandLeft( + Typed::with(brand), + Typed::with(oc), + )) + } + + /// Crea una barra de navegación con **marca a la derecha** y contenido en **offcanvas**. + pub fn offcanvas_brand_right(brand: navbar::Brand, oc: Offcanvas) -> Self { + Navbar::default().with_layout(navbar::Layout::OffcanvasBrandRight( + Typed::with(brand), + Typed::with(oc), + )) + } + + // **< Navbar BUILDER >************************************************************************* + + /// Establece el identificador único (`id`) de la barra de navegación. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + /// Modifica la lista de clases CSS aplicadas a la barra de navegación. + /// + /// También acepta clases predefinidas para: + /// + /// - Modificar el color de fondo ([`classes::Background`]). + /// - Definir la apariencia del texto ([`classes::Text`]). + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Define a partir de qué punto de ruptura la barra de navegación deja de colapsar. + #[builder_fn] + pub fn with_expand(mut self, bp: BreakPoint) -> Self { + self.expand = bp; + self + } + + /// Define el tipo de disposición que tendrá la barra de navegación. + #[builder_fn] + pub fn with_layout(mut self, layout: navbar::Layout) -> Self { + self.layout = layout; + self + } + + /// Define dónde se mostrará la barra de navegación dentro del documento. + #[builder_fn] + pub fn with_position(mut self, position: navbar::Position) -> Self { + self.position = position; + self + } + + /// Añade un nuevo contenido hijo. + #[inline] + pub fn add_item(mut self, item: navbar::Item) -> Self { + self.items.add(Child::with(item)); + self + } + + /// Modifica la lista de contenidos (`children`) aplicando una operación [`TypedOp`]. + #[builder_fn] + pub fn with_items(mut self, op: TypedOp<navbar::Item>) -> Self { + self.items.alter_typed(op); + self + } + + // **< Navbar GETTERS >************************************************************************* + + /// Devuelve las clases CSS asociadas a la barra de navegación. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el punto de ruptura configurado. + pub fn expand(&self) -> &BreakPoint { + &self.expand + } + + /// Devuelve la disposición configurada para la barra de navegación. + pub fn layout(&self) -> &navbar::Layout { + &self.layout + } + + /// Devuelve la posición configurada para la barra de navegación. + pub fn position(&self) -> &navbar::Position { + &self.position + } + + /// Devuelve la lista de contenidos (`children`). + pub fn items(&self) -> &Children { + &self.items + } +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/item.rs b/extensions/pagetop-bootsier/src/theme/navbar/item.rs new file mode 100644 index 0000000..7e912a4 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/item.rs @@ -0,0 +1,95 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +/// Elementos que puede contener una barra de navegación [`Navbar`](crate::theme::Navbar). +/// +/// Cada variante determina qué se renderiza y cómo. Estos elementos se colocan **dentro del +/// contenido** de la barra (la parte colapsable, el *offcanvas* o el bloque simple), por lo que son +/// independientes de la marca o del botón que ya pueda definir el propio [`navbar::Layout`]. +#[derive(AutoDefault)] +pub enum Item { + /// Sin contenido, no produce salida. + #[default] + Void, + /// Marca de identidad mostrada dentro del contenido de la barra de navegación. + /// + /// Útil cuando el [`navbar::Layout`] no incluye marca, y se quiere incluir dentro del área + /// colapsable/*offcanvas*. Si el *layout* ya muestra una marca, esta variante no la sustituye, + /// sólo añade otra dentro del bloque de contenidos. + Brand(Typed<navbar::Brand>), + /// Representa un menú de navegación [`Nav`](crate::theme::Nav). + Nav(Typed<Nav>), + /// Representa un texto libre localizado. + Text(L10n), +} + +impl Component for Item { + fn new() -> Self { + Item::default() + } + + fn id(&self) -> Option<String> { + match self { + Self::Void => None, + Self::Brand(brand) => brand.id(), + Self::Nav(nav) => nav.id(), + Self::Text(_) => None, + } + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + if let Self::Nav(nav) = self { + if let Some(mut nav) = nav.borrow_mut() { + nav.alter_classes(ClassesOp::Prepend, "navbar-nav"); + } + } + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + match self { + Self::Void => PrepareMarkup::None, + Self::Brand(brand) => PrepareMarkup::With(html! { (brand.render(cx)) }), + Self::Nav(nav) => { + if let Some(nav) = nav.borrow() { + let items = nav.items().render(cx); + if items.is_empty() { + return PrepareMarkup::None; + } + PrepareMarkup::With(html! { + ul id=[nav.id()] class=[nav.classes().get()] { + (items) + } + }) + } else { + PrepareMarkup::None + } + } + Self::Text(text) => PrepareMarkup::With(html! { + span class="navbar-text" { + (text.using(cx)) + } + }), + } + } +} + +impl Item { + /// Crea un elemento de tipo [`navbar::Brand`] para añadir en el contenido de [`Navbar`]. + /// + /// Pensado para barras colapsables u offcanvas donde se quiere que la marca aparezca en la zona + /// desplegable. + pub fn brand(brand: navbar::Brand) -> Self { + Self::Brand(Typed::with(brand)) + } + + /// Crea un elemento de tipo [`Nav`] para añadir al contenido de [`Navbar`]. + pub fn nav(item: Nav) -> Self { + Self::Nav(Typed::with(item)) + } + + /// Crea un elemento de texto localizado, mostrado sin interacción. + pub fn text(item: L10n) -> Self { + Self::Text(item) + } +} diff --git a/extensions/pagetop-bootsier/src/theme/navbar/props.rs b/extensions/pagetop-bootsier/src/theme/navbar/props.rs new file mode 100644 index 0000000..1aeb617 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/navbar/props.rs @@ -0,0 +1,98 @@ +use pagetop::prelude::*; + +use crate::prelude::*; + +// **< Layout >************************************************************************************* + +/// Representa los diferentes tipos de presentación de una barra de navegación [`Navbar`]. +#[derive(AutoDefault)] +pub enum Layout { + /// Barra simple, sin marca de identidad y sin botón de despliegue. + /// + /// La barra de navegación no se colapsa. + #[default] + Simple, + + /// Barra simple, con botón de despliegue a la izquierda y sin marca de identidad. + SimpleToggle, + + /// Barra simple, con marca de identidad a la izquierda y sin botón de despliegue. + /// + /// La barra de navegación no se colapsa. + SimpleBrandLeft(Typed<navbar::Brand>), + + /// Barra con marca de identidad a la izquierda y botón de despliegue a la derecha. + BrandLeft(Typed<navbar::Brand>), + + /// Barra con botón de despliegue a la izquierda y marca de identidad a la derecha. + BrandRight(Typed<navbar::Brand>), + + /// Contenido en [`Offcanvas`], con botón de despliegue a la izquierda y sin marca de identidad. + Offcanvas(Typed<Offcanvas>), + + /// Contenido en [`Offcanvas`], con marca de identidad a la izquierda y botón de despliegue a la + /// derecha. + OffcanvasBrandLeft(Typed<navbar::Brand>, Typed<Offcanvas>), + + /// Contenido en [`Offcanvas`], con botón de despliegue a la izquierda y marca de identidad a la + /// derecha. + OffcanvasBrandRight(Typed<navbar::Brand>, Typed<Offcanvas>), +} + +// **< Position >*********************************************************************************** + +/// Posición global de una barra de navegación [`Navbar`] en el documento. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Position { + /// Barra normal, fluye con el documento. + #[default] + Static, + /// Barra fijada en la parte superior, siempre visible. + /// + /// Puede ser necesario reservar espacio en la parte superior del contenido que fluye debajo + /// para evitar que quede oculto por la barra. + FixedTop, + /// Barra fijada en la parte inferior, siempre visible. + /// + /// Puede ser necesario reservar espacio en la parte inferior del contenido que fluye debajo + /// para evitar que quede oculto por la barra. + FixedBottom, + /// La barra de navegación se fija en la parte superior al hacer *scroll*. + StickyTop, + /// La barra de navegación se fija en la parte inferior al hacer *scroll*. + StickyBottom, +} + +impl Position { + // Devuelve la clase base asociada a la posición de la barra de navegación. + #[inline] + const fn as_str(self) -> &'static str { + match self { + Self::Static => "", + Self::FixedTop => "fixed-top", + Self::FixedBottom => "fixed-bottom", + Self::StickyTop => "sticky-top", + Self::StickyBottom => "sticky-bottom", + } + } + + // Añade la clase asociada a la posición de la barra de navegación a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let class = self.as_str(); + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + + /* Devuelve la clase asociada a la posición de la barra de navegación, o cadena vacía si no + // aplica (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + self.as_str().to_string() + } */ +} diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas.rs b/extensions/pagetop-bootsier/src/theme/offcanvas.rs new file mode 100644 index 0000000..18cc253 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/offcanvas.rs @@ -0,0 +1,27 @@ +//! Definiciones para crear paneles laterales deslizantes [`Offcanvas`]. +//! +//! # Ejemplo +//! +//! ```rust +//! # use pagetop::prelude::*; +//! # use pagetop_bootsier::prelude::*; +//! let panel = Offcanvas::new() +//! .with_id("offcanvas_example") +//! .with_title(L10n::n("Offcanvas title")) +//! .with_placement(offcanvas::Placement::End) +//! .with_backdrop(offcanvas::Backdrop::Enabled) +//! .with_body_scroll(offcanvas::BodyScroll::Enabled) +//! .with_visibility(offcanvas::Visibility::Default) +//! .add_child(Dropdown::new() +//! .with_title(L10n::n("Menu")) +//! .add_item(dropdown::Item::label(L10n::n("Label"))) +//! .add_item(dropdown::Item::link_blank(L10n::n("Google"), |_| "https://www.google.es")) +//! .add_item(dropdown::Item::link(L10n::n("Sign out"), |_| "/signout")) +//! ); +//! ``` + +mod props; +pub use props::{Backdrop, BodyScroll, Placement, Visibility}; + +mod component; +pub use component::Offcanvas; diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs new file mode 100644 index 0000000..f17fe97 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/offcanvas/component.rs @@ -0,0 +1,240 @@ +use pagetop::prelude::*; + +use crate::prelude::*; +use crate::LOCALES_BOOTSIER; + +/// Componente para crear un **panel lateral deslizante** con contenidos adicionales. +/// +/// Útil para navegación, filtros, formularios o menús contextuales. Incluye las siguientes +/// características principales: +/// +/// - Puede mostrar una capa de fondo para centrar la atención del usuario en el panel +/// ([`with_backdrop()`](Self::with_backdrop)); o puede bloquear el desplazamiento del documento +/// principal ([`with_body_scroll()`](Self::with_body_scroll)). +/// - Se puede configurar el borde de la ventana desde el que se desliza el panel +/// ([`with_placement()`](Self::with_placement)). +/// - Encabezado con título ([`with_title()`](Self::with_title)) y **botón de cierre** integrado. +/// - Puede cambiar su comportamiento a partir de un punto de ruptura +/// ([`with_breakpoint()`](Self::with_breakpoint)). +/// - Asocia título y controles de accesibilidad a un identificador único y expone atributos +/// adecuados para lectores de pantalla y navegación por teclado. +/// +/// Ver ejemplo en el módulo [`offcanvas`]. +/// Si no contiene elementos, el componente **no se renderiza**. +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Offcanvas { + id : AttrId, + classes : AttrClasses, + title : L10n, + breakpoint: BreakPoint, + backdrop : offcanvas::Backdrop, + scrolling : offcanvas::BodyScroll, + placement : offcanvas::Placement, + visibility: offcanvas::Visibility, + children : Children, +} + +impl Component for Offcanvas { + fn new() -> Self { + Offcanvas::default() + } + + fn id(&self) -> Option<String> { + self.id.get() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + self.alter_classes(ClassesOp::Prepend, { + let mut classes = "offcanvas".to_string(); + self.breakpoint().push_class(&mut classes, "offcanvas", ""); + self.placement().push_class(&mut classes); + self.visibility().push_class(&mut classes); + classes + }); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + PrepareMarkup::With(self.render_offcanvas(cx, None)) + } +} + +impl Offcanvas { + // **< Offcanvas BUILDER >********************************************************************** + + /// Establece el identificador único (`id`) del panel. + #[builder_fn] + pub fn with_id(mut self, id: impl AsRef<str>) -> Self { + self.id.alter_value(id); + self + } + + /// Modifica la lista de clases CSS aplicadas al panel. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + /// Establece el título del encabezado. + #[builder_fn] + pub fn with_title(mut self, title: L10n) -> Self { + self.title = title; + self + } + + /// Establece el punto de ruptura a partir del cual cambia el comportamiento del panel. + /// + /// - **Por debajo** de ese tamaño de pantalla, el componente actúa como panel deslizante + /// ([`Offcanvas`]). + /// - **Por encima**, el contenido del panel se muestra tal cual, integrado en la página. + /// + /// Por ejemplo, con `BreakPoint::LG`, será *offcanvas* en móviles y tabletas, y visible + /// directamente en pantallas grandes. Por defecto usa `BreakPoint::None` para que sea + /// *offcanvas* siempre. + #[builder_fn] + pub fn with_breakpoint(mut self, bp: BreakPoint) -> Self { + self.breakpoint = bp; + self + } + + /// Ajusta la capa de fondo del panel para definir su comportamiento al hacer clic fuera del + /// panel. + #[builder_fn] + pub fn with_backdrop(mut self, backdrop: offcanvas::Backdrop) -> Self { + self.backdrop = backdrop; + self + } + + /// Permite o bloquea el desplazamiento de la página principal mientras el panel está abierto. + #[builder_fn] + pub fn with_body_scroll(mut self, scrolling: offcanvas::BodyScroll) -> Self { + self.scrolling = scrolling; + self + } + + /// Indica desde qué borde de la ventana entra y se ancla el panel. + #[builder_fn] + pub fn with_placement(mut self, placement: offcanvas::Placement) -> Self { + self.placement = placement; + self + } + + /// Fija el estado inicial del panel (oculto o visible al cargar). + #[builder_fn] + pub fn with_visibility(mut self, visibility: offcanvas::Visibility) -> Self { + self.visibility = visibility; + self + } + + /// Añade un nuevo componente hijo al panel. + #[inline] + pub fn add_child(mut self, child: impl Component) -> Self { + self.children.add(Child::with(child)); + self + } + + /// Modifica la lista de componentes (`children`) aplicando una operación [`ChildOp`]. + #[builder_fn] + pub fn with_children(mut self, op: ChildOp) -> Self { + self.children.alter_child(op); + self + } + + // **< Offcanvas GETTERS >********************************************************************** + + /// Devuelve las clases CSS asociadas al panel. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + /// Devuelve el título del panel. + pub fn title(&self) -> &L10n { + &self.title + } + + /// Devuelve el punto de ruptura configurado para cambiar el comportamiento del panel. + pub fn breakpoint(&self) -> &BreakPoint { + &self.breakpoint + } + + /// Devuelve el comportamiento configurado para la capa de fondo. + pub fn backdrop(&self) -> &offcanvas::Backdrop { + &self.backdrop + } + + /// Indica si la página principal puede desplazarse mientras el panel está abierto. + pub fn body_scroll(&self) -> &offcanvas::BodyScroll { + &self.scrolling + } + + /// Devuelve la posición de inicio del panel. + pub fn placement(&self) -> &offcanvas::Placement { + &self.placement + } + + /// Devuelve el estado inicial del panel. + pub fn visibility(&self) -> &offcanvas::Visibility { + &self.visibility + } + + /// Devuelve la lista de componentes (`children`) del panel. + pub fn children(&self) -> &Children { + &self.children + } + + // **< Offcanvas HELPERS >********************************************************************** + + pub(crate) fn render_offcanvas(&self, cx: &mut Context, extra: Option<&Children>) -> Markup { + let body = self.children().render(cx); + let body_extra = extra.map(|c| c.render(cx)).unwrap_or_else(|| html! {}); + if body.is_empty() && body_extra.is_empty() { + return html! {}; + } + + let id = cx.required_id::<Self>(self.id()); + let id_label = join!(id, "-label"); + let id_target = join!("#", id); + + let body_scroll = match self.body_scroll() { + offcanvas::BodyScroll::Disabled => None, + offcanvas::BodyScroll::Enabled => Some("true"), + }; + + let backdrop = match self.backdrop() { + offcanvas::Backdrop::Disabled => Some("false"), + offcanvas::Backdrop::Enabled => None, + offcanvas::Backdrop::Static => Some("static"), + }; + + let title = self.title().using(cx); + + html! { + div + id=(id) + class=[self.classes().get()] + tabindex="-1" + data-bs-scroll=[body_scroll] + data-bs-backdrop=[backdrop] + aria-labelledby=(id_label) + { + div class="offcanvas-header" { + @if !title.is_empty() { + h5 class="offcanvas-title" id=(id_label) { (title) } + } + button + type="button" + class="btn-close" + data-bs-dismiss="offcanvas" + data-bs-target=(id_target) + aria-label=[L10n::t("offcanvas_close", &LOCALES_BOOTSIER).lookup(cx)] + {} + } + div class="offcanvas-body" { + (body) + (body_extra) + } + } + } + } +} diff --git a/extensions/pagetop-bootsier/src/theme/offcanvas/props.rs b/extensions/pagetop-bootsier/src/theme/offcanvas/props.rs new file mode 100644 index 0000000..cdfe862 --- /dev/null +++ b/extensions/pagetop-bootsier/src/theme/offcanvas/props.rs @@ -0,0 +1,119 @@ +use pagetop::prelude::*; + +// **< Backdrop >*********************************************************************************** + +/// Comportamiento de la capa de fondo (*backdrop*) de un panel +/// [`Offcanvas`](crate::theme::Offcanvas) al deslizarse. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Backdrop { + /// Sin capa de fondo, la página principal permanece visible e interactiva. + Disabled, + /// Opción por defecto, se oscurece el fondo; un clic fuera del panel suele cerrarlo. + #[default] + Enabled, + /// Muestra la capa de fondo pero no se cierra al hacer clic fuera del panel. Útil si se + /// requiere completar una acción antes de salir. + Static, +} + +// **< BodyScroll >********************************************************************************* + +/// Controla si la página principal puede desplazarse al abrir un panel +/// [`Offcanvas`](crate::theme::Offcanvas). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum BodyScroll { + /// Opción por defecto, la página principal se bloquea centrando la interacción en el panel. + #[default] + Disabled, + /// Permite el desplazamiento de la página principal. + Enabled, +} + +// **< Placement >********************************************************************************** + +/// Posición de aparición de un panel [`Offcanvas`](crate::theme::Offcanvas) al deslizarse. +/// +/// Define desde qué borde de la ventana entra y se ancla el panel. +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Placement { + /// Opción por defecto, desde el borde inicial según dirección de lectura (respetando LTR/RTL). + #[default] + Start, + /// Desde el borde final según dirección de lectura (respetando LTR/RTL). + End, + /// Desde la parte superior. + Top, + /// Desde la parte inferior. + Bottom, +} + +impl Placement { + // Devuelve la clase base asociada a la posición de aparición del panel. + #[rustfmt::skip] + #[inline] + const fn as_str(self) -> &'static str { + match self { + Placement::Start => "offcanvas-start", + Placement::End => "offcanvas-end", + Placement::Top => "offcanvas-top", + Placement::Bottom => "offcanvas-bottom", + } + } + + // Añade la clase asociada a la posición de aparición del panel a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(self.as_str()); + } + + /* Devuelve la clase asociada a la posición de aparición del panel (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + self.as_str().to_owned() + } */ +} + +// **< Visibility >********************************************************************************* + +/// Estado inicial de un panel [`Offcanvas`](crate::theme::Offcanvas). +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum Visibility { + /// El panel permanece oculto desde el principio. + #[default] + Default, + /// El panel se muestra abierto al cargar. + Show, +} + +impl Visibility { + // Devuelve la clase base asociada al estado inicial del panel. + #[inline] + const fn as_str(self) -> &'static str { + match self { + Visibility::Default => "", + Visibility::Show => "show", + } + } + + // Añade la clase asociada al estado inicial del panel a la cadena de clases. + #[inline] + pub(crate) fn push_class(self, classes: &mut String) { + let class = self.as_str(); + if class.is_empty() { + return; + } + if !classes.is_empty() { + classes.push(' '); + } + classes.push_str(class); + } + + /* Devuelve la clase asociada al estado inicial, o una cadena vacía si no aplica (reservado). + #[inline] + pub(crate) fn to_class(self) -> String { + self.as_str().to_owned() + } */ +} diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js b/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js new file mode 100644 index 0000000..0b87369 --- /dev/null +++ b/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.3.8 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!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).bootstrap=e()}(this,function(){"use strict";const t=new Map,e={set(e,i,n){t.has(e)||t.set(e,new Map);const s=t.get(e);s.has(i)||0===s.size?s.set(i,n):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(s.keys())[0]}.`)},get:(e,i)=>t.has(e)&&t.get(e).get(i)||null,remove(e,i){if(!t.has(e))return;const n=t.get(e);n.delete(i),0===n.size&&t.delete(e)}},i="transitionend",n=t=>(t&&window.CSS&&window.CSS.escape&&(t=t.replace(/#([^\s"#']+)/g,(t,e)=>`#${CSS.escape(e)}`)),t),s=t=>null==t?`${t}`:Object.prototype.toString.call(t).match(/\s([a-z]+)/i)[1].toLowerCase(),o=t=>{t.dispatchEvent(new Event(i))},r=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),a=t=>r(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(n(t)):null,l=t=>{if(!r(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",()=>{for(const t of p)t()}),p.push(e)):e()},_=(t,e=[],i=t)=>"function"==typeof t?t.call(...e):i,b=(t,e,n=!0)=>{if(!n)return void _(t);const s=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(e)+5;let r=!1;const a=({target:n})=>{n===e&&(r=!0,e.removeEventListener(i,a),_(t))};e.addEventListener(i,a),setTimeout(()=>{r||o(e)},s)},v=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,A=/::\d+$/,E={};let T=1;const C={mouseenter:"mouseover",mouseleave:"mouseout"},O=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function x(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function k(t){const e=x(t);return t.uidEvent=e,E[e]=E[e]||{},E[e]}function L(t,e,i=null){return Object.values(t).find(t=>t.callable===e&&t.delegationSelector===i)}function S(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=N(t);return O.has(o)||(o=t),[n,s,o]}function D(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=S(e,i,n);if(e in C){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=k(t),c=l[a]||(l[a]={}),h=L(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=x(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return j(s,{delegateTarget:r}),n.oneOff&&P.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return j(n,{delegateTarget:t}),i.oneOff&&P.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function $(t,e,i,n,s){const o=L(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function I(t,e,i,n){const s=e[i]||{};for(const[o,r]of Object.entries(s))o.includes(n)&&$(t,e,i,r.callable,r.delegationSelector)}function N(t){return t=t.replace(w,""),C[t]||t}const P={on(t,e,i,n){D(t,e,i,n,!1)},one(t,e,i,n){D(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=k(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))I(t,l,i,e.slice(1));for(const[i,n]of Object.entries(c)){const s=i.replace(A,"");a&&!e.includes(s)||$(t,l,r,n.callable,n.delegationSelector)}}else{if(!Object.keys(c).length)return;$(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f();let s=null,o=!0,r=!0,a=!1;e!==N(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());const l=j(new Event(e,{bubbles:o,cancelable:!0}),i);return a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function j(t,e={}){for(const[i,n]of Object.entries(e))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}function M(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function F(t){return t.replace(/[A-Z]/g,t=>`-${t.toLowerCase()}`)}const H={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter(t=>t.startsWith("bs")&&!t.startsWith("bsConfig"));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1),e[i]=M(t.dataset[n])}return e},getDataAttribute:(t,e)=>M(t.getAttribute(`data-bs-${F(e)}`))};class W{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=r(e)?H.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...r(e)?H.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const[i,n]of Object.entries(e)){const e=t[i],o=r(e)?"element":s(e);if(!new RegExp(n).test(o))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${i}" provided type "${o}" but expected type "${n}".`)}}}class B extends W{constructor(t,i){super(),(t=a(t))&&(this._element=t,this._config=this._getConfig(i),e.set(this._element,this.constructor.DATA_KEY,this))}dispose(){e.remove(this._element,this.constructor.DATA_KEY),P.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){b(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return e.get(a(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.3.8"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const z=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e?e.split(",").map(t=>n(t)).join(","):null},R={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter(t=>t.matches(e)),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map(t=>`${t}:not([tabindex^="-"])`).join(",");return this.find(e,t).filter(t=>!c(t)&&l(t))},getSelectorFromElement(t){const e=z(t);return e&&R.findOne(e)?e:null},getElementFromSelector(t){const e=z(t);return e?R.findOne(e):null},getMultipleElementsFromSelector(t){const e=z(t);return e?R.find(e):[]}},q=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,n=t.NAME;P.on(document,i,`[data-bs-dismiss="${n}"]`,function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const s=R.getElementFromSelector(this)||this.closest(`.${n}`);t.getOrCreateInstance(s)[e]()})},V=".bs.alert",K=`close${V}`,Q=`closed${V}`;class X extends B{static get NAME(){return"alert"}close(){if(P.trigger(this._element,K).defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback(()=>this._destroyElement(),this._element,t)}_destroyElement(){this._element.remove(),P.trigger(this._element,Q),this.dispose()}static jQueryInterface(t){return this.each(function(){const e=X.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}})}}q(X,"close"),g(X);const Y='[data-bs-toggle="button"]';class U extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each(function(){const e=U.getOrCreateInstance(this);"toggle"===t&&e[t]()})}}P.on(document,"click.bs.button.data-api",Y,t=>{t.preventDefault();const e=t.target.closest(Y);U.getOrCreateInstance(e).toggle()}),g(U);const G=".bs.swipe",J=`touchstart${G}`,Z=`touchmove${G}`,tt=`touchend${G}`,et=`pointerdown${G}`,it=`pointerup${G}`,nt={endCallback:null,leftCallback:null,rightCallback:null},st={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class ot extends W{constructor(t,e){super(),this._element=t,t&&ot.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return nt}static get DefaultType(){return st}static get NAME(){return"swipe"}dispose(){P.off(this._element,G)}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),_(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&_(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(P.on(this._element,et,t=>this._start(t)),P.on(this._element,it,t=>this._end(t)),this._element.classList.add("pointer-event")):(P.on(this._element,J,t=>this._start(t)),P.on(this._element,Z,t=>this._move(t)),P.on(this._element,tt,t=>this._end(t)))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const rt=".bs.carousel",at=".data-api",lt="ArrowLeft",ct="ArrowRight",ht="next",dt="prev",ut="left",ft="right",pt=`slide${rt}`,mt=`slid${rt}`,gt=`keydown${rt}`,_t=`mouseenter${rt}`,bt=`mouseleave${rt}`,vt=`dragstart${rt}`,yt=`load${rt}${at}`,wt=`click${rt}${at}`,At="carousel",Et="active",Tt=".active",Ct=".carousel-item",Ot=Tt+Ct,xt={[lt]:ft,[ct]:ut},kt={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},Lt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class St extends B{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=R.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===At&&this.cycle()}static get Default(){return kt}static get DefaultType(){return Lt}static get NAME(){return"carousel"}next(){this._slide(ht)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(dt)}pause(){this._isSliding&&o(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval(()=>this.nextWhenVisible(),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?P.one(this._element,mt,()=>this.cycle()):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void P.one(this._element,mt,()=>this.to(t));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?ht:dt;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&P.on(this._element,gt,t=>this._keydown(t)),"hover"===this._config.pause&&(P.on(this._element,_t,()=>this.pause()),P.on(this._element,bt,()=>this._maybeEnableCycle())),this._config.touch&&ot.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of R.find(".carousel-item img",this._element))P.on(t,vt,t=>t.preventDefault());const t={leftCallback:()=>this._slide(this._directionToOrder(ut)),rightCallback:()=>this._slide(this._directionToOrder(ft)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout(()=>this._maybeEnableCycle(),500+this._config.interval))}};this._swipeHelper=new ot(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=xt[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=R.findOne(Tt,this._indicatorsElement);e.classList.remove(Et),e.removeAttribute("aria-current");const i=R.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(Et),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===ht,s=e||v(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>P.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r(pt).defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),u(s),i.classList.add(l),s.classList.add(l),this._queueCallback(()=>{s.classList.remove(l,c),s.classList.add(Et),i.classList.remove(Et,c,l),this._isSliding=!1,r(mt)},i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return R.findOne(Ot,this._element)}_getItems(){return R.find(Ct,this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return m()?t===ut?dt:ht:t===ut?ht:dt}_orderToDirection(t){return m()?t===dt?ut:ft:t===dt?ft:ut}static jQueryInterface(t){return this.each(function(){const e=St.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)})}}P.on(document,wt,"[data-bs-slide], [data-bs-slide-to]",function(t){const e=R.getElementFromSelector(this);if(!e||!e.classList.contains(At))return;t.preventDefault();const i=St.getOrCreateInstance(e),n=this.getAttribute("data-bs-slide-to");return n?(i.to(n),void i._maybeEnableCycle()):"next"===H.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())}),P.on(window,yt,()=>{const t=R.find('[data-bs-ride="carousel"]');for(const e of t)St.getOrCreateInstance(e)}),g(St);const Dt=".bs.collapse",$t=`show${Dt}`,It=`shown${Dt}`,Nt=`hide${Dt}`,Pt=`hidden${Dt}`,jt=`click${Dt}.data-api`,Mt="show",Ft="collapse",Ht="collapsing",Wt=`:scope .${Ft} .${Ft}`,Bt='[data-bs-toggle="collapse"]',zt={parent:null,toggle:!0},Rt={parent:"(null|element)",toggle:"boolean"};class qt extends B{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const i=R.find(Bt);for(const t of i){const e=R.getSelectorFromElement(t),i=R.find(e).filter(t=>t===this._element);null!==e&&i.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return zt}static get DefaultType(){return Rt}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter(t=>t!==this._element).map(t=>qt.getOrCreateInstance(t,{toggle:!1}))),t.length&&t[0]._isTransitioning)return;if(P.trigger(this._element,$t).defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(Ft),this._element.classList.add(Ht),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback(()=>{this._isTransitioning=!1,this._element.classList.remove(Ht),this._element.classList.add(Ft,Mt),this._element.style[e]="",P.trigger(this._element,It)},this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(P.trigger(this._element,Nt).defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(Ht),this._element.classList.remove(Ft,Mt);for(const t of this._triggerArray){const e=R.getElementFromSelector(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback(()=>{this._isTransitioning=!1,this._element.classList.remove(Ht),this._element.classList.add(Ft),P.trigger(this._element,Pt)},this._element,!0)}_isShown(t=this._element){return t.classList.contains(Mt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=a(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(Bt);for(const e of t){const t=R.getElementFromSelector(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=R.find(Wt,this._config.parent);return R.find(t,this._config.parent).filter(t=>!e.includes(t))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each(function(){const i=qt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}})}}P.on(document,jt,Bt,function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();for(const t of R.getMultipleElementsFromSelector(this))qt.getOrCreateInstance(t,{toggle:!1}).toggle()}),g(qt);var Vt="top",Kt="bottom",Qt="right",Xt="left",Yt="auto",Ut=[Vt,Kt,Qt,Xt],Gt="start",Jt="end",Zt="clippingParents",te="viewport",ee="popper",ie="reference",ne=Ut.reduce(function(t,e){return t.concat([e+"-"+Gt,e+"-"+Jt])},[]),se=[].concat(Ut,[Yt]).reduce(function(t,e){return t.concat([e,e+"-"+Gt,e+"-"+Jt])},[]),oe="beforeRead",re="read",ae="afterRead",le="beforeMain",ce="main",he="afterMain",de="beforeWrite",ue="write",fe="afterWrite",pe=[oe,re,ae,le,ce,he,de,ue,fe];function me(t){return t?(t.nodeName||"").toLowerCase():null}function ge(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function _e(t){return t instanceof ge(t).Element||t instanceof Element}function be(t){return t instanceof ge(t).HTMLElement||t instanceof HTMLElement}function ve(t){return"undefined"!=typeof ShadowRoot&&(t instanceof ge(t).ShadowRoot||t instanceof ShadowRoot)}const ye={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach(function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];be(s)&&me(s)&&(Object.assign(s.style,i),Object.keys(n).forEach(function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)}))})},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach(function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce(function(t,e){return t[e]="",t},{});be(n)&&me(n)&&(Object.assign(n.style,o),Object.keys(s).forEach(function(t){n.removeAttribute(t)}))})}},requires:["computeStyles"]};function we(t){return t.split("-")[0]}var Ae=Math.max,Ee=Math.min,Te=Math.round;function Ce(){var t=navigator.userAgentData;return null!=t&&t.brands&&Array.isArray(t.brands)?t.brands.map(function(t){return t.brand+"/"+t.version}).join(" "):navigator.userAgent}function Oe(){return!/^((?!chrome|android).)*safari/i.test(Ce())}function xe(t,e,i){void 0===e&&(e=!1),void 0===i&&(i=!1);var n=t.getBoundingClientRect(),s=1,o=1;e&&be(t)&&(s=t.offsetWidth>0&&Te(n.width)/t.offsetWidth||1,o=t.offsetHeight>0&&Te(n.height)/t.offsetHeight||1);var r=(_e(t)?ge(t):window).visualViewport,a=!Oe()&&i,l=(n.left+(a&&r?r.offsetLeft:0))/s,c=(n.top+(a&&r?r.offsetTop:0))/o,h=n.width/s,d=n.height/o;return{width:h,height:d,top:c,right:l+h,bottom:c+d,left:l,x:l,y:c}}function ke(t){var e=xe(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Le(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&ve(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Se(t){return ge(t).getComputedStyle(t)}function De(t){return["table","td","th"].indexOf(me(t))>=0}function $e(t){return((_e(t)?t.ownerDocument:t.document)||window.document).documentElement}function Ie(t){return"html"===me(t)?t:t.assignedSlot||t.parentNode||(ve(t)?t.host:null)||$e(t)}function Ne(t){return be(t)&&"fixed"!==Se(t).position?t.offsetParent:null}function Pe(t){for(var e=ge(t),i=Ne(t);i&&De(i)&&"static"===Se(i).position;)i=Ne(i);return i&&("html"===me(i)||"body"===me(i)&&"static"===Se(i).position)?e:i||function(t){var e=/firefox/i.test(Ce());if(/Trident/i.test(Ce())&&be(t)&&"fixed"===Se(t).position)return null;var i=Ie(t);for(ve(i)&&(i=i.host);be(i)&&["html","body"].indexOf(me(i))<0;){var n=Se(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function je(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function Me(t,e,i){return Ae(t,Ee(e,i))}function Fe(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function He(t,e){return e.reduce(function(e,i){return e[i]=t,e},{})}const We={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=we(i.placement),l=je(a),c=[Xt,Qt].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return Fe("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:He(t,Ut))}(s.padding,i),d=ke(o),u="y"===l?Vt:Xt,f="y"===l?Kt:Qt,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=Pe(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=Me(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Le(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function Be(t){return t.split("-")[1]}var ze={top:"auto",right:"auto",bottom:"auto",left:"auto"};function Re(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,m=void 0===p?0:p,g="function"==typeof h?h({x:f,y:m}):{x:f,y:m};f=g.x,m=g.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=Xt,y=Vt,w=window;if(c){var A=Pe(i),E="clientHeight",T="clientWidth";A===ge(i)&&"static"!==Se(A=$e(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===Vt||(s===Xt||s===Qt)&&o===Jt)&&(y=Kt,m-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,m*=l?1:-1),s!==Xt&&(s!==Vt&&s!==Kt||o!==Jt)||(v=Qt,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&ze),x=!0===h?function(t,e){var i=t.x,n=t.y,s=e.devicePixelRatio||1;return{x:Te(i*s)/s||0,y:Te(n*s)/s||0}}({x:f,y:m},ge(i)):{x:f,y:m};return f=x.x,m=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?m+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const qe={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:we(e.placement),variation:Be(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,Re(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,Re(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var Ve={passive:!0};const Ke={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=ge(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach(function(t){t.addEventListener("scroll",i.update,Ve)}),a&&l.addEventListener("resize",i.update,Ve),function(){o&&c.forEach(function(t){t.removeEventListener("scroll",i.update,Ve)}),a&&l.removeEventListener("resize",i.update,Ve)}},data:{}};var Qe={left:"right",right:"left",bottom:"top",top:"bottom"};function Xe(t){return t.replace(/left|right|bottom|top/g,function(t){return Qe[t]})}var Ye={start:"end",end:"start"};function Ue(t){return t.replace(/start|end/g,function(t){return Ye[t]})}function Ge(t){var e=ge(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function Je(t){return xe($e(t)).left+Ge(t).scrollLeft}function Ze(t){var e=Se(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function ti(t){return["html","body","#document"].indexOf(me(t))>=0?t.ownerDocument.body:be(t)&&Ze(t)?t:ti(Ie(t))}function ei(t,e){var i;void 0===e&&(e=[]);var n=ti(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=ge(n),r=s?[o].concat(o.visualViewport||[],Ze(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(ei(Ie(r)))}function ii(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function ni(t,e,i){return e===te?ii(function(t,e){var i=ge(t),n=$e(t),s=i.visualViewport,o=n.clientWidth,r=n.clientHeight,a=0,l=0;if(s){o=s.width,r=s.height;var c=Oe();(c||!c&&"fixed"===e)&&(a=s.offsetLeft,l=s.offsetTop)}return{width:o,height:r,x:a+Je(t),y:l}}(t,i)):_e(e)?function(t,e){var i=xe(t,!1,"fixed"===e);return i.top=i.top+t.clientTop,i.left=i.left+t.clientLeft,i.bottom=i.top+t.clientHeight,i.right=i.left+t.clientWidth,i.width=t.clientWidth,i.height=t.clientHeight,i.x=i.left,i.y=i.top,i}(e,i):ii(function(t){var e,i=$e(t),n=Ge(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=Ae(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=Ae(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+Je(t),l=-n.scrollTop;return"rtl"===Se(s||i).direction&&(a+=Ae(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}($e(t)))}function si(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?we(s):null,r=s?Be(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case Vt:e={x:a,y:i.y-n.height};break;case Kt:e={x:a,y:i.y+i.height};break;case Qt:e={x:i.x+i.width,y:l};break;case Xt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?je(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case Gt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Jt:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function oi(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.strategy,r=void 0===o?t.strategy:o,a=i.boundary,l=void 0===a?Zt:a,c=i.rootBoundary,h=void 0===c?te:c,d=i.elementContext,u=void 0===d?ee:d,f=i.altBoundary,p=void 0!==f&&f,m=i.padding,g=void 0===m?0:m,_=Fe("number"!=typeof g?g:He(g,Ut)),b=u===ee?ie:ee,v=t.rects.popper,y=t.elements[p?b:u],w=function(t,e,i,n){var s="clippingParents"===e?function(t){var e=ei(Ie(t)),i=["absolute","fixed"].indexOf(Se(t).position)>=0&&be(t)?Pe(t):t;return _e(i)?e.filter(function(t){return _e(t)&&Le(t,i)&&"body"!==me(t)}):[]}(t):[].concat(e),o=[].concat(s,[i]),r=o[0],a=o.reduce(function(e,i){var s=ni(t,i,n);return e.top=Ae(s.top,e.top),e.right=Ee(s.right,e.right),e.bottom=Ee(s.bottom,e.bottom),e.left=Ae(s.left,e.left),e},ni(t,r,n));return a.width=a.right-a.left,a.height=a.bottom-a.top,a.x=a.left,a.y=a.top,a}(_e(y)?y:y.contextElement||$e(t.elements.popper),l,h,r),A=xe(t.elements.reference),E=si({reference:A,element:v,placement:s}),T=ii(Object.assign({},v,E)),C=u===ee?T:A,O={top:w.top-C.top+_.top,bottom:C.bottom-w.bottom+_.bottom,left:w.left-C.left+_.left,right:C.right-w.right+_.right},x=t.modifiersData.offset;if(u===ee&&x){var k=x[s];Object.keys(O).forEach(function(t){var e=[Qt,Kt].indexOf(t)>=0?1:-1,i=[Vt,Kt].indexOf(t)>=0?"y":"x";O[t]+=k[i]*e})}return O}function ri(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?se:l,h=Be(n),d=h?a?ne:ne.filter(function(t){return Be(t)===h}):Ut,u=d.filter(function(t){return c.indexOf(t)>=0});0===u.length&&(u=d);var f=u.reduce(function(e,i){return e[i]=oi(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[we(i)],e},{});return Object.keys(f).sort(function(t,e){return f[t]-f[e]})}const ai={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=we(g),b=l||(_!==g&&p?function(t){if(we(t)===Yt)return[];var e=Xe(t);return[Ue(t),e,Ue(e)]}(g):[Xe(g)]),v=[g].concat(b).reduce(function(t,i){return t.concat(we(i)===Yt?ri(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)},[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C<v.length;C++){var O=v[C],x=we(O),k=Be(O)===Gt,L=[Vt,Kt].indexOf(x)>=0,S=L?"width":"height",D=oi(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),$=L?k?Qt:Xt:k?Kt:Vt;y[S]>w[S]&&($=Xe($));var I=Xe($),N=[];if(o&&N.push(D[x]<=0),a&&N.push(D[$]<=0,D[I]<=0),N.every(function(t){return t})){T=O,E=!1;break}A.set(O,N)}if(E)for(var P=function(t){var e=v.find(function(e){var i=A.get(e);if(i)return i.slice(0,t).every(function(t){return t})});if(e)return T=e,"break"},j=p?3:1;j>0&&"break"!==P(j);j--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function li(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function ci(t){return[Vt,Qt,Kt,Xt].some(function(e){return t[e]>=0})}const hi={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=oi(e,{elementContext:"reference"}),a=oi(e,{altBoundary:!0}),l=li(r,n),c=li(a,s,o),h=ci(l),d=ci(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},di={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=se.reduce(function(t,i){return t[i]=function(t,e,i){var n=we(t),s=[Xt,Vt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[Xt,Qt].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t},{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},ui={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=si({reference:e.rects.reference,element:e.rects.popper,placement:e.placement})},data:{}},fi={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=oi(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=we(e.placement),b=Be(e.placement),v=!b,y=je(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,S="y"===y?Vt:Xt,D="y"===y?Kt:Qt,$="y"===y?"height":"width",I=A[y],N=I+g[S],P=I-g[D],j=f?-T[$]/2:0,M=b===Gt?E[$]:T[$],F=b===Gt?-T[$]:-E[$],H=e.elements.arrow,W=f&&H?ke(H):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=B[S],R=B[D],q=Me(0,E[$],W[$]),V=v?E[$]/2-j-q-z-O.mainAxis:M-q-z-O.mainAxis,K=v?-E[$]/2+j+q+R+O.mainAxis:F+q+R+O.mainAxis,Q=e.elements.arrow&&Pe(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=I+K-Y,G=Me(f?Ee(N,I+V-Y-X):N,I,f?Ae(P,U):P);A[y]=G,k[y]=G-I}if(a){var J,Z="x"===y?Vt:Xt,tt="x"===y?Kt:Qt,et=A[w],it="y"===w?"height":"width",nt=et+g[Z],st=et-g[tt],ot=-1!==[Vt,Xt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=Me(t,e,i);return n>i?i:n}(at,et,lt):Me(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function pi(t,e,i){void 0===i&&(i=!1);var n,s,o=be(e),r=be(e)&&function(t){var e=t.getBoundingClientRect(),i=Te(e.width)/t.offsetWidth||1,n=Te(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=$e(e),l=xe(t,r,i),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==me(e)||Ze(a))&&(c=(n=e)!==ge(n)&&be(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:Ge(n)),be(e)?((h=xe(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=Je(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function mi(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach(function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}}),n.push(t)}return t.forEach(function(t){e.set(t.name,t)}),t.forEach(function(t){i.has(t.name)||s(t)}),n}var gi={placement:"bottom",modifiers:[],strategy:"absolute"};function _i(){for(var t=arguments.length,e=new Array(t),i=0;i<t;i++)e[i]=arguments[i];return!e.some(function(t){return!(t&&"function"==typeof t.getBoundingClientRect)})}function bi(t){void 0===t&&(t={});var e=t,i=e.defaultModifiers,n=void 0===i?[]:i,s=e.defaultOptions,o=void 0===s?gi:s;return function(t,e,i){void 0===i&&(i=o);var s,r,a={placement:"bottom",orderedModifiers:[],options:Object.assign({},gi,o),modifiersData:{},elements:{reference:t,popper:e},attributes:{},styles:{}},l=[],c=!1,h={state:a,setOptions:function(i){var s="function"==typeof i?i(a.options):i;d(),a.options=Object.assign({},o,a.options,s),a.scrollParents={reference:_e(t)?ei(t):t.contextElement?ei(t.contextElement):[],popper:ei(e)};var r,c,u=function(t){var e=mi(t);return pe.reduce(function(t,i){return t.concat(e.filter(function(t){return t.phase===i}))},[])}((r=[].concat(n,a.options.modifiers),c=r.reduce(function(t,e){var i=t[e.name];return t[e.name]=i?Object.assign({},i,e,{options:Object.assign({},i.options,e.options),data:Object.assign({},i.data,e.data)}):e,t},{}),Object.keys(c).map(function(t){return c[t]})));return a.orderedModifiers=u.filter(function(t){return t.enabled}),a.orderedModifiers.forEach(function(t){var e=t.name,i=t.options,n=void 0===i?{}:i,s=t.effect;if("function"==typeof s){var o=s({state:a,name:e,instance:h,options:n});l.push(o||function(){})}}),h.update()},forceUpdate:function(){if(!c){var t=a.elements,e=t.reference,i=t.popper;if(_i(e,i)){a.rects={reference:pi(e,Pe(i),"fixed"===a.options.strategy),popper:ke(i)},a.reset=!1,a.placement=a.options.placement,a.orderedModifiers.forEach(function(t){return a.modifiersData[t.name]=Object.assign({},t.data)});for(var n=0;n<a.orderedModifiers.length;n++)if(!0!==a.reset){var s=a.orderedModifiers[n],o=s.fn,r=s.options,l=void 0===r?{}:r,d=s.name;"function"==typeof o&&(a=o({state:a,options:l,name:d,instance:h})||a)}else a.reset=!1,n=-1}}},update:(s=function(){return new Promise(function(t){h.forceUpdate(),t(a)})},function(){return r||(r=new Promise(function(t){Promise.resolve().then(function(){r=void 0,t(s())})})),r}),destroy:function(){d(),c=!0}};if(!_i(t,e))return h;function d(){l.forEach(function(t){return t()}),l=[]}return h.setOptions(i).then(function(t){!c&&i.onFirstUpdate&&i.onFirstUpdate(t)}),h}}var vi=bi(),yi=bi({defaultModifiers:[Ke,ui,qe,ye]}),wi=bi({defaultModifiers:[Ke,ui,qe,ye,di,ai,fi,We,hi]});const Ai=Object.freeze(Object.defineProperty({__proto__:null,afterMain:he,afterRead:ae,afterWrite:fe,applyStyles:ye,arrow:We,auto:Yt,basePlacements:Ut,beforeMain:le,beforeRead:oe,beforeWrite:de,bottom:Kt,clippingParents:Zt,computeStyles:qe,createPopper:wi,createPopperBase:vi,createPopperLite:yi,detectOverflow:oi,end:Jt,eventListeners:Ke,flip:ai,hide:hi,left:Xt,main:ce,modifierPhases:pe,offset:di,placements:se,popper:ee,popperGenerator:bi,popperOffsets:ui,preventOverflow:fi,read:re,reference:ie,right:Qt,start:Gt,top:Vt,variationPlacements:ne,viewport:te,write:ue},Symbol.toStringTag,{value:"Module"})),Ei="dropdown",Ti=".bs.dropdown",Ci=".data-api",Oi="ArrowUp",xi="ArrowDown",ki=`hide${Ti}`,Li=`hidden${Ti}`,Si=`show${Ti}`,Di=`shown${Ti}`,$i=`click${Ti}${Ci}`,Ii=`keydown${Ti}${Ci}`,Ni=`keyup${Ti}${Ci}`,Pi="show",ji='[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)',Mi=`${ji}.${Pi}`,Fi=".dropdown-menu",Hi=m()?"top-end":"top-start",Wi=m()?"top-start":"top-end",Bi=m()?"bottom-end":"bottom-start",zi=m()?"bottom-start":"bottom-end",Ri=m()?"left-start":"right-start",qi=m()?"right-start":"left-start",Vi={autoClose:!0,boundary:"clippingParents",display:"dynamic",offset:[0,2],popperConfig:null,reference:"toggle"},Ki={autoClose:"(boolean|string)",boundary:"(string|element)",display:"string",offset:"(array|string|function)",popperConfig:"(null|object|function)",reference:"(string|element|object)"};class Qi extends B{constructor(t,e){super(t,e),this._popper=null,this._parent=this._element.parentNode,this._menu=R.next(this._element,Fi)[0]||R.prev(this._element,Fi)[0]||R.findOne(Fi,this._parent),this._inNavbar=this._detectNavbar()}static get Default(){return Vi}static get DefaultType(){return Ki}static get NAME(){return Ei}toggle(){return this._isShown()?this.hide():this.show()}show(){if(c(this._element)||this._isShown())return;const t={relatedTarget:this._element};if(!P.trigger(this._element,Si,t).defaultPrevented){if(this._createPopper(),"ontouchstart"in document.documentElement&&!this._parent.closest(".navbar-nav"))for(const t of[].concat(...document.body.children))P.on(t,"mouseover",d);this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Pi),this._element.classList.add(Pi),P.trigger(this._element,Di,t)}}hide(){if(c(this._element)||!this._isShown())return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){if(!P.trigger(this._element,ki,t).defaultPrevented){if("ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))P.off(t,"mouseover",d);this._popper&&this._popper.destroy(),this._menu.classList.remove(Pi),this._element.classList.remove(Pi),this._element.setAttribute("aria-expanded","false"),H.removeDataAttribute(this._menu,"popper"),P.trigger(this._element,Li,t)}}_getConfig(t){if("object"==typeof(t=super._getConfig(t)).reference&&!r(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ei.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(){if(void 0===Ai)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org/docs/v2/)");let t=this._element;"parent"===this._config.reference?t=this._parent:r(this._config.reference)?t=a(this._config.reference):"object"==typeof this._config.reference&&(t=this._config.reference);const e=this._getPopperConfig();this._popper=wi(t,this._menu,e)}_isShown(){return this._menu.classList.contains(Pi)}_getPlacement(){const t=this._parent;if(t.classList.contains("dropend"))return Ri;if(t.classList.contains("dropstart"))return qi;if(t.classList.contains("dropup-center"))return"top";if(t.classList.contains("dropdown-center"))return"bottom";const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?Wi:Hi:e?zi:Bi}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(H.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..._(this._config.popperConfig,[void 0,t])}}_selectMenuItem({key:t,target:e}){const i=R.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(t=>l(t));i.length&&v(i,e,t===xi,!i.includes(e)).focus()}static jQueryInterface(t){return this.each(function(){const e=Qi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=R.find(Mi);for(const i of e){const e=Qi.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Oi,xi].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=this.matches(ji)?this:R.prev(this,ji)[0]||R.next(this,ji)[0]||R.findOne(ji,t.delegateTarget.parentNode),o=Qi.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}P.on(document,Ii,ji,Qi.dataApiKeydownHandler),P.on(document,Ii,Fi,Qi.dataApiKeydownHandler),P.on(document,$i,Qi.clearMenus),P.on(document,Ni,Qi.clearMenus),P.on(document,$i,ji,function(t){t.preventDefault(),Qi.getOrCreateInstance(this).toggle()}),g(Qi);const Xi="backdrop",Yi="show",Ui=`mousedown.bs.${Xi}`,Gi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},Ji={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class Zi extends W{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return Gi}static get DefaultType(){return Ji}static get NAME(){return Xi}show(t){if(!this._config.isVisible)return void _(t);this._append();const e=this._getElement();this._config.isAnimated&&u(e),e.classList.add(Yi),this._emulateAnimation(()=>{_(t)})}hide(t){this._config.isVisible?(this._getElement().classList.remove(Yi),this._emulateAnimation(()=>{this.dispose(),_(t)})):_(t)}dispose(){this._isAppended&&(P.off(this._element,Ui),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=a(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),P.on(t,Ui,()=>{_(this._config.clickCallback)}),this._isAppended=!0}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const tn=".bs.focustrap",en=`focusin${tn}`,nn=`keydown.tab${tn}`,sn="backward",on={autofocus:!0,trapElement:null},rn={autofocus:"boolean",trapElement:"element"};class an extends W{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return on}static get DefaultType(){return rn}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),P.off(document,tn),P.on(document,en,t=>this._handleFocusin(t)),P.on(document,nn,t=>this._handleKeydown(t)),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,P.off(document,tn))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=R.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===sn?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?sn:"forward")}}const ln=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",cn=".sticky-top",hn="padding-right",dn="margin-right";class un{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,hn,e=>e+t),this._setElementAttributes(ln,hn,e=>e+t),this._setElementAttributes(cn,dn,e=>e-t)}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,hn),this._resetElementAttributes(ln,hn),this._resetElementAttributes(cn,dn)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)})}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&H.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,t=>{const i=H.getDataAttribute(t,e);null!==i?(H.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)})}_applyManipulationCallback(t,e){if(r(t))e(t);else for(const i of R.find(t,this._element))e(i)}}const fn=".bs.modal",pn=`hide${fn}`,mn=`hidePrevented${fn}`,gn=`hidden${fn}`,_n=`show${fn}`,bn=`shown${fn}`,vn=`resize${fn}`,yn=`click.dismiss${fn}`,wn=`mousedown.dismiss${fn}`,An=`keydown.dismiss${fn}`,En=`click${fn}.data-api`,Tn="modal-open",Cn="show",On="modal-static",xn={backdrop:!0,focus:!0,keyboard:!0},kn={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Ln extends B{constructor(t,e){super(t,e),this._dialog=R.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new un,this._addEventListeners()}static get Default(){return xn}static get DefaultType(){return kn}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||P.trigger(this._element,_n,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Tn),this._adjustDialog(),this._backdrop.show(()=>this._showElement(t)))}hide(){this._isShown&&!this._isTransitioning&&(P.trigger(this._element,pn).defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(Cn),this._queueCallback(()=>this._hideModal(),this._element,this._isAnimated())))}dispose(){P.off(window,fn),P.off(this._dialog,fn),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new Zi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new an({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=R.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),u(this._element),this._element.classList.add(Cn),this._queueCallback(()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,P.trigger(this._element,bn,{relatedTarget:t})},this._dialog,this._isAnimated())}_addEventListeners(){P.on(this._element,An,t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():this._triggerBackdropTransition())}),P.on(window,vn,()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()}),P.on(this._element,wn,t=>{P.one(this._element,yn,e=>{this._element===t.target&&this._element===e.target&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())})})}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide(()=>{document.body.classList.remove(Tn),this._resetAdjustments(),this._scrollBar.reset(),P.trigger(this._element,gn)})}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(P.trigger(this._element,mn).defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(On)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(On),this._queueCallback(()=>{this._element.classList.remove(On),this._queueCallback(()=>{this._element.style.overflowY=e},this._dialog)},this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=m()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=m()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each(function(){const i=Ln.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}})}}P.on(document,En,'[data-bs-toggle="modal"]',function(t){const e=R.getElementFromSelector(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),P.one(e,_n,t=>{t.defaultPrevented||P.one(e,gn,()=>{l(this)&&this.focus()})});const i=R.findOne(".modal.show");i&&Ln.getInstance(i).hide(),Ln.getOrCreateInstance(e).toggle(this)}),q(Ln),g(Ln);const Sn=".bs.offcanvas",Dn=".data-api",$n=`load${Sn}${Dn}`,In="show",Nn="showing",Pn="hiding",jn=".offcanvas.show",Mn=`show${Sn}`,Fn=`shown${Sn}`,Hn=`hide${Sn}`,Wn=`hidePrevented${Sn}`,Bn=`hidden${Sn}`,zn=`resize${Sn}`,Rn=`click${Sn}${Dn}`,qn=`keydown.dismiss${Sn}`,Vn={backdrop:!0,keyboard:!0,scroll:!1},Kn={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class Qn extends B{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return Vn}static get DefaultType(){return Kn}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||P.trigger(this._element,Mn,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new un).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Nn),this._queueCallback(()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(In),this._element.classList.remove(Nn),P.trigger(this._element,Fn,{relatedTarget:t})},this._element,!0))}hide(){this._isShown&&(P.trigger(this._element,Hn).defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(Pn),this._backdrop.hide(),this._queueCallback(()=>{this._element.classList.remove(In,Pn),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new un).reset(),P.trigger(this._element,Bn)},this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new Zi({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():P.trigger(this._element,Wn)}:null})}_initializeFocusTrap(){return new an({trapElement:this._element})}_addEventListeners(){P.on(this._element,qn,t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():P.trigger(this._element,Wn))})}static jQueryInterface(t){return this.each(function(){const e=Qn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}})}}P.on(document,Rn,'[data-bs-toggle="offcanvas"]',function(t){const e=R.getElementFromSelector(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;P.one(e,Bn,()=>{l(this)&&this.focus()});const i=R.findOne(jn);i&&i!==e&&Qn.getInstance(i).hide(),Qn.getOrCreateInstance(e).toggle(this)}),P.on(window,$n,()=>{for(const t of R.find(jn))Qn.getOrCreateInstance(t).show()}),P.on(window,zn,()=>{for(const t of R.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&Qn.getOrCreateInstance(t).hide()}),q(Qn),g(Qn);const Xn={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],dd:[],div:[],dl:[],dt:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Yn=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Un=/^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i,Gn=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Yn.has(i)||Boolean(Un.test(t.nodeValue)):e.filter(t=>t instanceof RegExp).some(t=>t.test(i))},Jn={allowList:Xn,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"<div></div>"},Zn={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},ts={entry:"(string|element|function|null)",selector:"(string|element)"};class es extends W{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Jn}static get DefaultType(){return Zn}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map(t=>this._resolvePossibleFunction(t)).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},ts)}_setContent(t,e,i){const n=R.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?r(e)?this._putElementInTemplate(a(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)Gn(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return _(t,[void 0,this])}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const is=new Set(["sanitize","allowList","sanitizeFn"]),ns="fade",ss="show",os=".tooltip-inner",rs=".modal",as="hide.bs.modal",ls="hover",cs="focus",hs="click",ds={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},us={allowList:Xn,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,6],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',title:"",trigger:"hover focus"},fs={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class ps extends B{constructor(t,e){if(void 0===Ai)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org/docs/v2/)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=null,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners(),this._config.selector||this._fixTitle()}static get Default(){return us}static get DefaultType(){return fs}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(){this._isEnabled&&(this._isShown()?this._leave():this._enter())}dispose(){clearTimeout(this._timeout),P.off(this._element.closest(rs),as,this._hideModalHandler),this._element.getAttribute("data-bs-original-title")&&this._element.setAttribute("title",this._element.getAttribute("data-bs-original-title")),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=P.trigger(this._element,this.constructor.eventName("show")),e=(h(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this._disposePopper();const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),P.trigger(this._element,this.constructor.eventName("inserted"))),this._popper=this._createPopper(i),i.classList.add(ss),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))P.on(t,"mouseover",d);this._queueCallback(()=>{P.trigger(this._element,this.constructor.eventName("shown")),!1===this._isHovered&&this._leave(),this._isHovered=!1},this.tip,this._isAnimated())}hide(){if(this._isShown()&&!P.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented){if(this._getTipElement().classList.remove(ss),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))P.off(t,"mouseover",d);this._activeTrigger[hs]=!1,this._activeTrigger[cs]=!1,this._activeTrigger[ls]=!1,this._isHovered=null,this._queueCallback(()=>{this._isWithActiveTrigger()||(this._isHovered||this._disposePopper(),this._element.removeAttribute("aria-describedby"),P.trigger(this._element,this.constructor.eventName("hidden")))},this.tip,this._isAnimated())}}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(ns,ss),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(ns),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new es({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{[os]:this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._element.getAttribute("data-bs-original-title")}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(ns)}_isShown(){return this.tip&&this.tip.classList.contains(ss)}_createPopper(t){const e=_(this._config.placement,[this,t,this._element]),i=ds[e.toUpperCase()];return wi(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map(t=>Number.parseInt(t,10)):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return _(t,[this._element,this._element])}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,..._(this._config.popperConfig,[void 0,e])}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)P.on(this._element,this.constructor.eventName("click"),this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger[hs]=!(e._isShown()&&e._activeTrigger[hs]),e.toggle()});else if("manual"!==e){const t=e===ls?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===ls?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");P.on(this._element,t,this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?cs:ls]=!0,e._enter()}),P.on(this._element,i,this._config.selector,t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?cs:ls]=e._element.contains(t.relatedTarget),e._leave()})}this._hideModalHandler=()=>{this._element&&this.hide()},P.on(this._element.closest(rs),as,this._hideModalHandler)}_fixTitle(){const t=this._element.getAttribute("title");t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.setAttribute("data-bs-original-title",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout(()=>{this._isHovered&&this.show()},this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout(()=>{this._isHovered||this.hide()},this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=H.getDataAttributes(this._element);for(const t of Object.keys(e))is.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:a(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const[e,i]of Object.entries(this._config))this.constructor.Default[e]!==i&&(t[e]=i);return t.selector=!1,t.trigger="manual",t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null),this.tip&&(this.tip.remove(),this.tip=null)}static jQueryInterface(t){return this.each(function(){const e=ps.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}}g(ps);const ms=".popover-header",gs=".popover-body",_s={...ps.Default,content:"",offset:[0,8],placement:"right",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>',trigger:"click"},bs={...ps.DefaultType,content:"(null|string|element|function)"};class vs extends ps{static get Default(){return _s}static get DefaultType(){return bs}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{[ms]:this._getTitle(),[gs]:this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each(function(){const e=vs.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}})}}g(vs);const ys=".bs.scrollspy",ws=`activate${ys}`,As=`click${ys}`,Es=`load${ys}.data-api`,Ts="active",Cs="[href]",Os=".nav-link",xs=`${Os}, .nav-item > ${Os}, .list-group-item`,ks={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null,threshold:[.1,.5,1]},Ls={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element",threshold:"array"};class Ss extends B{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return ks}static get DefaultType(){return Ls}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=a(t.target)||document.body,t.rootMargin=t.offset?`${t.offset}px 0px -30%`:t.rootMargin,"string"==typeof t.threshold&&(t.threshold=t.threshold.split(",").map(t=>Number.parseFloat(t))),t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(P.off(this._config.target,As),P.on(this._config.target,As,Cs,t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}}))}_getNewObserver(){const t={root:this._rootElement,threshold:this._config.threshold,rootMargin:this._config.rootMargin};return new IntersectionObserver(t=>this._observerCallback(t),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=R.find(Cs,this._config.target);for(const e of t){if(!e.hash||c(e))continue;const t=R.findOne(decodeURI(e.hash),this._element);l(t)&&(this._targetLinks.set(decodeURI(e.hash),e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(Ts),this._activateParents(t),P.trigger(this._element,ws,{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))R.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(Ts);else for(const e of R.parents(t,".nav, .list-group"))for(const t of R.prev(e,xs))t.classList.add(Ts)}_clearActiveClass(t){t.classList.remove(Ts);const e=R.find(`${Cs}.${Ts}`,t);for(const t of e)t.classList.remove(Ts)}static jQueryInterface(t){return this.each(function(){const e=Ss.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}})}}P.on(window,Es,()=>{for(const t of R.find('[data-bs-spy="scroll"]'))Ss.getOrCreateInstance(t)}),g(Ss);const Ds=".bs.tab",$s=`hide${Ds}`,Is=`hidden${Ds}`,Ns=`show${Ds}`,Ps=`shown${Ds}`,js=`click${Ds}`,Ms=`keydown${Ds}`,Fs=`load${Ds}`,Hs="ArrowLeft",Ws="ArrowRight",Bs="ArrowUp",zs="ArrowDown",Rs="Home",qs="End",Vs="active",Ks="fade",Qs="show",Xs=".dropdown-toggle",Ys=`:not(${Xs})`,Us='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Gs=`.nav-link${Ys}, .list-group-item${Ys}, [role="tab"]${Ys}, ${Us}`,Js=`.${Vs}[data-bs-toggle="tab"], .${Vs}[data-bs-toggle="pill"], .${Vs}[data-bs-toggle="list"]`;class Zs extends B{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),P.on(this._element,Ms,t=>this._keydown(t)))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?P.trigger(e,$s,{relatedTarget:t}):null;P.trigger(t,Ns,{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(Vs),this._activate(R.getElementFromSelector(t)),this._queueCallback(()=>{"tab"===t.getAttribute("role")?(t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),P.trigger(t,Ps,{relatedTarget:e})):t.classList.add(Qs)},t,t.classList.contains(Ks)))}_deactivate(t,e){t&&(t.classList.remove(Vs),t.blur(),this._deactivate(R.getElementFromSelector(t)),this._queueCallback(()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),P.trigger(t,Is,{relatedTarget:e})):t.classList.remove(Qs)},t,t.classList.contains(Ks)))}_keydown(t){if(![Hs,Ws,Bs,zs,Rs,qs].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=this._getChildren().filter(t=>!c(t));let i;if([Rs,qs].includes(t.key))i=e[t.key===Rs?0:e.length-1];else{const n=[Ws,zs].includes(t.key);i=v(e,t.target,n,!0)}i&&(i.focus({preventScroll:!0}),Zs.getOrCreateInstance(i).show())}_getChildren(){return R.find(Gs,this._parent)}_getActiveElem(){return this._getChildren().find(t=>this._elemIsActive(t))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=R.getElementFromSelector(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=R.findOne(t,i);s&&s.classList.toggle(n,e)};n(Xs,Vs),n(".dropdown-menu",Qs),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(Vs)}_getInnerElement(t){return t.matches(Gs)?t:R.findOne(Gs,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each(function(){const e=Zs.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}})}}P.on(document,js,Us,function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||Zs.getOrCreateInstance(this).show()}),P.on(window,Fs,()=>{for(const t of R.find(Js))Zs.getOrCreateInstance(t)}),g(Zs);const to=".bs.toast",eo=`mouseover${to}`,io=`mouseout${to}`,no=`focusin${to}`,so=`focusout${to}`,oo=`hide${to}`,ro=`hidden${to}`,ao=`show${to}`,lo=`shown${to}`,co="hide",ho="show",uo="showing",fo={animation:"boolean",autohide:"boolean",delay:"number"},po={animation:!0,autohide:!0,delay:5e3};class mo extends B{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return po}static get DefaultType(){return fo}static get NAME(){return"toast"}show(){P.trigger(this._element,ao).defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(co),u(this._element),this._element.classList.add(ho,uo),this._queueCallback(()=>{this._element.classList.remove(uo),P.trigger(this._element,lo),this._maybeScheduleHide()},this._element,this._config.animation))}hide(){this.isShown()&&(P.trigger(this._element,oo).defaultPrevented||(this._element.classList.add(uo),this._queueCallback(()=>{this._element.classList.add(co),this._element.classList.remove(uo,ho),P.trigger(this._element,ro)},this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(ho),super.dispose()}isShown(){return this._element.classList.contains(ho)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout(()=>{this.hide()},this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){P.on(this._element,eo,t=>this._onInteraction(t,!0)),P.on(this._element,io,t=>this._onInteraction(t,!1)),P.on(this._element,no,t=>this._onInteraction(t,!0)),P.on(this._element,so,t=>this._onInteraction(t,!1))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each(function(){const e=mo.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}})}}return q(mo),g(mo),{Alert:X,Button:U,Carousel:St,Collapse:qt,Dropdown:Qi,Modal:Ln,Offcanvas:Qn,Popover:vs,ScrollSpy:Ss,Tab:Zs,Toast:mo,Tooltip:ps}}); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js.map b/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js.map new file mode 100644 index 0000000..3e678d4 --- /dev/null +++ b/extensions/pagetop-bootsier/static/js/bootstrap.bundle.min.js.map @@ -0,0 +1 @@ +{"version":3,"names":["elementMap","Map","Data","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","toType","object","Object","prototype","toString","call","toLowerCase","triggerTransitionEnd","dispatchEvent","Event","isElement","jquery","nodeType","getElement","length","document","querySelector","isVisible","getClientRects","elementIsVisible","getComputedStyle","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","isRTL","dir","defineJQueryPlugin","plugin","callback","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","readyState","addEventListener","push","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","emulatedDuration","transitionDuration","transitionDelay","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","getTransitionDurationFromElement","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","Math","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","findHandler","events","callable","delegationSelector","values","find","event","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","oneOff","wrapFunction","relatedTarget","delegateTarget","this","handlers","previousFunction","domElements","querySelectorAll","domElement","hydrateObj","EventHandler","off","type","apply","bootstrapDelegationHandler","bootstrapHandler","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","JSON","parse","decodeURIComponent","normalizeDataKey","chr","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","RegExp","test","TypeError","toUpperCase","BaseComponent","super","_element","_config","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","VERSION","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","Alert","close","_destroyElement","each","data","undefined","SELECTOR_DATA_TOGGLE","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","_eventIsPointerPenTouch","clientX","touches","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","DATA_API_KEY","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","EVENT_CLICK_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_ACTIVE","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","KEY_TO_DIRECTION","ARROW_LEFT_KEY$1","ARROW_RIGHT_KEY$1","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouchEventListeners","img","swipeConfig","_directionToOrder","endCallBack","clearTimeout","_setActiveIndicatorElement","activeIndicator","newActiveIndicator","elementInterval","parseInt","isNext","nextElement","nextElementIndex","triggerEvent","_orderToDirection","isCycling","directionalClassName","orderClassName","completeCallBack","_isAnimated","clearInterval","carousel","slideIndex","carousels","EVENT_SHOW","EVENT_SHOWN","EVENT_HIDE","EVENT_HIDDEN","CLASS_NAME_SHOW","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_DEEPER_CHILDREN","parent","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElement","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activeChildren","_getFirstLevelChildren","activeInstance","dimension","_getDimension","style","scrollSize","complete","getBoundingClientRect","selected","triggerArray","isOpen","top","bottom","right","left","auto","basePlacements","start","end","clippingParents","viewport","popper","reference","variationPlacements","reduce","acc","placement","placements","beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite","modifierPhases","getNodeName","nodeName","getWindow","node","ownerDocument","defaultView","isHTMLElement","HTMLElement","isShadowRoot","applyStyles$1","enabled","phase","_ref","state","elements","forEach","styles","assign","effect","_ref2","initialStyles","position","options","strategy","margin","arrow","hasOwnProperty","attribute","requires","getBasePlacement","round","getUAString","uaData","userAgentData","brands","isArray","item","brand","version","userAgent","isLayoutViewport","includeScale","isFixedStrategy","clientRect","scaleX","scaleY","offsetWidth","width","height","visualViewport","addVisualOffsets","x","offsetLeft","y","offsetTop","getLayoutRect","rootNode","isSameNode","host","isTableElement","getDocumentElement","getParentNode","assignedSlot","getTrueOffsetParent","offsetParent","getOffsetParent","isFirefox","currentNode","css","transform","perspective","contain","willChange","getContainingBlock","getMainAxisFromPlacement","within","mathMax","mathMin","mergePaddingObject","paddingObject","expandToHashMap","hashMap","arrow$1","_state$modifiersData$","arrowElement","popperOffsets","modifiersData","basePlacement","axis","len","padding","rects","toPaddingObject","arrowRect","minProp","maxProp","endDiff","startDiff","arrowOffsetParent","clientSize","clientHeight","clientWidth","centerToReference","center","offset","axisProp","centerOffset","_options$element","requiresIfExists","getVariation","unsetSides","mapToStyles","_Object$assign2","popperRect","variation","offsets","gpuAcceleration","adaptive","roundOffsets","isFixed","_offsets$x","_offsets$y","_ref3","hasX","hasY","sideX","sideY","win","heightProp","widthProp","_Object$assign","commonStyles","_ref4","dpr","devicePixelRatio","roundOffsetsByDPR","computeStyles$1","_ref5","_options$gpuAccelerat","_options$adaptive","_options$roundOffsets","passive","eventListeners","_options$scroll","scroll","_options$resize","resize","scrollParents","scrollParent","update","hash","getOppositePlacement","matched","getOppositeVariationPlacement","getWindowScroll","scrollLeft","pageXOffset","scrollTop","pageYOffset","getWindowScrollBarX","isScrollParent","_getComputedStyle","overflow","overflowX","overflowY","getScrollParent","listScrollParents","_element$ownerDocumen","isBody","updatedList","rectToClientRect","rect","getClientRectFromMixedType","clippingParent","html","layoutViewport","getViewportRect","clientTop","clientLeft","getInnerBoundingClientRect","winScroll","scrollWidth","scrollHeight","getDocumentRect","computeOffsets","commonX","commonY","mainAxis","detectOverflow","_options","_options$placement","_options$strategy","_options$boundary","boundary","_options$rootBoundary","rootBoundary","_options$elementConte","elementContext","_options$altBoundary","altBoundary","_options$padding","altContext","clippingClientRect","mainClippingParents","clipperElement","getClippingParents","firstClippingParent","clippingRect","accRect","getClippingRect","contextElement","referenceClientRect","popperClientRect","elementClientRect","overflowOffsets","offsetData","multiply","computeAutoPlacement","flipVariations","_options$allowedAutoP","allowedAutoPlacements","allPlacements","allowedPlacements","overflows","sort","a","b","flip$1","_skip","_options$mainAxis","checkMainAxis","_options$altAxis","altAxis","checkAltAxis","specifiedFallbackPlacements","fallbackPlacements","_options$flipVariatio","preferredPlacement","oppositePlacement","getExpandedFallbackPlacements","referenceRect","checksMap","makeFallbackChecks","firstFittingPlacement","i","_basePlacement","isStartVariation","isVertical","mainVariationSide","altVariationSide","checks","every","check","_loop","_i","fittingPlacement","reset","getSideOffsets","preventedOffsets","isAnySideFullyClipped","some","side","hide$1","preventOverflow","referenceOverflow","popperAltOverflow","referenceClippingOffsets","popperEscapeOffsets","isReferenceHidden","hasPopperEscaped","offset$1","_options$offset","invertDistance","skidding","distance","distanceAndSkiddingToXY","_data$state$placement","popperOffsets$1","preventOverflow$1","_options$tether","tether","_options$tetherOffset","tetherOffset","isBasePlacement","tetherOffsetValue","normalizedTetherOffsetValue","offsetModifierState","_offsetModifierState$","mainSide","altSide","additive","minLen","maxLen","arrowPaddingObject","arrowPaddingMin","arrowPaddingMax","arrowLen","minOffset","maxOffset","clientOffset","offsetModifierValue","tetherMax","preventedOffset","_offsetModifierState$2","_mainSide","_altSide","_offset","_len","_min","_max","isOriginSide","_offsetModifierValue","_tetherMin","_tetherMax","_preventedOffset","v","withinMaxClamp","getCompositeRect","elementOrVirtualElement","isOffsetParentAnElement","offsetParentIsScaled","isElementScaled","modifiers","visited","result","modifier","dep","depModifier","DEFAULT_OPTIONS","areValidElements","arguments","_key","popperGenerator","generatorOptions","_generatorOptions","_generatorOptions$def","defaultModifiers","_generatorOptions$def2","defaultOptions","pending","orderedModifiers","effectCleanupFns","isDestroyed","setOptions","setOptionsAction","cleanupModifierEffects","merged","orderModifiers","current","existing","m","_ref$options","cleanupFn","forceUpdate","_state$elements","_state$orderedModifie","_state$orderedModifie2","Promise","resolve","then","destroy","onFirstUpdate","createPopper","computeStyles","applyStyles","flip","ARROW_UP_KEY","ARROW_DOWN_KEY","EVENT_KEYDOWN_DATA_API","EVENT_KEYUP_DATA_API","SELECTOR_DATA_TOGGLE_SHOWN","SELECTOR_MENU","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","autoClose","display","popperConfig","Dropdown","_popper","_parent","_menu","_inNavbar","_detectNavbar","_createPopper","focus","_completeHide","Popper","referenceElement","_getPopperConfig","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","_selectMenuItem","clearMenus","openToggles","context","composedPath","isMenuTarget","dataApiKeydownHandler","isInput","isEscapeEvent","isUpOrDownEvent","getToggleButton","stopPropagation","EVENT_MOUSEDOWN","className","clickCallback","rootElement","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_NAV_BACKWARD","autofocus","trapElement","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","shiftKey","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","getWidth","documentWidth","innerWidth","_disableOverFlow","_setElementAttributes","calculatedValue","_resetElementAttributes","isOverflowing","_saveInitialAttribute","styleProperty","scrollbarWidth","_applyManipulationCallback","setProperty","actualValue","removeProperty","callBack","EVENT_HIDE_PREVENTED","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_MOUSEDOWN_DISMISS","EVENT_KEYDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_scrollBar","_adjustDialog","_showElement","_hideModal","handleUpdate","modalBody","transitionComplete","_triggerBackdropTransition","event2","_resetAdjustments","isModalOverflowing","initialOverflowY","isBodyOverflowing","paddingLeft","paddingRight","showEvent","alreadyOpen","CLASS_NAME_SHOWING","CLASS_NAME_HIDING","OPEN_SELECTOR","Offcanvas","blur","completeCallback","DefaultAllowlist","area","br","col","code","dd","div","dl","dt","em","hr","h1","h2","h3","h4","h5","h6","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","uriAttributes","SAFE_URL_PATTERN","allowedAttribute","allowedAttributeList","attributeName","nodeValue","attributeRegex","regex","allowList","content","extraClass","sanitize","sanitizeFn","template","DefaultContentType","entry","TemplateFactory","getContent","_resolvePossibleFunction","hasContent","changeContent","_checkContent","toHtml","templateWrapper","innerHTML","_maybeSanitize","text","_setContent","arg","templateElement","_putElementInTemplate","textContent","unsafeHtml","sanitizeFunction","createdDocument","DOMParser","parseFromString","elementName","attributeList","allowedAttributes","sanitizeHtml","DISALLOWED_ATTRIBUTES","CLASS_NAME_FADE","SELECTOR_TOOLTIP_INNER","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","TRIGGER_CLICK","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","animation","container","customClass","delay","title","Tooltip","_isEnabled","_timeout","_isHovered","_activeTrigger","_templateFactory","_newContent","tip","_setListeners","_fixTitle","enable","disable","toggleEnabled","_leave","_enter","_hideModalHandler","_disposePopper","_isWithContent","isInTheDom","_getTipElement","_isWithActiveTrigger","_getTitle","_createTipElement","_getContentForTemplate","_getTemplateFactory","tipId","prefix","floor","random","getElementById","getUID","setContent","_initializeOnDelegatedTarget","_getDelegateConfig","attachment","triggers","eventIn","eventOut","_setTimeout","timeout","dataAttributes","dataAttribute","SELECTOR_TITLE","SELECTOR_CONTENT","Popover","_getContent","EVENT_ACTIVATE","EVENT_CLICK","SELECTOR_TARGET_LINKS","SELECTOR_NAV_LINKS","SELECTOR_LINK_ITEMS","rootMargin","smoothScroll","threshold","ScrollSpy","_targetLinks","_observableSections","_rootElement","_activeTarget","_observer","_previousScrollData","visibleEntryTop","parentScrollTop","refresh","_initializeTargetsAndObservables","_maybeEnableSmoothScroll","disconnect","_getNewObserver","section","observe","observableSection","scrollTo","behavior","IntersectionObserver","_observerCallback","targetElement","_process","userScrollsDown","isIntersecting","_clearActiveClass","entryIsLowerThanPrevious","targetLinks","anchor","decodeURI","_activateParents","listGroup","activeNodes","spy","HOME_KEY","END_KEY","SELECTOR_DROPDOWN_TOGGLE","NOT_SELECTOR_DROPDOWN_TOGGLE","SELECTOR_INNER_ELEM","SELECTOR_DATA_TOGGLE_ACTIVE","Tab","_setInitialAttributes","_getChildren","innerElem","_elemIsActive","active","_getActiveElem","hideEvent","_deactivate","_activate","relatedElem","_toggleDropDown","nextActiveElement","preventScroll","_setAttributeIfNotExists","_setInitialAttributesOnChild","_getInnerElement","isActive","outerElem","_getOuterElement","_setInitialAttributesOnTargetPanel","open","EVENT_MOUSEOVER","EVENT_MOUSEOUT","EVENT_FOCUSOUT","CLASS_NAME_HIDE","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","isShown","_onInteraction","isInteracting"],"sources":["../../js/src/dom/data.js","../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/manipulator.js","../../js/src/util/config.js","../../js/src/base-component.js","../../js/src/dom/selector-engine.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/util/swipe.js","../../js/src/carousel.js","../../js/src/collapse.js","../../node_modules/@popperjs/core/lib/enums.js","../../node_modules/@popperjs/core/lib/dom-utils/getNodeName.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindow.js","../../node_modules/@popperjs/core/lib/dom-utils/instanceOf.js","../../node_modules/@popperjs/core/lib/modifiers/applyStyles.js","../../node_modules/@popperjs/core/lib/utils/getBasePlacement.js","../../node_modules/@popperjs/core/lib/utils/math.js","../../node_modules/@popperjs/core/lib/utils/userAgent.js","../../node_modules/@popperjs/core/lib/dom-utils/isLayoutViewport.js","../../node_modules/@popperjs/core/lib/dom-utils/getBoundingClientRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getLayoutRect.js","../../node_modules/@popperjs/core/lib/dom-utils/contains.js","../../node_modules/@popperjs/core/lib/dom-utils/getComputedStyle.js","../../node_modules/@popperjs/core/lib/dom-utils/isTableElement.js","../../node_modules/@popperjs/core/lib/dom-utils/getDocumentElement.js","../../node_modules/@popperjs/core/lib/dom-utils/getParentNode.js","../../node_modules/@popperjs/core/lib/dom-utils/getOffsetParent.js","../../node_modules/@popperjs/core/lib/utils/getMainAxisFromPlacement.js","../../node_modules/@popperjs/core/lib/utils/within.js","../../node_modules/@popperjs/core/lib/utils/mergePaddingObject.js","../../node_modules/@popperjs/core/lib/utils/getFreshSideObject.js","../../node_modules/@popperjs/core/lib/utils/expandToHashMap.js","../../node_modules/@popperjs/core/lib/modifiers/arrow.js","../../node_modules/@popperjs/core/lib/utils/getVariation.js","../../node_modules/@popperjs/core/lib/modifiers/computeStyles.js","../../node_modules/@popperjs/core/lib/modifiers/eventListeners.js","../../node_modules/@popperjs/core/lib/utils/getOppositePlacement.js","../../node_modules/@popperjs/core/lib/utils/getOppositeVariationPlacement.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindowScroll.js","../../node_modules/@popperjs/core/lib/dom-utils/getWindowScrollBarX.js","../../node_modules/@popperjs/core/lib/dom-utils/isScrollParent.js","../../node_modules/@popperjs/core/lib/dom-utils/getScrollParent.js","../../node_modules/@popperjs/core/lib/dom-utils/listScrollParents.js","../../node_modules/@popperjs/core/lib/utils/rectToClientRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getClippingRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getViewportRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getDocumentRect.js","../../node_modules/@popperjs/core/lib/utils/computeOffsets.js","../../node_modules/@popperjs/core/lib/utils/detectOverflow.js","../../node_modules/@popperjs/core/lib/utils/computeAutoPlacement.js","../../node_modules/@popperjs/core/lib/modifiers/flip.js","../../node_modules/@popperjs/core/lib/modifiers/hide.js","../../node_modules/@popperjs/core/lib/modifiers/offset.js","../../node_modules/@popperjs/core/lib/modifiers/popperOffsets.js","../../node_modules/@popperjs/core/lib/modifiers/preventOverflow.js","../../node_modules/@popperjs/core/lib/utils/getAltAxis.js","../../node_modules/@popperjs/core/lib/dom-utils/getCompositeRect.js","../../node_modules/@popperjs/core/lib/dom-utils/getNodeScroll.js","../../node_modules/@popperjs/core/lib/dom-utils/getHTMLElementScroll.js","../../node_modules/@popperjs/core/lib/utils/orderModifiers.js","../../node_modules/@popperjs/core/lib/createPopper.js","../../node_modules/@popperjs/core/lib/utils/debounce.js","../../node_modules/@popperjs/core/lib/utils/mergeByName.js","../../node_modules/@popperjs/core/lib/popper-lite.js","../../node_modules/@popperjs/core/lib/popper.js","../../js/src/dropdown.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/util/scrollbar.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/util/template-factory.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1_000_000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\n }\n\n return selector\n}\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`\n }\n\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false\n }\n\n if (typeof object.jquery !== 'undefined') {\n object = object[0]\n }\n\n return typeof object.nodeType !== 'undefined'\n}\n\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object\n }\n\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object))\n }\n\n return null\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])')\n\n if (!closedDetails) {\n return elementIsVisible\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary')\n if (summary && summary.parentNode !== closedDetails) {\n return false\n }\n\n if (summary === null) {\n return false\n }\n }\n\n return elementIsVisible\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.harrytheo.com/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight // eslint-disable-line no-unused-expressions\n}\n\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback()\n }\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback.call(...args) : defaultValue\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\n }\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n defineJQueryPlugin,\n execute,\n executeAfterTransition,\n findShadowRoot,\n getElement,\n getjQuery,\n getNextActiveElement,\n getTransitionDurationFromElement,\n getUID,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n onDOMContentLoaded,\n parseSelector,\n reflow,\n triggerTransitionEnd,\n toType\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index.js'\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getElementEvents(element) {\n const uid = makeEventUid(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, { delegateTarget: element })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events)\n .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string'\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\n let typeEvent = getTypeEvent(originalTypeEvent)\n\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent\n }\n\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\n\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff\n\n return\n }\n\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = isDelegated ?\n bootstrapDelegationHandler(element, handler, callable) :\n bootstrapHandler(element, callable)\n\n fn.delegationSelector = isDelegated ? handler : null\n fn.callable = callable\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, isDelegated)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false)\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getElementEvents(element)\n const storeElementEvent = events[typeEvent] || {}\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n\n let jQueryEvent = null\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport { isElement, toType } from './index.js'\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {}\n }\n\n static get DefaultType() {\n return {}\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n return config\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n }\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property]\n const valueType = isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n }\n }\n}\n\nexport default Config\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.8'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n // Private\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`\n }\n\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\n }\n\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null\n}\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n let ancestor = element.parentNode.closest(selector)\n\n while (ancestor) {\n parents.push(ancestor)\n ancestor = ancestor.parentNode.closest(selector)\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n },\n\n getSelectorFromElement(element) {\n const selector = getSelector(element)\n\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null\n }\n\n return null\n },\n\n getElementFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.findOne(selector) : null\n },\n\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.find(selector) : []\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'swipe'\nconst EVENT_KEY = '.bs.swipe'\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n}\n\nconst DefaultType = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n}\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super()\n this._element = element\n\n if (!element || !Swipe.isSupported()) {\n return\n }\n\n this._config = this._getConfig(config)\n this._deltaX = 0\n this._supportPointerEvents = Boolean(window.PointerEvent)\n this._initEvents()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY)\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX\n\n return\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX\n }\n\n this._handleSwipe()\n execute(this._config.endCallback)\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this._deltaX\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX)\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltaX / this._deltaX\n\n this._deltaX = 0\n\n if (!direction) {\n return\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n }\n}\n\nexport default Swipe\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getNextActiveElement,\n isRTL,\n isVisible,\n reflow,\n triggerTransitionEnd\n} from './util/index.js'\nimport Swipe from './util/swipe.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)', // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._interval = null\n this._activeElement = null\n this._isSliding = false\n this.touchTimeout = null\n this._swipeHelper = null\n\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._addEventListeners()\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element)\n }\n\n this._clearInterval()\n }\n\n cycle() {\n this._clearInterval()\n this._updateInterval()\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\n return\n }\n\n this.cycle()\n }\n\n to(index) {\n const items = this._getItems()\n if (index > items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n const activeIndex = this._getItemIndex(this._getActive())\n if (activeIndex === index) {\n return\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\n\n this._slide(order, items[index])\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose()\n }\n\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval\n return config\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\n EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n }\n\n this._swipeHelper = new Swipe(this._element, swipeConfig)\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(this._directionToOrder(direction))\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element)\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement)\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\n newActiveIndicator.setAttribute('aria-current', 'true')\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive()\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n this._config.interval = elementInterval || this._config.defaultInterval\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return\n }\n\n const activeElement = this._getActive()\n const isNext = order === ORDER_NEXT\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\n\n if (nextElement === activeElement) {\n return\n }\n\n const nextElementIndex = this._getItemIndex(nextElement)\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n })\n }\n\n const slideEvent = triggerEvent(EVENT_SLIDE)\n\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return\n }\n\n const isCycling = Boolean(this._interval)\n this.pause()\n\n this._isSliding = true\n\n this._setActiveIndicatorElement(nextElementIndex)\n this._activeElement = nextElement\n\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n triggerEvent(EVENT_SLID)\n }\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated())\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE)\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element)\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config)\n\n if (typeof config === 'number') {\n data.to(config)\n return\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n event.preventDefault()\n\n const carousel = Carousel.getOrCreateInstance(target)\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n carousel.to(slideIndex)\n carousel._maybeEnableCycle()\n return\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next()\n carousel._maybeEnableCycle()\n return\n }\n\n carousel.prev()\n carousel._maybeEnableCycle()\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getElement,\n reflow\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\nconst Default = {\n parent: null,\n toggle: true\n}\n\nconst DefaultType = {\n parent: '(null|element)',\n toggle: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isTransitioning = false\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElement => foundElement === this._element)\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let activeChildren = []\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\n .filter(element => element !== this._element)\n .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide()\n }\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger)\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n // Private\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\n\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\n element.setAttribute('aria-expanded', isOpen)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","export var top = 'top';\nexport var bottom = 'bottom';\nexport var right = 'right';\nexport var left = 'left';\nexport var auto = 'auto';\nexport var basePlacements = [top, bottom, right, left];\nexport var start = 'start';\nexport var end = 'end';\nexport var clippingParents = 'clippingParents';\nexport var viewport = 'viewport';\nexport var popper = 'popper';\nexport var reference = 'reference';\nexport var variationPlacements = /*#__PURE__*/basePlacements.reduce(function (acc, placement) {\n return acc.concat([placement + \"-\" + start, placement + \"-\" + end]);\n}, []);\nexport var placements = /*#__PURE__*/[].concat(basePlacements, [auto]).reduce(function (acc, placement) {\n return acc.concat([placement, placement + \"-\" + start, placement + \"-\" + end]);\n}, []); // modifiers that need to read the DOM\n\nexport var beforeRead = 'beforeRead';\nexport var read = 'read';\nexport var afterRead = 'afterRead'; // pure-logic modifiers\n\nexport var beforeMain = 'beforeMain';\nexport var main = 'main';\nexport var afterMain = 'afterMain'; // modifier with the purpose to write to the DOM (or write into a framework state)\n\nexport var beforeWrite = 'beforeWrite';\nexport var write = 'write';\nexport var afterWrite = 'afterWrite';\nexport var modifierPhases = [beforeRead, read, afterRead, beforeMain, main, afterMain, beforeWrite, write, afterWrite];","export default function getNodeName(element) {\n return element ? (element.nodeName || '').toLowerCase() : null;\n}","export default function getWindow(node) {\n if (node == null) {\n return window;\n }\n\n if (node.toString() !== '[object Window]') {\n var ownerDocument = node.ownerDocument;\n return ownerDocument ? ownerDocument.defaultView || window : window;\n }\n\n return node;\n}","import getWindow from \"./getWindow.js\";\n\nfunction isElement(node) {\n var OwnElement = getWindow(node).Element;\n return node instanceof OwnElement || node instanceof Element;\n}\n\nfunction isHTMLElement(node) {\n var OwnElement = getWindow(node).HTMLElement;\n return node instanceof OwnElement || node instanceof HTMLElement;\n}\n\nfunction isShadowRoot(node) {\n // IE 11 has no ShadowRoot\n if (typeof ShadowRoot === 'undefined') {\n return false;\n }\n\n var OwnElement = getWindow(node).ShadowRoot;\n return node instanceof OwnElement || node instanceof ShadowRoot;\n}\n\nexport { isElement, isHTMLElement, isShadowRoot };","import getNodeName from \"../dom-utils/getNodeName.js\";\nimport { isHTMLElement } from \"../dom-utils/instanceOf.js\"; // This modifier takes the styles prepared by the `computeStyles` modifier\n// and applies them to the HTMLElements such as popper and arrow\n\nfunction applyStyles(_ref) {\n var state = _ref.state;\n Object.keys(state.elements).forEach(function (name) {\n var style = state.styles[name] || {};\n var attributes = state.attributes[name] || {};\n var element = state.elements[name]; // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n } // Flow doesn't support to extend this property, but it's the most\n // effective way to apply styles to an HTMLElement\n // $FlowFixMe[cannot-write]\n\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (name) {\n var value = attributes[name];\n\n if (value === false) {\n element.removeAttribute(name);\n } else {\n element.setAttribute(name, value === true ? '' : value);\n }\n });\n });\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state;\n var initialStyles = {\n popper: {\n position: state.options.strategy,\n left: '0',\n top: '0',\n margin: '0'\n },\n arrow: {\n position: 'absolute'\n },\n reference: {}\n };\n Object.assign(state.elements.popper.style, initialStyles.popper);\n state.styles = initialStyles;\n\n if (state.elements.arrow) {\n Object.assign(state.elements.arrow.style, initialStyles.arrow);\n }\n\n return function () {\n Object.keys(state.elements).forEach(function (name) {\n var element = state.elements[name];\n var attributes = state.attributes[name] || {};\n var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them\n\n var style = styleProperties.reduce(function (style, property) {\n style[property] = '';\n return style;\n }, {}); // arrow is optional + virtual elements\n\n if (!isHTMLElement(element) || !getNodeName(element)) {\n return;\n }\n\n Object.assign(element.style, style);\n Object.keys(attributes).forEach(function (attribute) {\n element.removeAttribute(attribute);\n });\n });\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'applyStyles',\n enabled: true,\n phase: 'write',\n fn: applyStyles,\n effect: effect,\n requires: ['computeStyles']\n};","import { auto } from \"../enums.js\";\nexport default function getBasePlacement(placement) {\n return placement.split('-')[0];\n}","export var max = Math.max;\nexport var min = Math.min;\nexport var round = Math.round;","export default function getUAString() {\n var uaData = navigator.userAgentData;\n\n if (uaData != null && uaData.brands && Array.isArray(uaData.brands)) {\n return uaData.brands.map(function (item) {\n return item.brand + \"/\" + item.version;\n }).join(' ');\n }\n\n return navigator.userAgent;\n}","import getUAString from \"../utils/userAgent.js\";\nexport default function isLayoutViewport() {\n return !/^((?!chrome|android).)*safari/i.test(getUAString());\n}","import { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport { round } from \"../utils/math.js\";\nimport getWindow from \"./getWindow.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getBoundingClientRect(element, includeScale, isFixedStrategy) {\n if (includeScale === void 0) {\n includeScale = false;\n }\n\n if (isFixedStrategy === void 0) {\n isFixedStrategy = false;\n }\n\n var clientRect = element.getBoundingClientRect();\n var scaleX = 1;\n var scaleY = 1;\n\n if (includeScale && isHTMLElement(element)) {\n scaleX = element.offsetWidth > 0 ? round(clientRect.width) / element.offsetWidth || 1 : 1;\n scaleY = element.offsetHeight > 0 ? round(clientRect.height) / element.offsetHeight || 1 : 1;\n }\n\n var _ref = isElement(element) ? getWindow(element) : window,\n visualViewport = _ref.visualViewport;\n\n var addVisualOffsets = !isLayoutViewport() && isFixedStrategy;\n var x = (clientRect.left + (addVisualOffsets && visualViewport ? visualViewport.offsetLeft : 0)) / scaleX;\n var y = (clientRect.top + (addVisualOffsets && visualViewport ? visualViewport.offsetTop : 0)) / scaleY;\n var width = clientRect.width / scaleX;\n var height = clientRect.height / scaleY;\n return {\n width: width,\n height: height,\n top: y,\n right: x + width,\n bottom: y + height,\n left: x,\n x: x,\n y: y\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\"; // Returns the layout rect of an element relative to its offsetParent. Layout\n// means it doesn't take into account transforms.\n\nexport default function getLayoutRect(element) {\n var clientRect = getBoundingClientRect(element); // Use the clientRect sizes if it's not been transformed.\n // Fixes https://github.com/popperjs/popper-core/issues/1223\n\n var width = element.offsetWidth;\n var height = element.offsetHeight;\n\n if (Math.abs(clientRect.width - width) <= 1) {\n width = clientRect.width;\n }\n\n if (Math.abs(clientRect.height - height) <= 1) {\n height = clientRect.height;\n }\n\n return {\n x: element.offsetLeft,\n y: element.offsetTop,\n width: width,\n height: height\n };\n}","import { isShadowRoot } from \"./instanceOf.js\";\nexport default function contains(parent, child) {\n var rootNode = child.getRootNode && child.getRootNode(); // First, attempt with faster native method\n\n if (parent.contains(child)) {\n return true;\n } // then fallback to custom implementation with Shadow DOM support\n else if (rootNode && isShadowRoot(rootNode)) {\n var next = child;\n\n do {\n if (next && parent.isSameNode(next)) {\n return true;\n } // $FlowFixMe[prop-missing]: need a better way to handle this...\n\n\n next = next.parentNode || next.host;\n } while (next);\n } // Give up, the result is false\n\n\n return false;\n}","import getWindow from \"./getWindow.js\";\nexport default function getComputedStyle(element) {\n return getWindow(element).getComputedStyle(element);\n}","import getNodeName from \"./getNodeName.js\";\nexport default function isTableElement(element) {\n return ['table', 'td', 'th'].indexOf(getNodeName(element)) >= 0;\n}","import { isElement } from \"./instanceOf.js\";\nexport default function getDocumentElement(element) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return ((isElement(element) ? element.ownerDocument : // $FlowFixMe[prop-missing]\n element.document) || window.document).documentElement;\n}","import getNodeName from \"./getNodeName.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport { isShadowRoot } from \"./instanceOf.js\";\nexport default function getParentNode(element) {\n if (getNodeName(element) === 'html') {\n return element;\n }\n\n return (// this is a quicker (but less type safe) way to save quite some bytes from the bundle\n // $FlowFixMe[incompatible-return]\n // $FlowFixMe[prop-missing]\n element.assignedSlot || // step into the shadow DOM of the parent of a slotted node\n element.parentNode || ( // DOM Element detected\n isShadowRoot(element) ? element.host : null) || // ShadowRoot detected\n // $FlowFixMe[incompatible-call]: HTMLElement is a Node\n getDocumentElement(element) // fallback\n\n );\n}","import getWindow from \"./getWindow.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isHTMLElement, isShadowRoot } from \"./instanceOf.js\";\nimport isTableElement from \"./isTableElement.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getUAString from \"../utils/userAgent.js\";\n\nfunction getTrueOffsetParent(element) {\n if (!isHTMLElement(element) || // https://github.com/popperjs/popper-core/issues/837\n getComputedStyle(element).position === 'fixed') {\n return null;\n }\n\n return element.offsetParent;\n} // `.offsetParent` reports `null` for fixed elements, while absolute elements\n// return the containing block\n\n\nfunction getContainingBlock(element) {\n var isFirefox = /firefox/i.test(getUAString());\n var isIE = /Trident/i.test(getUAString());\n\n if (isIE && isHTMLElement(element)) {\n // In IE 9, 10 and 11 fixed elements containing block is always established by the viewport\n var elementCss = getComputedStyle(element);\n\n if (elementCss.position === 'fixed') {\n return null;\n }\n }\n\n var currentNode = getParentNode(element);\n\n if (isShadowRoot(currentNode)) {\n currentNode = currentNode.host;\n }\n\n while (isHTMLElement(currentNode) && ['html', 'body'].indexOf(getNodeName(currentNode)) < 0) {\n var css = getComputedStyle(currentNode); // This is non-exhaustive but covers the most common CSS properties that\n // create a containing block.\n // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block\n\n if (css.transform !== 'none' || css.perspective !== 'none' || css.contain === 'paint' || ['transform', 'perspective'].indexOf(css.willChange) !== -1 || isFirefox && css.willChange === 'filter' || isFirefox && css.filter && css.filter !== 'none') {\n return currentNode;\n } else {\n currentNode = currentNode.parentNode;\n }\n }\n\n return null;\n} // Gets the closest ancestor positioned element. Handles some edge cases,\n// such as table ancestors and cross browser bugs.\n\n\nexport default function getOffsetParent(element) {\n var window = getWindow(element);\n var offsetParent = getTrueOffsetParent(element);\n\n while (offsetParent && isTableElement(offsetParent) && getComputedStyle(offsetParent).position === 'static') {\n offsetParent = getTrueOffsetParent(offsetParent);\n }\n\n if (offsetParent && (getNodeName(offsetParent) === 'html' || getNodeName(offsetParent) === 'body' && getComputedStyle(offsetParent).position === 'static')) {\n return window;\n }\n\n return offsetParent || getContainingBlock(element) || window;\n}","export default function getMainAxisFromPlacement(placement) {\n return ['top', 'bottom'].indexOf(placement) >= 0 ? 'x' : 'y';\n}","import { max as mathMax, min as mathMin } from \"./math.js\";\nexport function within(min, value, max) {\n return mathMax(min, mathMin(value, max));\n}\nexport function withinMaxClamp(min, value, max) {\n var v = within(min, value, max);\n return v > max ? max : v;\n}","import getFreshSideObject from \"./getFreshSideObject.js\";\nexport default function mergePaddingObject(paddingObject) {\n return Object.assign({}, getFreshSideObject(), paddingObject);\n}","export default function getFreshSideObject() {\n return {\n top: 0,\n right: 0,\n bottom: 0,\n left: 0\n };\n}","export default function expandToHashMap(value, keys) {\n return keys.reduce(function (hashMap, key) {\n hashMap[key] = value;\n return hashMap;\n }, {});\n}","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport contains from \"../dom-utils/contains.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport { within } from \"../utils/within.js\";\nimport mergePaddingObject from \"../utils/mergePaddingObject.js\";\nimport expandToHashMap from \"../utils/expandToHashMap.js\";\nimport { left, right, basePlacements, top, bottom } from \"../enums.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar toPaddingObject = function toPaddingObject(padding, state) {\n padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, {\n placement: state.placement\n })) : padding;\n return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n};\n\nfunction arrow(_ref) {\n var _state$modifiersData$;\n\n var state = _ref.state,\n name = _ref.name,\n options = _ref.options;\n var arrowElement = state.elements.arrow;\n var popperOffsets = state.modifiersData.popperOffsets;\n var basePlacement = getBasePlacement(state.placement);\n var axis = getMainAxisFromPlacement(basePlacement);\n var isVertical = [left, right].indexOf(basePlacement) >= 0;\n var len = isVertical ? 'height' : 'width';\n\n if (!arrowElement || !popperOffsets) {\n return;\n }\n\n var paddingObject = toPaddingObject(options.padding, state);\n var arrowRect = getLayoutRect(arrowElement);\n var minProp = axis === 'y' ? top : left;\n var maxProp = axis === 'y' ? bottom : right;\n var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len];\n var startDiff = popperOffsets[axis] - state.rects.reference[axis];\n var arrowOffsetParent = getOffsetParent(arrowElement);\n var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;\n var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is\n // outside of the popper bounds\n\n var min = paddingObject[minProp];\n var max = clientSize - arrowRect[len] - paddingObject[maxProp];\n var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference;\n var offset = within(min, center, max); // Prevents breaking syntax highlighting...\n\n var axisProp = axis;\n state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$);\n}\n\nfunction effect(_ref2) {\n var state = _ref2.state,\n options = _ref2.options;\n var _options$element = options.element,\n arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element;\n\n if (arrowElement == null) {\n return;\n } // CSS selector\n\n\n if (typeof arrowElement === 'string') {\n arrowElement = state.elements.popper.querySelector(arrowElement);\n\n if (!arrowElement) {\n return;\n }\n }\n\n if (!contains(state.elements.popper, arrowElement)) {\n return;\n }\n\n state.elements.arrow = arrowElement;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'arrow',\n enabled: true,\n phase: 'main',\n fn: arrow,\n effect: effect,\n requires: ['popperOffsets'],\n requiresIfExists: ['preventOverflow']\n};","export default function getVariation(placement) {\n return placement.split('-')[1];\n}","import { top, left, right, bottom, end } from \"../enums.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport getWindow from \"../dom-utils/getWindow.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getComputedStyle from \"../dom-utils/getComputedStyle.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport { round } from \"../utils/math.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar unsetSides = {\n top: 'auto',\n right: 'auto',\n bottom: 'auto',\n left: 'auto'\n}; // Round the offsets to the nearest suitable subpixel based on the DPR.\n// Zooming can change the DPR, but it seems to report a value that will\n// cleanly divide the values into the appropriate subpixels.\n\nfunction roundOffsetsByDPR(_ref, win) {\n var x = _ref.x,\n y = _ref.y;\n var dpr = win.devicePixelRatio || 1;\n return {\n x: round(x * dpr) / dpr || 0,\n y: round(y * dpr) / dpr || 0\n };\n}\n\nexport function mapToStyles(_ref2) {\n var _Object$assign2;\n\n var popper = _ref2.popper,\n popperRect = _ref2.popperRect,\n placement = _ref2.placement,\n variation = _ref2.variation,\n offsets = _ref2.offsets,\n position = _ref2.position,\n gpuAcceleration = _ref2.gpuAcceleration,\n adaptive = _ref2.adaptive,\n roundOffsets = _ref2.roundOffsets,\n isFixed = _ref2.isFixed;\n var _offsets$x = offsets.x,\n x = _offsets$x === void 0 ? 0 : _offsets$x,\n _offsets$y = offsets.y,\n y = _offsets$y === void 0 ? 0 : _offsets$y;\n\n var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({\n x: x,\n y: y\n }) : {\n x: x,\n y: y\n };\n\n x = _ref3.x;\n y = _ref3.y;\n var hasX = offsets.hasOwnProperty('x');\n var hasY = offsets.hasOwnProperty('y');\n var sideX = left;\n var sideY = top;\n var win = window;\n\n if (adaptive) {\n var offsetParent = getOffsetParent(popper);\n var heightProp = 'clientHeight';\n var widthProp = 'clientWidth';\n\n if (offsetParent === getWindow(popper)) {\n offsetParent = getDocumentElement(popper);\n\n if (getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') {\n heightProp = 'scrollHeight';\n widthProp = 'scrollWidth';\n }\n } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it\n\n\n offsetParent = offsetParent;\n\n if (placement === top || (placement === left || placement === right) && variation === end) {\n sideY = bottom;\n var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]\n offsetParent[heightProp];\n y -= offsetY - popperRect.height;\n y *= gpuAcceleration ? 1 : -1;\n }\n\n if (placement === left || (placement === top || placement === bottom) && variation === end) {\n sideX = right;\n var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]\n offsetParent[widthProp];\n x -= offsetX - popperRect.width;\n x *= gpuAcceleration ? 1 : -1;\n }\n }\n\n var commonStyles = Object.assign({\n position: position\n }, adaptive && unsetSides);\n\n var _ref4 = roundOffsets === true ? roundOffsetsByDPR({\n x: x,\n y: y\n }, getWindow(popper)) : {\n x: x,\n y: y\n };\n\n x = _ref4.x;\n y = _ref4.y;\n\n if (gpuAcceleration) {\n var _Object$assign;\n\n return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? \"translate(\" + x + \"px, \" + y + \"px)\" : \"translate3d(\" + x + \"px, \" + y + \"px, 0)\", _Object$assign));\n }\n\n return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + \"px\" : '', _Object$assign2[sideX] = hasX ? x + \"px\" : '', _Object$assign2.transform = '', _Object$assign2));\n}\n\nfunction computeStyles(_ref5) {\n var state = _ref5.state,\n options = _ref5.options;\n var _options$gpuAccelerat = options.gpuAcceleration,\n gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,\n _options$adaptive = options.adaptive,\n adaptive = _options$adaptive === void 0 ? true : _options$adaptive,\n _options$roundOffsets = options.roundOffsets,\n roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;\n var commonStyles = {\n placement: getBasePlacement(state.placement),\n variation: getVariation(state.placement),\n popper: state.elements.popper,\n popperRect: state.rects.popper,\n gpuAcceleration: gpuAcceleration,\n isFixed: state.options.strategy === 'fixed'\n };\n\n if (state.modifiersData.popperOffsets != null) {\n state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.popperOffsets,\n position: state.options.strategy,\n adaptive: adaptive,\n roundOffsets: roundOffsets\n })));\n }\n\n if (state.modifiersData.arrow != null) {\n state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {\n offsets: state.modifiersData.arrow,\n position: 'absolute',\n adaptive: false,\n roundOffsets: roundOffsets\n })));\n }\n\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-placement': state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'computeStyles',\n enabled: true,\n phase: 'beforeWrite',\n fn: computeStyles,\n data: {}\n};","import getWindow from \"../dom-utils/getWindow.js\"; // eslint-disable-next-line import/no-unused-modules\n\nvar passive = {\n passive: true\n};\n\nfunction effect(_ref) {\n var state = _ref.state,\n instance = _ref.instance,\n options = _ref.options;\n var _options$scroll = options.scroll,\n scroll = _options$scroll === void 0 ? true : _options$scroll,\n _options$resize = options.resize,\n resize = _options$resize === void 0 ? true : _options$resize;\n var window = getWindow(state.elements.popper);\n var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper);\n\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.addEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.addEventListener('resize', instance.update, passive);\n }\n\n return function () {\n if (scroll) {\n scrollParents.forEach(function (scrollParent) {\n scrollParent.removeEventListener('scroll', instance.update, passive);\n });\n }\n\n if (resize) {\n window.removeEventListener('resize', instance.update, passive);\n }\n };\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'eventListeners',\n enabled: true,\n phase: 'write',\n fn: function fn() {},\n effect: effect,\n data: {}\n};","var hash = {\n left: 'right',\n right: 'left',\n bottom: 'top',\n top: 'bottom'\n};\nexport default function getOppositePlacement(placement) {\n return placement.replace(/left|right|bottom|top/g, function (matched) {\n return hash[matched];\n });\n}","var hash = {\n start: 'end',\n end: 'start'\n};\nexport default function getOppositeVariationPlacement(placement) {\n return placement.replace(/start|end/g, function (matched) {\n return hash[matched];\n });\n}","import getWindow from \"./getWindow.js\";\nexport default function getWindowScroll(node) {\n var win = getWindow(node);\n var scrollLeft = win.pageXOffset;\n var scrollTop = win.pageYOffset;\n return {\n scrollLeft: scrollLeft,\n scrollTop: scrollTop\n };\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nexport default function getWindowScrollBarX(element) {\n // If <html> has a CSS width greater than the viewport, then this will be\n // incorrect for RTL.\n // Popper 1 is broken in this case and never had a bug report so let's assume\n // it's not an issue. I don't think anyone ever specifies width on <html>\n // anyway.\n // Browsers where the left scrollbar doesn't cause an issue report `0` for\n // this (e.g. Edge 2019, IE11, Safari)\n return getBoundingClientRect(getDocumentElement(element)).left + getWindowScroll(element).scrollLeft;\n}","import getComputedStyle from \"./getComputedStyle.js\";\nexport default function isScrollParent(element) {\n // Firefox wants us to check `-x` and `-y` variations as well\n var _getComputedStyle = getComputedStyle(element),\n overflow = _getComputedStyle.overflow,\n overflowX = _getComputedStyle.overflowX,\n overflowY = _getComputedStyle.overflowY;\n\n return /auto|scroll|overlay|hidden/.test(overflow + overflowY + overflowX);\n}","import getParentNode from \"./getParentNode.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nexport default function getScrollParent(node) {\n if (['html', 'body', '#document'].indexOf(getNodeName(node)) >= 0) {\n // $FlowFixMe[incompatible-return]: assume body is always available\n return node.ownerDocument.body;\n }\n\n if (isHTMLElement(node) && isScrollParent(node)) {\n return node;\n }\n\n return getScrollParent(getParentNode(node));\n}","import getScrollParent from \"./getScrollParent.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport getWindow from \"./getWindow.js\";\nimport isScrollParent from \"./isScrollParent.js\";\n/*\ngiven a DOM element, return the list of all scroll parents, up the list of ancesors\nuntil we get to the top window object. This list is what we attach scroll listeners\nto, because if any of these parent elements scroll, we'll need to re-calculate the\nreference element's position.\n*/\n\nexport default function listScrollParents(element, list) {\n var _element$ownerDocumen;\n\n if (list === void 0) {\n list = [];\n }\n\n var scrollParent = getScrollParent(element);\n var isBody = scrollParent === ((_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body);\n var win = getWindow(scrollParent);\n var target = isBody ? [win].concat(win.visualViewport || [], isScrollParent(scrollParent) ? scrollParent : []) : scrollParent;\n var updatedList = list.concat(target);\n return isBody ? updatedList : // $FlowFixMe[incompatible-call]: isBody tells us target will be an HTMLElement here\n updatedList.concat(listScrollParents(getParentNode(target)));\n}","export default function rectToClientRect(rect) {\n return Object.assign({}, rect, {\n left: rect.x,\n top: rect.y,\n right: rect.x + rect.width,\n bottom: rect.y + rect.height\n });\n}","import { viewport } from \"../enums.js\";\nimport getViewportRect from \"./getViewportRect.js\";\nimport getDocumentRect from \"./getDocumentRect.js\";\nimport listScrollParents from \"./listScrollParents.js\";\nimport getOffsetParent from \"./getOffsetParent.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport { isElement, isHTMLElement } from \"./instanceOf.js\";\nimport getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getParentNode from \"./getParentNode.js\";\nimport contains from \"./contains.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport rectToClientRect from \"../utils/rectToClientRect.js\";\nimport { max, min } from \"../utils/math.js\";\n\nfunction getInnerBoundingClientRect(element, strategy) {\n var rect = getBoundingClientRect(element, false, strategy === 'fixed');\n rect.top = rect.top + element.clientTop;\n rect.left = rect.left + element.clientLeft;\n rect.bottom = rect.top + element.clientHeight;\n rect.right = rect.left + element.clientWidth;\n rect.width = element.clientWidth;\n rect.height = element.clientHeight;\n rect.x = rect.left;\n rect.y = rect.top;\n return rect;\n}\n\nfunction getClientRectFromMixedType(element, clippingParent, strategy) {\n return clippingParent === viewport ? rectToClientRect(getViewportRect(element, strategy)) : isElement(clippingParent) ? getInnerBoundingClientRect(clippingParent, strategy) : rectToClientRect(getDocumentRect(getDocumentElement(element)));\n} // A \"clipping parent\" is an overflowable container with the characteristic of\n// clipping (or hiding) overflowing elements with a position different from\n// `initial`\n\n\nfunction getClippingParents(element) {\n var clippingParents = listScrollParents(getParentNode(element));\n var canEscapeClipping = ['absolute', 'fixed'].indexOf(getComputedStyle(element).position) >= 0;\n var clipperElement = canEscapeClipping && isHTMLElement(element) ? getOffsetParent(element) : element;\n\n if (!isElement(clipperElement)) {\n return [];\n } // $FlowFixMe[incompatible-return]: https://github.com/facebook/flow/issues/1414\n\n\n return clippingParents.filter(function (clippingParent) {\n return isElement(clippingParent) && contains(clippingParent, clipperElement) && getNodeName(clippingParent) !== 'body';\n });\n} // Gets the maximum area that the element is visible in due to any number of\n// clipping parents\n\n\nexport default function getClippingRect(element, boundary, rootBoundary, strategy) {\n var mainClippingParents = boundary === 'clippingParents' ? getClippingParents(element) : [].concat(boundary);\n var clippingParents = [].concat(mainClippingParents, [rootBoundary]);\n var firstClippingParent = clippingParents[0];\n var clippingRect = clippingParents.reduce(function (accRect, clippingParent) {\n var rect = getClientRectFromMixedType(element, clippingParent, strategy);\n accRect.top = max(rect.top, accRect.top);\n accRect.right = min(rect.right, accRect.right);\n accRect.bottom = min(rect.bottom, accRect.bottom);\n accRect.left = max(rect.left, accRect.left);\n return accRect;\n }, getClientRectFromMixedType(element, firstClippingParent, strategy));\n clippingRect.width = clippingRect.right - clippingRect.left;\n clippingRect.height = clippingRect.bottom - clippingRect.top;\n clippingRect.x = clippingRect.left;\n clippingRect.y = clippingRect.top;\n return clippingRect;\n}","import getWindow from \"./getWindow.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport isLayoutViewport from \"./isLayoutViewport.js\";\nexport default function getViewportRect(element, strategy) {\n var win = getWindow(element);\n var html = getDocumentElement(element);\n var visualViewport = win.visualViewport;\n var width = html.clientWidth;\n var height = html.clientHeight;\n var x = 0;\n var y = 0;\n\n if (visualViewport) {\n width = visualViewport.width;\n height = visualViewport.height;\n var layoutViewport = isLayoutViewport();\n\n if (layoutViewport || !layoutViewport && strategy === 'fixed') {\n x = visualViewport.offsetLeft;\n y = visualViewport.offsetTop;\n }\n }\n\n return {\n width: width,\n height: height,\n x: x + getWindowScrollBarX(element),\n y: y\n };\n}","import getDocumentElement from \"./getDocumentElement.js\";\nimport getComputedStyle from \"./getComputedStyle.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getWindowScroll from \"./getWindowScroll.js\";\nimport { max } from \"../utils/math.js\"; // Gets the entire size of the scrollable document area, even extending outside\n// of the `<html>` and `<body>` rect bounds if horizontally scrollable\n\nexport default function getDocumentRect(element) {\n var _element$ownerDocumen;\n\n var html = getDocumentElement(element);\n var winScroll = getWindowScroll(element);\n var body = (_element$ownerDocumen = element.ownerDocument) == null ? void 0 : _element$ownerDocumen.body;\n var width = max(html.scrollWidth, html.clientWidth, body ? body.scrollWidth : 0, body ? body.clientWidth : 0);\n var height = max(html.scrollHeight, html.clientHeight, body ? body.scrollHeight : 0, body ? body.clientHeight : 0);\n var x = -winScroll.scrollLeft + getWindowScrollBarX(element);\n var y = -winScroll.scrollTop;\n\n if (getComputedStyle(body || html).direction === 'rtl') {\n x += max(html.clientWidth, body ? body.clientWidth : 0) - width;\n }\n\n return {\n width: width,\n height: height,\n x: x,\n y: y\n };\n}","import getBasePlacement from \"./getBasePlacement.js\";\nimport getVariation from \"./getVariation.js\";\nimport getMainAxisFromPlacement from \"./getMainAxisFromPlacement.js\";\nimport { top, right, bottom, left, start, end } from \"../enums.js\";\nexport default function computeOffsets(_ref) {\n var reference = _ref.reference,\n element = _ref.element,\n placement = _ref.placement;\n var basePlacement = placement ? getBasePlacement(placement) : null;\n var variation = placement ? getVariation(placement) : null;\n var commonX = reference.x + reference.width / 2 - element.width / 2;\n var commonY = reference.y + reference.height / 2 - element.height / 2;\n var offsets;\n\n switch (basePlacement) {\n case top:\n offsets = {\n x: commonX,\n y: reference.y - element.height\n };\n break;\n\n case bottom:\n offsets = {\n x: commonX,\n y: reference.y + reference.height\n };\n break;\n\n case right:\n offsets = {\n x: reference.x + reference.width,\n y: commonY\n };\n break;\n\n case left:\n offsets = {\n x: reference.x - element.width,\n y: commonY\n };\n break;\n\n default:\n offsets = {\n x: reference.x,\n y: reference.y\n };\n }\n\n var mainAxis = basePlacement ? getMainAxisFromPlacement(basePlacement) : null;\n\n if (mainAxis != null) {\n var len = mainAxis === 'y' ? 'height' : 'width';\n\n switch (variation) {\n case start:\n offsets[mainAxis] = offsets[mainAxis] - (reference[len] / 2 - element[len] / 2);\n break;\n\n case end:\n offsets[mainAxis] = offsets[mainAxis] + (reference[len] / 2 - element[len] / 2);\n break;\n\n default:\n }\n }\n\n return offsets;\n}","import getClippingRect from \"../dom-utils/getClippingRect.js\";\nimport getDocumentElement from \"../dom-utils/getDocumentElement.js\";\nimport getBoundingClientRect from \"../dom-utils/getBoundingClientRect.js\";\nimport computeOffsets from \"./computeOffsets.js\";\nimport rectToClientRect from \"./rectToClientRect.js\";\nimport { clippingParents, reference, popper, bottom, top, right, basePlacements, viewport } from \"../enums.js\";\nimport { isElement } from \"../dom-utils/instanceOf.js\";\nimport mergePaddingObject from \"./mergePaddingObject.js\";\nimport expandToHashMap from \"./expandToHashMap.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport default function detectOverflow(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n _options$placement = _options.placement,\n placement = _options$placement === void 0 ? state.placement : _options$placement,\n _options$strategy = _options.strategy,\n strategy = _options$strategy === void 0 ? state.strategy : _options$strategy,\n _options$boundary = _options.boundary,\n boundary = _options$boundary === void 0 ? clippingParents : _options$boundary,\n _options$rootBoundary = _options.rootBoundary,\n rootBoundary = _options$rootBoundary === void 0 ? viewport : _options$rootBoundary,\n _options$elementConte = _options.elementContext,\n elementContext = _options$elementConte === void 0 ? popper : _options$elementConte,\n _options$altBoundary = _options.altBoundary,\n altBoundary = _options$altBoundary === void 0 ? false : _options$altBoundary,\n _options$padding = _options.padding,\n padding = _options$padding === void 0 ? 0 : _options$padding;\n var paddingObject = mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements));\n var altContext = elementContext === popper ? reference : popper;\n var popperRect = state.rects.popper;\n var element = state.elements[altBoundary ? altContext : elementContext];\n var clippingClientRect = getClippingRect(isElement(element) ? element : element.contextElement || getDocumentElement(state.elements.popper), boundary, rootBoundary, strategy);\n var referenceClientRect = getBoundingClientRect(state.elements.reference);\n var popperOffsets = computeOffsets({\n reference: referenceClientRect,\n element: popperRect,\n strategy: 'absolute',\n placement: placement\n });\n var popperClientRect = rectToClientRect(Object.assign({}, popperRect, popperOffsets));\n var elementClientRect = elementContext === popper ? popperClientRect : referenceClientRect; // positive = overflowing the clipping rect\n // 0 or negative = within the clipping rect\n\n var overflowOffsets = {\n top: clippingClientRect.top - elementClientRect.top + paddingObject.top,\n bottom: elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\n left: clippingClientRect.left - elementClientRect.left + paddingObject.left,\n right: elementClientRect.right - clippingClientRect.right + paddingObject.right\n };\n var offsetData = state.modifiersData.offset; // Offsets can be applied only to the popper element\n\n if (elementContext === popper && offsetData) {\n var offset = offsetData[placement];\n Object.keys(overflowOffsets).forEach(function (key) {\n var multiply = [right, bottom].indexOf(key) >= 0 ? 1 : -1;\n var axis = [top, bottom].indexOf(key) >= 0 ? 'y' : 'x';\n overflowOffsets[key] += offset[axis] * multiply;\n });\n }\n\n return overflowOffsets;\n}","import getVariation from \"./getVariation.js\";\nimport { variationPlacements, basePlacements, placements as allPlacements } from \"../enums.js\";\nimport detectOverflow from \"./detectOverflow.js\";\nimport getBasePlacement from \"./getBasePlacement.js\";\nexport default function computeAutoPlacement(state, options) {\n if (options === void 0) {\n options = {};\n }\n\n var _options = options,\n placement = _options.placement,\n boundary = _options.boundary,\n rootBoundary = _options.rootBoundary,\n padding = _options.padding,\n flipVariations = _options.flipVariations,\n _options$allowedAutoP = _options.allowedAutoPlacements,\n allowedAutoPlacements = _options$allowedAutoP === void 0 ? allPlacements : _options$allowedAutoP;\n var variation = getVariation(placement);\n var placements = variation ? flipVariations ? variationPlacements : variationPlacements.filter(function (placement) {\n return getVariation(placement) === variation;\n }) : basePlacements;\n var allowedPlacements = placements.filter(function (placement) {\n return allowedAutoPlacements.indexOf(placement) >= 0;\n });\n\n if (allowedPlacements.length === 0) {\n allowedPlacements = placements;\n } // $FlowFixMe[incompatible-type]: Flow seems to have problems with two array unions...\n\n\n var overflows = allowedPlacements.reduce(function (acc, placement) {\n acc[placement] = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding\n })[getBasePlacement(placement)];\n return acc;\n }, {});\n return Object.keys(overflows).sort(function (a, b) {\n return overflows[a] - overflows[b];\n });\n}","import getOppositePlacement from \"../utils/getOppositePlacement.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getOppositeVariationPlacement from \"../utils/getOppositeVariationPlacement.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport computeAutoPlacement from \"../utils/computeAutoPlacement.js\";\nimport { bottom, top, start, right, left, auto } from \"../enums.js\";\nimport getVariation from \"../utils/getVariation.js\"; // eslint-disable-next-line import/no-unused-modules\n\nfunction getExpandedFallbackPlacements(placement) {\n if (getBasePlacement(placement) === auto) {\n return [];\n }\n\n var oppositePlacement = getOppositePlacement(placement);\n return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)];\n}\n\nfunction flip(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n\n if (state.modifiersData[name]._skip) {\n return;\n }\n\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis,\n specifiedFallbackPlacements = options.fallbackPlacements,\n padding = options.padding,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n _options$flipVariatio = options.flipVariations,\n flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio,\n allowedAutoPlacements = options.allowedAutoPlacements;\n var preferredPlacement = state.options.placement;\n var basePlacement = getBasePlacement(preferredPlacement);\n var isBasePlacement = basePlacement === preferredPlacement;\n var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement));\n var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) {\n return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n flipVariations: flipVariations,\n allowedAutoPlacements: allowedAutoPlacements\n }) : placement);\n }, []);\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var checksMap = new Map();\n var makeFallbackChecks = true;\n var firstFittingPlacement = placements[0];\n\n for (var i = 0; i < placements.length; i++) {\n var placement = placements[i];\n\n var _basePlacement = getBasePlacement(placement);\n\n var isStartVariation = getVariation(placement) === start;\n var isVertical = [top, bottom].indexOf(_basePlacement) >= 0;\n var len = isVertical ? 'width' : 'height';\n var overflow = detectOverflow(state, {\n placement: placement,\n boundary: boundary,\n rootBoundary: rootBoundary,\n altBoundary: altBoundary,\n padding: padding\n });\n var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top;\n\n if (referenceRect[len] > popperRect[len]) {\n mainVariationSide = getOppositePlacement(mainVariationSide);\n }\n\n var altVariationSide = getOppositePlacement(mainVariationSide);\n var checks = [];\n\n if (checkMainAxis) {\n checks.push(overflow[_basePlacement] <= 0);\n }\n\n if (checkAltAxis) {\n checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0);\n }\n\n if (checks.every(function (check) {\n return check;\n })) {\n firstFittingPlacement = placement;\n makeFallbackChecks = false;\n break;\n }\n\n checksMap.set(placement, checks);\n }\n\n if (makeFallbackChecks) {\n // `2` may be desired in some cases – research later\n var numberOfChecks = flipVariations ? 3 : 1;\n\n var _loop = function _loop(_i) {\n var fittingPlacement = placements.find(function (placement) {\n var checks = checksMap.get(placement);\n\n if (checks) {\n return checks.slice(0, _i).every(function (check) {\n return check;\n });\n }\n });\n\n if (fittingPlacement) {\n firstFittingPlacement = fittingPlacement;\n return \"break\";\n }\n };\n\n for (var _i = numberOfChecks; _i > 0; _i--) {\n var _ret = _loop(_i);\n\n if (_ret === \"break\") break;\n }\n }\n\n if (state.placement !== firstFittingPlacement) {\n state.modifiersData[name]._skip = true;\n state.placement = firstFittingPlacement;\n state.reset = true;\n }\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'flip',\n enabled: true,\n phase: 'main',\n fn: flip,\n requiresIfExists: ['offset'],\n data: {\n _skip: false\n }\n};","import { top, bottom, left, right } from \"../enums.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\n\nfunction getSideOffsets(overflow, rect, preventedOffsets) {\n if (preventedOffsets === void 0) {\n preventedOffsets = {\n x: 0,\n y: 0\n };\n }\n\n return {\n top: overflow.top - rect.height - preventedOffsets.y,\n right: overflow.right - rect.width + preventedOffsets.x,\n bottom: overflow.bottom - rect.height + preventedOffsets.y,\n left: overflow.left - rect.width - preventedOffsets.x\n };\n}\n\nfunction isAnySideFullyClipped(overflow) {\n return [top, right, bottom, left].some(function (side) {\n return overflow[side] >= 0;\n });\n}\n\nfunction hide(_ref) {\n var state = _ref.state,\n name = _ref.name;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var preventedOffsets = state.modifiersData.preventOverflow;\n var referenceOverflow = detectOverflow(state, {\n elementContext: 'reference'\n });\n var popperAltOverflow = detectOverflow(state, {\n altBoundary: true\n });\n var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect);\n var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets);\n var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets);\n var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets);\n state.modifiersData[name] = {\n referenceClippingOffsets: referenceClippingOffsets,\n popperEscapeOffsets: popperEscapeOffsets,\n isReferenceHidden: isReferenceHidden,\n hasPopperEscaped: hasPopperEscaped\n };\n state.attributes.popper = Object.assign({}, state.attributes.popper, {\n 'data-popper-reference-hidden': isReferenceHidden,\n 'data-popper-escaped': hasPopperEscaped\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'hide',\n enabled: true,\n phase: 'main',\n requiresIfExists: ['preventOverflow'],\n fn: hide\n};","import getBasePlacement from \"../utils/getBasePlacement.js\";\nimport { top, left, right, placements } from \"../enums.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport function distanceAndSkiddingToXY(placement, rects, offset) {\n var basePlacement = getBasePlacement(placement);\n var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1;\n\n var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, {\n placement: placement\n })) : offset,\n skidding = _ref[0],\n distance = _ref[1];\n\n skidding = skidding || 0;\n distance = (distance || 0) * invertDistance;\n return [left, right].indexOf(basePlacement) >= 0 ? {\n x: distance,\n y: skidding\n } : {\n x: skidding,\n y: distance\n };\n}\n\nfunction offset(_ref2) {\n var state = _ref2.state,\n options = _ref2.options,\n name = _ref2.name;\n var _options$offset = options.offset,\n offset = _options$offset === void 0 ? [0, 0] : _options$offset;\n var data = placements.reduce(function (acc, placement) {\n acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset);\n return acc;\n }, {});\n var _data$state$placement = data[state.placement],\n x = _data$state$placement.x,\n y = _data$state$placement.y;\n\n if (state.modifiersData.popperOffsets != null) {\n state.modifiersData.popperOffsets.x += x;\n state.modifiersData.popperOffsets.y += y;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'offset',\n enabled: true,\n phase: 'main',\n requires: ['popperOffsets'],\n fn: offset\n};","import computeOffsets from \"../utils/computeOffsets.js\";\n\nfunction popperOffsets(_ref) {\n var state = _ref.state,\n name = _ref.name;\n // Offsets are the actual position the popper needs to have to be\n // properly positioned near its reference element\n // This is the most basic placement, and will be adjusted by\n // the modifiers in the next step\n state.modifiersData[name] = computeOffsets({\n reference: state.rects.reference,\n element: state.rects.popper,\n strategy: 'absolute',\n placement: state.placement\n });\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'popperOffsets',\n enabled: true,\n phase: 'read',\n fn: popperOffsets,\n data: {}\n};","import { top, left, right, bottom, start } from \"../enums.js\";\nimport getBasePlacement from \"../utils/getBasePlacement.js\";\nimport getMainAxisFromPlacement from \"../utils/getMainAxisFromPlacement.js\";\nimport getAltAxis from \"../utils/getAltAxis.js\";\nimport { within, withinMaxClamp } from \"../utils/within.js\";\nimport getLayoutRect from \"../dom-utils/getLayoutRect.js\";\nimport getOffsetParent from \"../dom-utils/getOffsetParent.js\";\nimport detectOverflow from \"../utils/detectOverflow.js\";\nimport getVariation from \"../utils/getVariation.js\";\nimport getFreshSideObject from \"../utils/getFreshSideObject.js\";\nimport { min as mathMin, max as mathMax } from \"../utils/math.js\";\n\nfunction preventOverflow(_ref) {\n var state = _ref.state,\n options = _ref.options,\n name = _ref.name;\n var _options$mainAxis = options.mainAxis,\n checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,\n _options$altAxis = options.altAxis,\n checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,\n boundary = options.boundary,\n rootBoundary = options.rootBoundary,\n altBoundary = options.altBoundary,\n padding = options.padding,\n _options$tether = options.tether,\n tether = _options$tether === void 0 ? true : _options$tether,\n _options$tetherOffset = options.tetherOffset,\n tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;\n var overflow = detectOverflow(state, {\n boundary: boundary,\n rootBoundary: rootBoundary,\n padding: padding,\n altBoundary: altBoundary\n });\n var basePlacement = getBasePlacement(state.placement);\n var variation = getVariation(state.placement);\n var isBasePlacement = !variation;\n var mainAxis = getMainAxisFromPlacement(basePlacement);\n var altAxis = getAltAxis(mainAxis);\n var popperOffsets = state.modifiersData.popperOffsets;\n var referenceRect = state.rects.reference;\n var popperRect = state.rects.popper;\n var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {\n placement: state.placement\n })) : tetherOffset;\n var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {\n mainAxis: tetherOffsetValue,\n altAxis: tetherOffsetValue\n } : Object.assign({\n mainAxis: 0,\n altAxis: 0\n }, tetherOffsetValue);\n var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;\n var data = {\n x: 0,\n y: 0\n };\n\n if (!popperOffsets) {\n return;\n }\n\n if (checkMainAxis) {\n var _offsetModifierState$;\n\n var mainSide = mainAxis === 'y' ? top : left;\n var altSide = mainAxis === 'y' ? bottom : right;\n var len = mainAxis === 'y' ? 'height' : 'width';\n var offset = popperOffsets[mainAxis];\n var min = offset + overflow[mainSide];\n var max = offset - overflow[altSide];\n var additive = tether ? -popperRect[len] / 2 : 0;\n var minLen = variation === start ? referenceRect[len] : popperRect[len];\n var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go\n // outside the reference bounds\n\n var arrowElement = state.elements.arrow;\n var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {\n width: 0,\n height: 0\n };\n var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();\n var arrowPaddingMin = arrowPaddingObject[mainSide];\n var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want\n // to include its full size in the calculation. If the reference is small\n // and near the edge of a boundary, the popper can overflow even if the\n // reference is not overflowing as well (e.g. virtual elements with no\n // width or height)\n\n var arrowLen = within(0, referenceRect[len], arrowRect[len]);\n var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;\n var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;\n var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);\n var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;\n var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;\n var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;\n var tetherMax = offset + maxOffset - offsetModifierValue;\n var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max);\n popperOffsets[mainAxis] = preventedOffset;\n data[mainAxis] = preventedOffset - offset;\n }\n\n if (checkAltAxis) {\n var _offsetModifierState$2;\n\n var _mainSide = mainAxis === 'x' ? top : left;\n\n var _altSide = mainAxis === 'x' ? bottom : right;\n\n var _offset = popperOffsets[altAxis];\n\n var _len = altAxis === 'y' ? 'height' : 'width';\n\n var _min = _offset + overflow[_mainSide];\n\n var _max = _offset - overflow[_altSide];\n\n var isOriginSide = [top, left].indexOf(basePlacement) !== -1;\n\n var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;\n\n var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;\n\n var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;\n\n var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);\n\n popperOffsets[altAxis] = _preventedOffset;\n data[altAxis] = _preventedOffset - _offset;\n }\n\n state.modifiersData[name] = data;\n} // eslint-disable-next-line import/no-unused-modules\n\n\nexport default {\n name: 'preventOverflow',\n enabled: true,\n phase: 'main',\n fn: preventOverflow,\n requiresIfExists: ['offset']\n};","export default function getAltAxis(axis) {\n return axis === 'x' ? 'y' : 'x';\n}","import getBoundingClientRect from \"./getBoundingClientRect.js\";\nimport getNodeScroll from \"./getNodeScroll.js\";\nimport getNodeName from \"./getNodeName.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getWindowScrollBarX from \"./getWindowScrollBarX.js\";\nimport getDocumentElement from \"./getDocumentElement.js\";\nimport isScrollParent from \"./isScrollParent.js\";\nimport { round } from \"../utils/math.js\";\n\nfunction isElementScaled(element) {\n var rect = element.getBoundingClientRect();\n var scaleX = round(rect.width) / element.offsetWidth || 1;\n var scaleY = round(rect.height) / element.offsetHeight || 1;\n return scaleX !== 1 || scaleY !== 1;\n} // Returns the composite rect of an element relative to its offsetParent.\n// Composite means it takes into account transforms as well as layout.\n\n\nexport default function getCompositeRect(elementOrVirtualElement, offsetParent, isFixed) {\n if (isFixed === void 0) {\n isFixed = false;\n }\n\n var isOffsetParentAnElement = isHTMLElement(offsetParent);\n var offsetParentIsScaled = isHTMLElement(offsetParent) && isElementScaled(offsetParent);\n var documentElement = getDocumentElement(offsetParent);\n var rect = getBoundingClientRect(elementOrVirtualElement, offsetParentIsScaled, isFixed);\n var scroll = {\n scrollLeft: 0,\n scrollTop: 0\n };\n var offsets = {\n x: 0,\n y: 0\n };\n\n if (isOffsetParentAnElement || !isOffsetParentAnElement && !isFixed) {\n if (getNodeName(offsetParent) !== 'body' || // https://github.com/popperjs/popper-core/issues/1078\n isScrollParent(documentElement)) {\n scroll = getNodeScroll(offsetParent);\n }\n\n if (isHTMLElement(offsetParent)) {\n offsets = getBoundingClientRect(offsetParent, true);\n offsets.x += offsetParent.clientLeft;\n offsets.y += offsetParent.clientTop;\n } else if (documentElement) {\n offsets.x = getWindowScrollBarX(documentElement);\n }\n }\n\n return {\n x: rect.left + scroll.scrollLeft - offsets.x,\n y: rect.top + scroll.scrollTop - offsets.y,\n width: rect.width,\n height: rect.height\n };\n}","import getWindowScroll from \"./getWindowScroll.js\";\nimport getWindow from \"./getWindow.js\";\nimport { isHTMLElement } from \"./instanceOf.js\";\nimport getHTMLElementScroll from \"./getHTMLElementScroll.js\";\nexport default function getNodeScroll(node) {\n if (node === getWindow(node) || !isHTMLElement(node)) {\n return getWindowScroll(node);\n } else {\n return getHTMLElementScroll(node);\n }\n}","export default function getHTMLElementScroll(element) {\n return {\n scrollLeft: element.scrollLeft,\n scrollTop: element.scrollTop\n };\n}","import { modifierPhases } from \"../enums.js\"; // source: https://stackoverflow.com/questions/49875255\n\nfunction order(modifiers) {\n var map = new Map();\n var visited = new Set();\n var result = [];\n modifiers.forEach(function (modifier) {\n map.set(modifier.name, modifier);\n }); // On visiting object, check for its dependencies and visit them recursively\n\n function sort(modifier) {\n visited.add(modifier.name);\n var requires = [].concat(modifier.requires || [], modifier.requiresIfExists || []);\n requires.forEach(function (dep) {\n if (!visited.has(dep)) {\n var depModifier = map.get(dep);\n\n if (depModifier) {\n sort(depModifier);\n }\n }\n });\n result.push(modifier);\n }\n\n modifiers.forEach(function (modifier) {\n if (!visited.has(modifier.name)) {\n // check for visited object\n sort(modifier);\n }\n });\n return result;\n}\n\nexport default function orderModifiers(modifiers) {\n // order based on dependencies\n var orderedModifiers = order(modifiers); // order based on phase\n\n return modifierPhases.reduce(function (acc, phase) {\n return acc.concat(orderedModifiers.filter(function (modifier) {\n return modifier.phase === phase;\n }));\n }, []);\n}","import getCompositeRect from \"./dom-utils/getCompositeRect.js\";\nimport getLayoutRect from \"./dom-utils/getLayoutRect.js\";\nimport listScrollParents from \"./dom-utils/listScrollParents.js\";\nimport getOffsetParent from \"./dom-utils/getOffsetParent.js\";\nimport orderModifiers from \"./utils/orderModifiers.js\";\nimport debounce from \"./utils/debounce.js\";\nimport mergeByName from \"./utils/mergeByName.js\";\nimport detectOverflow from \"./utils/detectOverflow.js\";\nimport { isElement } from \"./dom-utils/instanceOf.js\";\nvar DEFAULT_OPTIONS = {\n placement: 'bottom',\n modifiers: [],\n strategy: 'absolute'\n};\n\nfunction areValidElements() {\n for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {\n args[_key] = arguments[_key];\n }\n\n return !args.some(function (element) {\n return !(element && typeof element.getBoundingClientRect === 'function');\n });\n}\n\nexport function popperGenerator(generatorOptions) {\n if (generatorOptions === void 0) {\n generatorOptions = {};\n }\n\n var _generatorOptions = generatorOptions,\n _generatorOptions$def = _generatorOptions.defaultModifiers,\n defaultModifiers = _generatorOptions$def === void 0 ? [] : _generatorOptions$def,\n _generatorOptions$def2 = _generatorOptions.defaultOptions,\n defaultOptions = _generatorOptions$def2 === void 0 ? DEFAULT_OPTIONS : _generatorOptions$def2;\n return function createPopper(reference, popper, options) {\n if (options === void 0) {\n options = defaultOptions;\n }\n\n var state = {\n placement: 'bottom',\n orderedModifiers: [],\n options: Object.assign({}, DEFAULT_OPTIONS, defaultOptions),\n modifiersData: {},\n elements: {\n reference: reference,\n popper: popper\n },\n attributes: {},\n styles: {}\n };\n var effectCleanupFns = [];\n var isDestroyed = false;\n var instance = {\n state: state,\n setOptions: function setOptions(setOptionsAction) {\n var options = typeof setOptionsAction === 'function' ? setOptionsAction(state.options) : setOptionsAction;\n cleanupModifierEffects();\n state.options = Object.assign({}, defaultOptions, state.options, options);\n state.scrollParents = {\n reference: isElement(reference) ? listScrollParents(reference) : reference.contextElement ? listScrollParents(reference.contextElement) : [],\n popper: listScrollParents(popper)\n }; // Orders the modifiers based on their dependencies and `phase`\n // properties\n\n var orderedModifiers = orderModifiers(mergeByName([].concat(defaultModifiers, state.options.modifiers))); // Strip out disabled modifiers\n\n state.orderedModifiers = orderedModifiers.filter(function (m) {\n return m.enabled;\n });\n runModifierEffects();\n return instance.update();\n },\n // Sync update – it will always be executed, even if not necessary. This\n // is useful for low frequency updates where sync behavior simplifies the\n // logic.\n // For high frequency updates (e.g. `resize` and `scroll` events), always\n // prefer the async Popper#update method\n forceUpdate: function forceUpdate() {\n if (isDestroyed) {\n return;\n }\n\n var _state$elements = state.elements,\n reference = _state$elements.reference,\n popper = _state$elements.popper; // Don't proceed if `reference` or `popper` are not valid elements\n // anymore\n\n if (!areValidElements(reference, popper)) {\n return;\n } // Store the reference and popper rects to be read by modifiers\n\n\n state.rects = {\n reference: getCompositeRect(reference, getOffsetParent(popper), state.options.strategy === 'fixed'),\n popper: getLayoutRect(popper)\n }; // Modifiers have the ability to reset the current update cycle. The\n // most common use case for this is the `flip` modifier changing the\n // placement, which then needs to re-run all the modifiers, because the\n // logic was previously ran for the previous placement and is therefore\n // stale/incorrect\n\n state.reset = false;\n state.placement = state.options.placement; // On each update cycle, the `modifiersData` property for each modifier\n // is filled with the initial data specified by the modifier. This means\n // it doesn't persist and is fresh on each update.\n // To ensure persistent data, use `${name}#persistent`\n\n state.orderedModifiers.forEach(function (modifier) {\n return state.modifiersData[modifier.name] = Object.assign({}, modifier.data);\n });\n\n for (var index = 0; index < state.orderedModifiers.length; index++) {\n if (state.reset === true) {\n state.reset = false;\n index = -1;\n continue;\n }\n\n var _state$orderedModifie = state.orderedModifiers[index],\n fn = _state$orderedModifie.fn,\n _state$orderedModifie2 = _state$orderedModifie.options,\n _options = _state$orderedModifie2 === void 0 ? {} : _state$orderedModifie2,\n name = _state$orderedModifie.name;\n\n if (typeof fn === 'function') {\n state = fn({\n state: state,\n options: _options,\n name: name,\n instance: instance\n }) || state;\n }\n }\n },\n // Async and optimistically optimized update – it will not be executed if\n // not necessary (debounced to run at most once-per-tick)\n update: debounce(function () {\n return new Promise(function (resolve) {\n instance.forceUpdate();\n resolve(state);\n });\n }),\n destroy: function destroy() {\n cleanupModifierEffects();\n isDestroyed = true;\n }\n };\n\n if (!areValidElements(reference, popper)) {\n return instance;\n }\n\n instance.setOptions(options).then(function (state) {\n if (!isDestroyed && options.onFirstUpdate) {\n options.onFirstUpdate(state);\n }\n }); // Modifiers have the ability to execute arbitrary code before the first\n // update cycle runs. They will be executed in the same order as the update\n // cycle. This is useful when a modifier adds some persistent data that\n // other modifiers need to use, but the modifier is run after the dependent\n // one.\n\n function runModifierEffects() {\n state.orderedModifiers.forEach(function (_ref) {\n var name = _ref.name,\n _ref$options = _ref.options,\n options = _ref$options === void 0 ? {} : _ref$options,\n effect = _ref.effect;\n\n if (typeof effect === 'function') {\n var cleanupFn = effect({\n state: state,\n name: name,\n instance: instance,\n options: options\n });\n\n var noopFn = function noopFn() {};\n\n effectCleanupFns.push(cleanupFn || noopFn);\n }\n });\n }\n\n function cleanupModifierEffects() {\n effectCleanupFns.forEach(function (fn) {\n return fn();\n });\n effectCleanupFns = [];\n }\n\n return instance;\n };\n}\nexport var createPopper = /*#__PURE__*/popperGenerator(); // eslint-disable-next-line import/no-unused-modules\n\nexport { detectOverflow };","export default function debounce(fn) {\n var pending;\n return function () {\n if (!pending) {\n pending = new Promise(function (resolve) {\n Promise.resolve().then(function () {\n pending = undefined;\n resolve(fn());\n });\n });\n }\n\n return pending;\n };\n}","export default function mergeByName(modifiers) {\n var merged = modifiers.reduce(function (merged, current) {\n var existing = merged[current.name];\n merged[current.name] = existing ? Object.assign({}, existing, current, {\n options: Object.assign({}, existing.options, current.options),\n data: Object.assign({}, existing.data, current.data)\n }) : current;\n return merged;\n }, {}); // IE11 does not support Object.values\n\n return Object.keys(merged).map(function (key) {\n return merged[key];\n });\n}","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow };","import { popperGenerator, detectOverflow } from \"./createPopper.js\";\nimport eventListeners from \"./modifiers/eventListeners.js\";\nimport popperOffsets from \"./modifiers/popperOffsets.js\";\nimport computeStyles from \"./modifiers/computeStyles.js\";\nimport applyStyles from \"./modifiers/applyStyles.js\";\nimport offset from \"./modifiers/offset.js\";\nimport flip from \"./modifiers/flip.js\";\nimport preventOverflow from \"./modifiers/preventOverflow.js\";\nimport arrow from \"./modifiers/arrow.js\";\nimport hide from \"./modifiers/hide.js\";\nvar defaultModifiers = [eventListeners, popperOffsets, computeStyles, applyStyles, offset, flip, preventOverflow, arrow, hide];\nvar createPopper = /*#__PURE__*/popperGenerator({\n defaultModifiers: defaultModifiers\n}); // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper, popperGenerator, defaultModifiers, detectOverflow }; // eslint-disable-next-line import/no-unused-modules\n\nexport { createPopper as createPopperLite } from \"./popper-lite.js\"; // eslint-disable-next-line import/no-unused-modules\n\nexport * from \"./modifiers/index.js\";","/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n execute,\n getElement,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)'\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR = '.navbar'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\nconst PLACEMENT_TOPCENTER = 'top'\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\n\nconst Default = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n}\n\nconst DefaultType = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n}\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._popper = null\n this._parent = this._element.parentNode // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.findOne(SELECTOR_MENU, this._parent)\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._createPopper()\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = super._getConfig(config)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org/docs/v2/)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getPlacement() {\n const parentDropdown = this._parent\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\n return\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle)\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n const relatedTarget = { relatedTarget: context._element }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName)\n const isEscapeEvent = event.key === ESCAPE_KEY\n const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return\n }\n\n if (isInput && !isEscapeEvent) {\n return\n }\n\n event.preventDefault()\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\n this :\n (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\n\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (isUpOrDownEvent) {\n event.stopPropagation()\n instance.show()\n instance._selectMenuItem(event)\n return\n }\n\n if (instance._isShown()) { // else is escape and we check if it is shown\n event.stopPropagation()\n instance.hide()\n getToggleButton.focus()\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport {\n execute, executeAfterTransition, getElement, reflow\n} from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nconst Default = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n}\n\nconst DefaultType = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n}\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n const element = this._getElement()\n if (this._config.isAnimated) {\n reflow(element)\n }\n\n element.classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n const element = this._getElement()\n this._config.rootElement.append(element)\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin, isRTL, isVisible, reflow\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\nconst Default = {\n backdrop: true,\n focus: true,\n keyboard: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._isTransitioning = true\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._backdrop.show(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n this._isTransitioning = true\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\n }\n\n dispose() {\n EventHandler.off(window, EVENT_KEY)\n EventHandler.off(this._dialog, EVENT_KEY)\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n EventHandler.on(window, EVENT_RESIZE, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog()\n }\n })\n\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n return\n }\n\n if (this._config.backdrop) {\n this.hide()\n }\n })\n })\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const initialOverflowY = this._element.style.overflowY\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden'\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY\n }, this._dialog)\n }, this._dialog)\n\n this._element.focus()\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin,\n isDisabled,\n isVisible\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\nconst CLASS_NAME_HIDING = 'hiding'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate()\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.add(CLASS_NAME_HIDING)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n return\n }\n\n this.hide()\n }\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop)\n\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n })\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show()\n }\n})\n\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide()\n }\n }\n})\n\nenableDismissTrigger(Offcanvas)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n// js-docs-end allow-list\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n .some(regex => regex.test(attributeName))\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n }\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\nimport { execute, getElement, isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'TemplateFactory'\n\nconst Default = {\n allowList: DefaultAllowlist,\n content: {}, // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '<div></div>'\n}\n\nconst DefaultType = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n}\n\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n}\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content)\n .map(config => this._resolvePossibleFunction(config))\n .filter(Boolean)\n }\n\n hasContent() {\n return this.getContent().length > 0\n }\n\n changeContent(content) {\n this._checkContent(content)\n this._config.content = { ...this._config.content, ...content }\n return this\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div')\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector)\n }\n\n const template = templateWrapper.children[0]\n const extraClass = this._resolvePossibleFunction(this._config.extraClass)\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '))\n }\n\n return template\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config)\n this._checkContent(config.content)\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!templateElement) {\n return\n }\n\n content = this._resolvePossibleFunction(content)\n\n if (!content) {\n templateElement.remove()\n return\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement)\n return\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content)\n return\n }\n\n templateElement.textContent = content\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [undefined, this])\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = ''\n templateElement.append(element)\n return\n }\n\n templateElement.textContent = element.textContent\n }\n}\n\nexport default TemplateFactory\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport {\n defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop\n} from './util/index.js'\nimport { DefaultAllowlist } from './util/sanitizer.js'\nimport TemplateFactory from './util/template-factory.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\nconst EVENT_HIDE = 'hide'\nconst EVENT_HIDDEN = 'hidden'\nconst EVENT_SHOW = 'show'\nconst EVENT_SHOWN = 'shown'\nconst EVENT_INSERTED = 'inserted'\nconst EVENT_CLICK = 'click'\nconst EVENT_FOCUSIN = 'focusin'\nconst EVENT_FOCUSOUT = 'focusout'\nconst EVENT_MOUSEENTER = 'mouseenter'\nconst EVENT_MOUSELEAVE = 'mouseleave'\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n title: '',\n trigger: 'hover focus'\n}\n\nconst DefaultType = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n}\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org/docs/v2/)')\n }\n\n super(element, config)\n\n // Private\n this._isEnabled = true\n this._timeout = 0\n this._isHovered = null\n this._activeTrigger = {}\n this._popper = null\n this._templateFactory = null\n this._newContent = null\n\n // Protected\n this.tip = null\n\n this._setListeners()\n\n if (!this._config.selector) {\n this._fixTitle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle() {\n if (!this._isEnabled) {\n return\n }\n\n if (this._isShown()) {\n this._leave()\n return\n }\n\n this._enter()\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper()\n\n const tip = this._getTipElement()\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\n\n const { container } = this._config\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\n }\n\n this._popper = this._createPopper(tip)\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\n\n if (this._isHovered === false) {\n this._leave()\n }\n\n this._isHovered = false\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n hide() {\n if (!this._isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const tip = this._getTipElement()\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n this._isHovered = null // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (!this._isHovered) {\n this._disposePopper()\n }\n\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n update() {\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle())\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\n }\n\n return this.tip\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml()\n\n // TODO: remove this check in v6\n if (!tip) {\n return null\n }\n\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`)\n\n const tipId = getUID(this.constructor.NAME).toString()\n\n tip.setAttribute('id', tipId)\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n return tip\n }\n\n setContent(content) {\n this._newContent = content\n if (this._isShown()) {\n this._disposePopper()\n this.show()\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content)\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n })\n }\n\n return this._templateFactory\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n }\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _isAnimated() {\n return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\n }\n\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element])\n const attachment = AttachmentMap[placement.toUpperCase()]\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element, this._element])\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\n }\n }\n ]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[TRIGGER_CLICK] = !(context._isShown() && context._activeTrigger[TRIGGER_CLICK])\n context.toggle()\n })\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSEENTER) :\n this.constructor.eventName(EVENT_FOCUSIN)\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSELEAVE) :\n this.constructor.eventName(EVENT_FOCUSOUT)\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\n context._enter()\n })\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\n context._element.contains(event.relatedTarget)\n\n context._leave()\n })\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n\n if (!title) {\n return\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title')\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true\n return\n }\n\n this._isHovered = true\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show()\n }\n }, this._config.delay.show)\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n this._isHovered = false\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide()\n }\n }, this._config.delay.hide)\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout)\n this._timeout = setTimeout(handler, timeout)\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true)\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute]\n }\n }\n\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value\n }\n }\n\n config.selector = false\n config.trigger = 'manual'\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n\n if (this.tip) {\n this.tip.remove()\n this.tip = null\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin, getElement, isDisabled, isVisible\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map()\n this._observableSections = new Map()\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n this._activeTarget = null\n this._observer = null\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n }\n this.refresh() // initialize\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables()\n this._maybeEnableSmoothScroll()\n\n if (this._observer) {\n this._observer.disconnect()\n } else {\n this._observer = this._getNewObserver()\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section)\n }\n }\n\n dispose() {\n this._observer.disconnect()\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n }\n\n return config\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK)\n\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash)\n if (observableSection) {\n event.preventDefault()\n const root = this._rootElement || window\n const height = observableSection.offsetTop - this._element.offsetTop\n if (root.scrollTo) {\n root.scrollTo({ top: height, behavior: 'smooth' })\n return\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height\n }\n })\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n }\n\n return new IntersectionObserver(entries => this._observerCallback(entries), options)\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n this._process(targetElement(entry))\n }\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n this._previousScrollData.parentScrollTop = parentScrollTop\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null\n this._clearActiveClass(targetElement(entry))\n\n continue\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry)\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return\n }\n\n continue\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry)\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map()\n this._observableSections = new Map()\n\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue\n }\n\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor)\n this._observableSections.set(anchor.hash, observableSection)\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return\n }\n\n this._clearActiveClass(this._config.target)\n this._activeTarget = target\n target.classList.add(CLASS_NAME_ACTIVE)\n this._activateParents(target)\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n return\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {\n item.classList.add(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n _clearActiveClass(parent) {\n parent.classList.remove(CLASS_NAME_ACTIVE)\n\n const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)\n for (const node of activeNodes) {\n node.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {\n ScrollSpy.getOrCreateInstance(spy)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}`\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst HOME_KEY = 'Home'\nconst END_KEY = 'End'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_DROPDOWN = 'dropdown'\n\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_MENU = '.dropdown-menu'\nconst NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`\n\nconst SELECTOR_TAB_PANEL = '.list-group, .nav, [role=\"tablist\"]'\nconst SELECTOR_OUTER = '.nav-item, .list-group-item'\nconst SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role=\"tab\"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]' // TODO: could only be `tab` in v6\nconst SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`\n\nconst SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle=\"tab\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"pill\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"list\"]`\n\n/**\n * Class definition\n */\n\nclass Tab extends BaseComponent {\n constructor(element) {\n super(element)\n this._parent = this._element.closest(SELECTOR_TAB_PANEL)\n\n if (!this._parent) {\n return\n // TODO: should throw exception in v6\n // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)\n }\n\n // Set up initial aria attributes\n this._setInitialAttributes(this._parent, this._getChildren())\n\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n show() { // Shows this elem and deactivate the active sibling if exists\n const innerElem = this._element\n if (this._elemIsActive(innerElem)) {\n return\n }\n\n // Search for active tab on same parent to deactivate it\n const active = this._getActiveElem()\n\n const hideEvent = active ?\n EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :\n null\n\n const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })\n\n if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {\n return\n }\n\n this._deactivate(active, innerElem)\n this._activate(innerElem, active)\n }\n\n // Private\n _activate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n\n this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.add(CLASS_NAME_SHOW)\n return\n }\n\n element.removeAttribute('tabindex')\n element.setAttribute('aria-selected', true)\n this._toggleDropDown(element, true)\n EventHandler.trigger(element, EVENT_SHOWN, {\n relatedTarget: relatedElem\n })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _deactivate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.remove(CLASS_NAME_ACTIVE)\n element.blur()\n\n this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.remove(CLASS_NAME_SHOW)\n return\n }\n\n element.setAttribute('aria-selected', false)\n element.setAttribute('tabindex', '-1')\n this._toggleDropDown(element, false)\n EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _keydown(event) {\n if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {\n return\n }\n\n event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page\n event.preventDefault()\n\n const children = this._getChildren().filter(element => !isDisabled(element))\n let nextActiveElement\n\n if ([HOME_KEY, END_KEY].includes(event.key)) {\n nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]\n } else {\n const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)\n nextActiveElement = getNextActiveElement(children, event.target, isNext, true)\n }\n\n if (nextActiveElement) {\n nextActiveElement.focus({ preventScroll: true })\n Tab.getOrCreateInstance(nextActiveElement).show()\n }\n }\n\n _getChildren() { // collection of inner elements\n return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)\n }\n\n _getActiveElem() {\n return this._getChildren().find(child => this._elemIsActive(child)) || null\n }\n\n _setInitialAttributes(parent, children) {\n this._setAttributeIfNotExists(parent, 'role', 'tablist')\n\n for (const child of children) {\n this._setInitialAttributesOnChild(child)\n }\n }\n\n _setInitialAttributesOnChild(child) {\n child = this._getInnerElement(child)\n const isActive = this._elemIsActive(child)\n const outerElem = this._getOuterElement(child)\n child.setAttribute('aria-selected', isActive)\n\n if (outerElem !== child) {\n this._setAttributeIfNotExists(outerElem, 'role', 'presentation')\n }\n\n if (!isActive) {\n child.setAttribute('tabindex', '-1')\n }\n\n this._setAttributeIfNotExists(child, 'role', 'tab')\n\n // set attributes to the related panel too\n this._setInitialAttributesOnTargetPanel(child)\n }\n\n _setInitialAttributesOnTargetPanel(child) {\n const target = SelectorEngine.getElementFromSelector(child)\n\n if (!target) {\n return\n }\n\n this._setAttributeIfNotExists(target, 'role', 'tabpanel')\n\n if (child.id) {\n this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)\n }\n }\n\n _toggleDropDown(element, open) {\n const outerElem = this._getOuterElement(element)\n if (!outerElem.classList.contains(CLASS_DROPDOWN)) {\n return\n }\n\n const toggle = (selector, className) => {\n const element = SelectorEngine.findOne(selector, outerElem)\n if (element) {\n element.classList.toggle(className, open)\n }\n }\n\n toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)\n toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)\n outerElem.setAttribute('aria-expanded', open)\n }\n\n _setAttributeIfNotExists(element, attribute, value) {\n if (!element.hasAttribute(attribute)) {\n element.setAttribute(attribute, value)\n }\n }\n\n _elemIsActive(elem) {\n return elem.classList.contains(CLASS_NAME_ACTIVE)\n }\n\n // Try to get the inner element (usually the .nav-link)\n _getInnerElement(elem) {\n return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)\n }\n\n // Try to get the outer element (usually the .nav-item)\n _getOuterElement(elem) {\n return elem.closest(SELECTOR_OUTER) || elem\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n Tab.getOrCreateInstance(this).show()\n})\n\n/**\n * Initialize on focus\n */\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {\n Tab.getOrCreateInstance(element)\n }\n})\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin, reflow } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * Class definition\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this.isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this.isShown()) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n isShown() {\n return this._element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout': {\n this._hasMouseInteraction = isInteracting\n break\n }\n\n case 'focusin':\n case 'focusout': {\n this._hasKeyboardInteraction = isInteracting\n break\n }\n\n default: {\n break\n }\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Toast)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert.js'\nimport Button from './src/button.js'\nimport Carousel from './src/carousel.js'\nimport Collapse from './src/collapse.js'\nimport Dropdown from './src/dropdown.js'\nimport Modal from './src/modal.js'\nimport Offcanvas from './src/offcanvas.js'\nimport Popover from './src/popover.js'\nimport ScrollSpy from './src/scrollspy.js'\nimport Tab from './src/tab.js'\nimport Toast from './src/toast.js'\nimport Tooltip from './src/tooltip.js'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.js b/extensions/pagetop-bootsier/static/js/bootstrap.js new file mode 100644 index 0000000..e1f6e58 --- /dev/null +++ b/extensions/pagetop-bootsier/static/js/bootstrap.js @@ -0,0 +1,4494 @@ +/*! + * Bootstrap v5.3.8 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('@popperjs/core')) : + typeof define === 'function' && define.amd ? define(['@popperjs/core'], factory) : + (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.bootstrap = factory(global.Popper)); +})(this, (function (Popper) { 'use strict'; + + function _interopNamespaceDefault(e) { + const n = Object.create(null, { [Symbol.toStringTag]: { value: 'Module' } }); + if (e) { + for (const k in e) { + if (k !== 'default') { + const d = Object.getOwnPropertyDescriptor(e, k); + Object.defineProperty(n, k, d.get ? d : { + enumerable: true, + get: () => e[k] + }); + } + } + } + n.default = e; + return Object.freeze(n); + } + + const Popper__namespace = /*#__PURE__*/_interopNamespaceDefault(Popper); + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/data.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + /** + * Constants + */ + + const elementMap = new Map(); + const Data = { + set(element, key, instance) { + if (!elementMap.has(element)) { + elementMap.set(element, new Map()); + } + const instanceMap = elementMap.get(element); + + // make it clear we only want one instance per element + // can be removed later when multiple key/instances are fine to be used + if (!instanceMap.has(key) && instanceMap.size !== 0) { + // eslint-disable-next-line no-console + console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`); + return; + } + instanceMap.set(key, instance); + }, + get(element, key) { + if (elementMap.has(element)) { + return elementMap.get(element).get(key) || null; + } + return null; + }, + remove(element, key) { + if (!elementMap.has(element)) { + return; + } + const instanceMap = elementMap.get(element); + instanceMap.delete(key); + + // free up element references if there are no instances left for an element + if (instanceMap.size === 0) { + elementMap.delete(element); + } + } + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/index.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const MAX_UID = 1000000; + const MILLISECONDS_MULTIPLIER = 1000; + const TRANSITION_END = 'transitionend'; + + /** + * Properly escape IDs selectors to handle weird IDs + * @param {string} selector + * @returns {string} + */ + const parseSelector = selector => { + if (selector && window.CSS && window.CSS.escape) { + // document.querySelector needs escaping to handle IDs (html5+) containing for instance / + selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`); + } + return selector; + }; + + // Shout-out Angus Croll (https://goo.gl/pxwQGp) + const toType = object => { + if (object === null || object === undefined) { + return `${object}`; + } + return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)[1].toLowerCase(); + }; + + /** + * Public Util API + */ + + const getUID = prefix => { + do { + prefix += Math.floor(Math.random() * MAX_UID); + } while (document.getElementById(prefix)); + return prefix; + }; + const getTransitionDurationFromElement = element => { + if (!element) { + return 0; + } + + // Get transition-duration of the element + let { + transitionDuration, + transitionDelay + } = window.getComputedStyle(element); + const floatTransitionDuration = Number.parseFloat(transitionDuration); + const floatTransitionDelay = Number.parseFloat(transitionDelay); + + // Return 0 if element or transition duration is not found + if (!floatTransitionDuration && !floatTransitionDelay) { + return 0; + } + + // If multiple durations are defined, take the first + transitionDuration = transitionDuration.split(',')[0]; + transitionDelay = transitionDelay.split(',')[0]; + return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER; + }; + const triggerTransitionEnd = element => { + element.dispatchEvent(new Event(TRANSITION_END)); + }; + const isElement = object => { + if (!object || typeof object !== 'object') { + return false; + } + if (typeof object.jquery !== 'undefined') { + object = object[0]; + } + return typeof object.nodeType !== 'undefined'; + }; + const getElement = object => { + // it's a jQuery object or a node element + if (isElement(object)) { + return object.jquery ? object[0] : object; + } + if (typeof object === 'string' && object.length > 0) { + return document.querySelector(parseSelector(object)); + } + return null; + }; + const isVisible = element => { + if (!isElement(element) || element.getClientRects().length === 0) { + return false; + } + const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'; + // Handle `details` element as its content may falsie appear visible when it is closed + const closedDetails = element.closest('details:not([open])'); + if (!closedDetails) { + return elementIsVisible; + } + if (closedDetails !== element) { + const summary = element.closest('summary'); + if (summary && summary.parentNode !== closedDetails) { + return false; + } + if (summary === null) { + return false; + } + } + return elementIsVisible; + }; + const isDisabled = element => { + if (!element || element.nodeType !== Node.ELEMENT_NODE) { + return true; + } + if (element.classList.contains('disabled')) { + return true; + } + if (typeof element.disabled !== 'undefined') { + return element.disabled; + } + return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'; + }; + const findShadowRoot = element => { + if (!document.documentElement.attachShadow) { + return null; + } + + // Can find the shadow root otherwise it'll return the document + if (typeof element.getRootNode === 'function') { + const root = element.getRootNode(); + return root instanceof ShadowRoot ? root : null; + } + if (element instanceof ShadowRoot) { + return element; + } + + // when we don't find a shadow root + if (!element.parentNode) { + return null; + } + return findShadowRoot(element.parentNode); + }; + const noop = () => {}; + + /** + * Trick to restart an element's animation + * + * @param {HTMLElement} element + * @return void + * + * @see https://www.harrytheo.com/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation + */ + const reflow = element => { + element.offsetHeight; // eslint-disable-line no-unused-expressions + }; + const getjQuery = () => { + if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) { + return window.jQuery; + } + return null; + }; + const DOMContentLoadedCallbacks = []; + const onDOMContentLoaded = callback => { + if (document.readyState === 'loading') { + // add listener on the first call when the document is in loading state + if (!DOMContentLoadedCallbacks.length) { + document.addEventListener('DOMContentLoaded', () => { + for (const callback of DOMContentLoadedCallbacks) { + callback(); + } + }); + } + DOMContentLoadedCallbacks.push(callback); + } else { + callback(); + } + }; + const isRTL = () => document.documentElement.dir === 'rtl'; + const defineJQueryPlugin = plugin => { + onDOMContentLoaded(() => { + const $ = getjQuery(); + /* istanbul ignore if */ + if ($) { + const name = plugin.NAME; + const JQUERY_NO_CONFLICT = $.fn[name]; + $.fn[name] = plugin.jQueryInterface; + $.fn[name].Constructor = plugin; + $.fn[name].noConflict = () => { + $.fn[name] = JQUERY_NO_CONFLICT; + return plugin.jQueryInterface; + }; + } + }); + }; + const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => { + return typeof possibleCallback === 'function' ? possibleCallback.call(...args) : defaultValue; + }; + const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => { + if (!waitForTransition) { + execute(callback); + return; + } + const durationPadding = 5; + const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding; + let called = false; + const handler = ({ + target + }) => { + if (target !== transitionElement) { + return; + } + called = true; + transitionElement.removeEventListener(TRANSITION_END, handler); + execute(callback); + }; + transitionElement.addEventListener(TRANSITION_END, handler); + setTimeout(() => { + if (!called) { + triggerTransitionEnd(transitionElement); + } + }, emulatedDuration); + }; + + /** + * Return the previous/next element of a list. + * + * @param {array} list The list of elements + * @param activeElement The active element + * @param shouldGetNext Choose to get next or previous element + * @param isCycleAllowed + * @return {Element|elem} The proper element + */ + const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => { + const listLength = list.length; + let index = list.indexOf(activeElement); + + // if the element does not exist in the list return an element + // depending on the direction and if cycle is allowed + if (index === -1) { + return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]; + } + index += shouldGetNext ? 1 : -1; + if (isCycleAllowed) { + index = (index + listLength) % listLength; + } + return list[Math.max(0, Math.min(index, listLength - 1))]; + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/event-handler.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const namespaceRegex = /[^.]*(?=\..*)\.|.*/; + const stripNameRegex = /\..*/; + const stripUidRegex = /::\d+$/; + const eventRegistry = {}; // Events storage + let uidEvent = 1; + const customEvents = { + mouseenter: 'mouseover', + mouseleave: 'mouseout' + }; + const nativeEvents = new Set(['click', 'dblclick', 'mouseup', 'mousedown', 'contextmenu', 'mousewheel', 'DOMMouseScroll', 'mouseover', 'mouseout', 'mousemove', 'selectstart', 'selectend', 'keydown', 'keypress', 'keyup', 'orientationchange', 'touchstart', 'touchmove', 'touchend', 'touchcancel', 'pointerdown', 'pointermove', 'pointerup', 'pointerleave', 'pointercancel', 'gesturestart', 'gesturechange', 'gestureend', 'focus', 'blur', 'change', 'reset', 'select', 'submit', 'focusin', 'focusout', 'load', 'unload', 'beforeunload', 'resize', 'move', 'DOMContentLoaded', 'readystatechange', 'error', 'abort', 'scroll']); + + /** + * Private methods + */ + + function makeEventUid(element, uid) { + return uid && `${uid}::${uidEvent++}` || element.uidEvent || uidEvent++; + } + function getElementEvents(element) { + const uid = makeEventUid(element); + element.uidEvent = uid; + eventRegistry[uid] = eventRegistry[uid] || {}; + return eventRegistry[uid]; + } + function bootstrapHandler(element, fn) { + return function handler(event) { + hydrateObj(event, { + delegateTarget: element + }); + if (handler.oneOff) { + EventHandler.off(element, event.type, fn); + } + return fn.apply(element, [event]); + }; + } + function bootstrapDelegationHandler(element, selector, fn) { + return function handler(event) { + const domElements = element.querySelectorAll(selector); + for (let { + target + } = event; target && target !== this; target = target.parentNode) { + for (const domElement of domElements) { + if (domElement !== target) { + continue; + } + hydrateObj(event, { + delegateTarget: target + }); + if (handler.oneOff) { + EventHandler.off(element, event.type, selector, fn); + } + return fn.apply(target, [event]); + } + } + }; + } + function findHandler(events, callable, delegationSelector = null) { + return Object.values(events).find(event => event.callable === callable && event.delegationSelector === delegationSelector); + } + function normalizeParameters(originalTypeEvent, handler, delegationFunction) { + const isDelegated = typeof handler === 'string'; + // TODO: tooltip passes `false` instead of selector, so we need to check + const callable = isDelegated ? delegationFunction : handler || delegationFunction; + let typeEvent = getTypeEvent(originalTypeEvent); + if (!nativeEvents.has(typeEvent)) { + typeEvent = originalTypeEvent; + } + return [isDelegated, callable, typeEvent]; + } + function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) { + if (typeof originalTypeEvent !== 'string' || !element) { + return; + } + let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction); + + // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position + // this prevents the handler from being dispatched the same way as mouseover or mouseout does + if (originalTypeEvent in customEvents) { + const wrapFunction = fn => { + return function (event) { + if (!event.relatedTarget || event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget)) { + return fn.call(this, event); + } + }; + }; + callable = wrapFunction(callable); + } + const events = getElementEvents(element); + const handlers = events[typeEvent] || (events[typeEvent] = {}); + const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null); + if (previousFunction) { + previousFunction.oneOff = previousFunction.oneOff && oneOff; + return; + } + const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, '')); + const fn = isDelegated ? bootstrapDelegationHandler(element, handler, callable) : bootstrapHandler(element, callable); + fn.delegationSelector = isDelegated ? handler : null; + fn.callable = callable; + fn.oneOff = oneOff; + fn.uidEvent = uid; + handlers[uid] = fn; + element.addEventListener(typeEvent, fn, isDelegated); + } + function removeHandler(element, events, typeEvent, handler, delegationSelector) { + const fn = findHandler(events[typeEvent], handler, delegationSelector); + if (!fn) { + return; + } + element.removeEventListener(typeEvent, fn, Boolean(delegationSelector)); + delete events[typeEvent][fn.uidEvent]; + } + function removeNamespacedHandlers(element, events, typeEvent, namespace) { + const storeElementEvent = events[typeEvent] || {}; + for (const [handlerKey, event] of Object.entries(storeElementEvent)) { + if (handlerKey.includes(namespace)) { + removeHandler(element, events, typeEvent, event.callable, event.delegationSelector); + } + } + } + function getTypeEvent(event) { + // allow to get the native events from namespaced events ('click.bs.button' --> 'click') + event = event.replace(stripNameRegex, ''); + return customEvents[event] || event; + } + const EventHandler = { + on(element, event, handler, delegationFunction) { + addHandler(element, event, handler, delegationFunction, false); + }, + one(element, event, handler, delegationFunction) { + addHandler(element, event, handler, delegationFunction, true); + }, + off(element, originalTypeEvent, handler, delegationFunction) { + if (typeof originalTypeEvent !== 'string' || !element) { + return; + } + const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction); + const inNamespace = typeEvent !== originalTypeEvent; + const events = getElementEvents(element); + const storeElementEvent = events[typeEvent] || {}; + const isNamespace = originalTypeEvent.startsWith('.'); + if (typeof callable !== 'undefined') { + // Simplest case: handler is passed, remove that listener ONLY. + if (!Object.keys(storeElementEvent).length) { + return; + } + removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null); + return; + } + if (isNamespace) { + for (const elementEvent of Object.keys(events)) { + removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1)); + } + } + for (const [keyHandlers, event] of Object.entries(storeElementEvent)) { + const handlerKey = keyHandlers.replace(stripUidRegex, ''); + if (!inNamespace || originalTypeEvent.includes(handlerKey)) { + removeHandler(element, events, typeEvent, event.callable, event.delegationSelector); + } + } + }, + trigger(element, event, args) { + if (typeof event !== 'string' || !element) { + return null; + } + const $ = getjQuery(); + const typeEvent = getTypeEvent(event); + const inNamespace = event !== typeEvent; + let jQueryEvent = null; + let bubbles = true; + let nativeDispatch = true; + let defaultPrevented = false; + if (inNamespace && $) { + jQueryEvent = $.Event(event, args); + $(element).trigger(jQueryEvent); + bubbles = !jQueryEvent.isPropagationStopped(); + nativeDispatch = !jQueryEvent.isImmediatePropagationStopped(); + defaultPrevented = jQueryEvent.isDefaultPrevented(); + } + const evt = hydrateObj(new Event(event, { + bubbles, + cancelable: true + }), args); + if (defaultPrevented) { + evt.preventDefault(); + } + if (nativeDispatch) { + element.dispatchEvent(evt); + } + if (evt.defaultPrevented && jQueryEvent) { + jQueryEvent.preventDefault(); + } + return evt; + } + }; + function hydrateObj(obj, meta = {}) { + for (const [key, value] of Object.entries(meta)) { + try { + obj[key] = value; + } catch (_unused) { + Object.defineProperty(obj, key, { + configurable: true, + get() { + return value; + } + }); + } + } + return obj; + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/manipulator.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + function normalizeData(value) { + if (value === 'true') { + return true; + } + if (value === 'false') { + return false; + } + if (value === Number(value).toString()) { + return Number(value); + } + if (value === '' || value === 'null') { + return null; + } + if (typeof value !== 'string') { + return value; + } + try { + return JSON.parse(decodeURIComponent(value)); + } catch (_unused) { + return value; + } + } + function normalizeDataKey(key) { + return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`); + } + const Manipulator = { + setDataAttribute(element, key, value) { + element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value); + }, + removeDataAttribute(element, key) { + element.removeAttribute(`data-bs-${normalizeDataKey(key)}`); + }, + getDataAttributes(element) { + if (!element) { + return {}; + } + const attributes = {}; + const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig')); + for (const key of bsKeys) { + let pureKey = key.replace(/^bs/, ''); + pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1); + attributes[pureKey] = normalizeData(element.dataset[key]); + } + return attributes; + }, + getDataAttribute(element, key) { + return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`)); + } + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/config.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Class definition + */ + + class Config { + // Getters + static get Default() { + return {}; + } + static get DefaultType() { + return {}; + } + static get NAME() { + throw new Error('You have to implement the static method "NAME", for each component!'); + } + _getConfig(config) { + config = this._mergeConfigObj(config); + config = this._configAfterMerge(config); + this._typeCheckConfig(config); + return config; + } + _configAfterMerge(config) { + return config; + } + _mergeConfigObj(config, element) { + const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse + + return { + ...this.constructor.Default, + ...(typeof jsonConfig === 'object' ? jsonConfig : {}), + ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}), + ...(typeof config === 'object' ? config : {}) + }; + } + _typeCheckConfig(config, configTypes = this.constructor.DefaultType) { + for (const [property, expectedTypes] of Object.entries(configTypes)) { + const value = config[property]; + const valueType = isElement(value) ? 'element' : toType(value); + if (!new RegExp(expectedTypes).test(valueType)) { + throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`); + } + } + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap base-component.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const VERSION = '5.3.8'; + + /** + * Class definition + */ + + class BaseComponent extends Config { + constructor(element, config) { + super(); + element = getElement(element); + if (!element) { + return; + } + this._element = element; + this._config = this._getConfig(config); + Data.set(this._element, this.constructor.DATA_KEY, this); + } + + // Public + dispose() { + Data.remove(this._element, this.constructor.DATA_KEY); + EventHandler.off(this._element, this.constructor.EVENT_KEY); + for (const propertyName of Object.getOwnPropertyNames(this)) { + this[propertyName] = null; + } + } + + // Private + _queueCallback(callback, element, isAnimated = true) { + executeAfterTransition(callback, element, isAnimated); + } + _getConfig(config) { + config = this._mergeConfigObj(config, this._element); + config = this._configAfterMerge(config); + this._typeCheckConfig(config); + return config; + } + + // Static + static getInstance(element) { + return Data.get(getElement(element), this.DATA_KEY); + } + static getOrCreateInstance(element, config = {}) { + return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null); + } + static get VERSION() { + return VERSION; + } + static get DATA_KEY() { + return `bs.${this.NAME}`; + } + static get EVENT_KEY() { + return `.${this.DATA_KEY}`; + } + static eventName(name) { + return `${name}${this.EVENT_KEY}`; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap dom/selector-engine.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const getSelector = element => { + let selector = element.getAttribute('data-bs-target'); + if (!selector || selector === '#') { + let hrefAttribute = element.getAttribute('href'); + + // The only valid content that could double as a selector are IDs or classes, + // so everything starting with `#` or `.`. If a "real" URL is used as the selector, + // `document.querySelector` will rightfully complain it is invalid. + // See https://github.com/twbs/bootstrap/issues/32273 + if (!hrefAttribute || !hrefAttribute.includes('#') && !hrefAttribute.startsWith('.')) { + return null; + } + + // Just in case some CMS puts out a full URL with the anchor appended + if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) { + hrefAttribute = `#${hrefAttribute.split('#')[1]}`; + } + selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null; + } + return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null; + }; + const SelectorEngine = { + find(selector, element = document.documentElement) { + return [].concat(...Element.prototype.querySelectorAll.call(element, selector)); + }, + findOne(selector, element = document.documentElement) { + return Element.prototype.querySelector.call(element, selector); + }, + children(element, selector) { + return [].concat(...element.children).filter(child => child.matches(selector)); + }, + parents(element, selector) { + const parents = []; + let ancestor = element.parentNode.closest(selector); + while (ancestor) { + parents.push(ancestor); + ancestor = ancestor.parentNode.closest(selector); + } + return parents; + }, + prev(element, selector) { + let previous = element.previousElementSibling; + while (previous) { + if (previous.matches(selector)) { + return [previous]; + } + previous = previous.previousElementSibling; + } + return []; + }, + // TODO: this is now unused; remove later along with prev() + next(element, selector) { + let next = element.nextElementSibling; + while (next) { + if (next.matches(selector)) { + return [next]; + } + next = next.nextElementSibling; + } + return []; + }, + focusableChildren(element) { + const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector => `${selector}:not([tabindex^="-"])`).join(','); + return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el)); + }, + getSelectorFromElement(element) { + const selector = getSelector(element); + if (selector) { + return SelectorEngine.findOne(selector) ? selector : null; + } + return null; + }, + getElementFromSelector(element) { + const selector = getSelector(element); + return selector ? SelectorEngine.findOne(selector) : null; + }, + getMultipleElementsFromSelector(element) { + const selector = getSelector(element); + return selector ? SelectorEngine.find(selector) : []; + } + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/component-functions.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const enableDismissTrigger = (component, method = 'hide') => { + const clickEvent = `click.dismiss${component.EVENT_KEY}`; + const name = component.NAME; + EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) { + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + if (isDisabled(this)) { + return; + } + const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`); + const instance = component.getOrCreateInstance(target); + + // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method + instance[method](); + }); + }; + + /** + * -------------------------------------------------------------------------- + * Bootstrap alert.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$f = 'alert'; + const DATA_KEY$a = 'bs.alert'; + const EVENT_KEY$b = `.${DATA_KEY$a}`; + const EVENT_CLOSE = `close${EVENT_KEY$b}`; + const EVENT_CLOSED = `closed${EVENT_KEY$b}`; + const CLASS_NAME_FADE$5 = 'fade'; + const CLASS_NAME_SHOW$8 = 'show'; + + /** + * Class definition + */ + + class Alert extends BaseComponent { + // Getters + static get NAME() { + return NAME$f; + } + + // Public + close() { + const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE); + if (closeEvent.defaultPrevented) { + return; + } + this._element.classList.remove(CLASS_NAME_SHOW$8); + const isAnimated = this._element.classList.contains(CLASS_NAME_FADE$5); + this._queueCallback(() => this._destroyElement(), this._element, isAnimated); + } + + // Private + _destroyElement() { + this._element.remove(); + EventHandler.trigger(this._element, EVENT_CLOSED); + this.dispose(); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Alert.getOrCreateInstance(this); + if (typeof config !== 'string') { + return; + } + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](this); + }); + } + } + + /** + * Data API implementation + */ + + enableDismissTrigger(Alert, 'close'); + + /** + * jQuery + */ + + defineJQueryPlugin(Alert); + + /** + * -------------------------------------------------------------------------- + * Bootstrap button.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$e = 'button'; + const DATA_KEY$9 = 'bs.button'; + const EVENT_KEY$a = `.${DATA_KEY$9}`; + const DATA_API_KEY$6 = '.data-api'; + const CLASS_NAME_ACTIVE$3 = 'active'; + const SELECTOR_DATA_TOGGLE$5 = '[data-bs-toggle="button"]'; + const EVENT_CLICK_DATA_API$6 = `click${EVENT_KEY$a}${DATA_API_KEY$6}`; + + /** + * Class definition + */ + + class Button extends BaseComponent { + // Getters + static get NAME() { + return NAME$e; + } + + // Public + toggle() { + // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method + this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE$3)); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Button.getOrCreateInstance(this); + if (config === 'toggle') { + data[config](); + } + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$6, SELECTOR_DATA_TOGGLE$5, event => { + event.preventDefault(); + const button = event.target.closest(SELECTOR_DATA_TOGGLE$5); + const data = Button.getOrCreateInstance(button); + data.toggle(); + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Button); + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/swipe.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$d = 'swipe'; + const EVENT_KEY$9 = '.bs.swipe'; + const EVENT_TOUCHSTART = `touchstart${EVENT_KEY$9}`; + const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY$9}`; + const EVENT_TOUCHEND = `touchend${EVENT_KEY$9}`; + const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY$9}`; + const EVENT_POINTERUP = `pointerup${EVENT_KEY$9}`; + const POINTER_TYPE_TOUCH = 'touch'; + const POINTER_TYPE_PEN = 'pen'; + const CLASS_NAME_POINTER_EVENT = 'pointer-event'; + const SWIPE_THRESHOLD = 40; + const Default$c = { + endCallback: null, + leftCallback: null, + rightCallback: null + }; + const DefaultType$c = { + endCallback: '(function|null)', + leftCallback: '(function|null)', + rightCallback: '(function|null)' + }; + + /** + * Class definition + */ + + class Swipe extends Config { + constructor(element, config) { + super(); + this._element = element; + if (!element || !Swipe.isSupported()) { + return; + } + this._config = this._getConfig(config); + this._deltaX = 0; + this._supportPointerEvents = Boolean(window.PointerEvent); + this._initEvents(); + } + + // Getters + static get Default() { + return Default$c; + } + static get DefaultType() { + return DefaultType$c; + } + static get NAME() { + return NAME$d; + } + + // Public + dispose() { + EventHandler.off(this._element, EVENT_KEY$9); + } + + // Private + _start(event) { + if (!this._supportPointerEvents) { + this._deltaX = event.touches[0].clientX; + return; + } + if (this._eventIsPointerPenTouch(event)) { + this._deltaX = event.clientX; + } + } + _end(event) { + if (this._eventIsPointerPenTouch(event)) { + this._deltaX = event.clientX - this._deltaX; + } + this._handleSwipe(); + execute(this._config.endCallback); + } + _move(event) { + this._deltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this._deltaX; + } + _handleSwipe() { + const absDeltaX = Math.abs(this._deltaX); + if (absDeltaX <= SWIPE_THRESHOLD) { + return; + } + const direction = absDeltaX / this._deltaX; + this._deltaX = 0; + if (!direction) { + return; + } + execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback); + } + _initEvents() { + if (this._supportPointerEvents) { + EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event)); + EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event)); + this._element.classList.add(CLASS_NAME_POINTER_EVENT); + } else { + EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event)); + EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event)); + EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event)); + } + } + _eventIsPointerPenTouch(event) { + return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH); + } + + // Static + static isSupported() { + return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap carousel.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$c = 'carousel'; + const DATA_KEY$8 = 'bs.carousel'; + const EVENT_KEY$8 = `.${DATA_KEY$8}`; + const DATA_API_KEY$5 = '.data-api'; + const ARROW_LEFT_KEY$1 = 'ArrowLeft'; + const ARROW_RIGHT_KEY$1 = 'ArrowRight'; + const TOUCHEVENT_COMPAT_WAIT = 500; // Time for mouse compat events to fire after touch + + const ORDER_NEXT = 'next'; + const ORDER_PREV = 'prev'; + const DIRECTION_LEFT = 'left'; + const DIRECTION_RIGHT = 'right'; + const EVENT_SLIDE = `slide${EVENT_KEY$8}`; + const EVENT_SLID = `slid${EVENT_KEY$8}`; + const EVENT_KEYDOWN$1 = `keydown${EVENT_KEY$8}`; + const EVENT_MOUSEENTER$1 = `mouseenter${EVENT_KEY$8}`; + const EVENT_MOUSELEAVE$1 = `mouseleave${EVENT_KEY$8}`; + const EVENT_DRAG_START = `dragstart${EVENT_KEY$8}`; + const EVENT_LOAD_DATA_API$3 = `load${EVENT_KEY$8}${DATA_API_KEY$5}`; + const EVENT_CLICK_DATA_API$5 = `click${EVENT_KEY$8}${DATA_API_KEY$5}`; + const CLASS_NAME_CAROUSEL = 'carousel'; + const CLASS_NAME_ACTIVE$2 = 'active'; + const CLASS_NAME_SLIDE = 'slide'; + const CLASS_NAME_END = 'carousel-item-end'; + const CLASS_NAME_START = 'carousel-item-start'; + const CLASS_NAME_NEXT = 'carousel-item-next'; + const CLASS_NAME_PREV = 'carousel-item-prev'; + const SELECTOR_ACTIVE = '.active'; + const SELECTOR_ITEM = '.carousel-item'; + const SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM; + const SELECTOR_ITEM_IMG = '.carousel-item img'; + const SELECTOR_INDICATORS = '.carousel-indicators'; + const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'; + const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]'; + const KEY_TO_DIRECTION = { + [ARROW_LEFT_KEY$1]: DIRECTION_RIGHT, + [ARROW_RIGHT_KEY$1]: DIRECTION_LEFT + }; + const Default$b = { + interval: 5000, + keyboard: true, + pause: 'hover', + ride: false, + touch: true, + wrap: true + }; + const DefaultType$b = { + interval: '(number|boolean)', + // TODO:v6 remove boolean support + keyboard: 'boolean', + pause: '(string|boolean)', + ride: '(boolean|string)', + touch: 'boolean', + wrap: 'boolean' + }; + + /** + * Class definition + */ + + class Carousel extends BaseComponent { + constructor(element, config) { + super(element, config); + this._interval = null; + this._activeElement = null; + this._isSliding = false; + this.touchTimeout = null; + this._swipeHelper = null; + this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element); + this._addEventListeners(); + if (this._config.ride === CLASS_NAME_CAROUSEL) { + this.cycle(); + } + } + + // Getters + static get Default() { + return Default$b; + } + static get DefaultType() { + return DefaultType$b; + } + static get NAME() { + return NAME$c; + } + + // Public + next() { + this._slide(ORDER_NEXT); + } + nextWhenVisible() { + // FIXME TODO use `document.visibilityState` + // Don't call next when the page isn't visible + // or the carousel or its parent isn't visible + if (!document.hidden && isVisible(this._element)) { + this.next(); + } + } + prev() { + this._slide(ORDER_PREV); + } + pause() { + if (this._isSliding) { + triggerTransitionEnd(this._element); + } + this._clearInterval(); + } + cycle() { + this._clearInterval(); + this._updateInterval(); + this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval); + } + _maybeEnableCycle() { + if (!this._config.ride) { + return; + } + if (this._isSliding) { + EventHandler.one(this._element, EVENT_SLID, () => this.cycle()); + return; + } + this.cycle(); + } + to(index) { + const items = this._getItems(); + if (index > items.length - 1 || index < 0) { + return; + } + if (this._isSliding) { + EventHandler.one(this._element, EVENT_SLID, () => this.to(index)); + return; + } + const activeIndex = this._getItemIndex(this._getActive()); + if (activeIndex === index) { + return; + } + const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV; + this._slide(order, items[index]); + } + dispose() { + if (this._swipeHelper) { + this._swipeHelper.dispose(); + } + super.dispose(); + } + + // Private + _configAfterMerge(config) { + config.defaultInterval = config.interval; + return config; + } + _addEventListeners() { + if (this._config.keyboard) { + EventHandler.on(this._element, EVENT_KEYDOWN$1, event => this._keydown(event)); + } + if (this._config.pause === 'hover') { + EventHandler.on(this._element, EVENT_MOUSEENTER$1, () => this.pause()); + EventHandler.on(this._element, EVENT_MOUSELEAVE$1, () => this._maybeEnableCycle()); + } + if (this._config.touch && Swipe.isSupported()) { + this._addTouchEventListeners(); + } + } + _addTouchEventListeners() { + for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) { + EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault()); + } + const endCallBack = () => { + if (this._config.pause !== 'hover') { + return; + } + + // If it's a touch-enabled device, mouseenter/leave are fired as + // part of the mouse compatibility events on first tap - the carousel + // would stop cycling until user tapped out of it; + // here, we listen for touchend, explicitly pause the carousel + // (as if it's the second time we tap on it, mouseenter compat event + // is NOT fired) and after a timeout (to allow for mouse compatibility + // events to fire) we explicitly restart cycling + + this.pause(); + if (this.touchTimeout) { + clearTimeout(this.touchTimeout); + } + this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval); + }; + const swipeConfig = { + leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)), + rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)), + endCallback: endCallBack + }; + this._swipeHelper = new Swipe(this._element, swipeConfig); + } + _keydown(event) { + if (/input|textarea/i.test(event.target.tagName)) { + return; + } + const direction = KEY_TO_DIRECTION[event.key]; + if (direction) { + event.preventDefault(); + this._slide(this._directionToOrder(direction)); + } + } + _getItemIndex(element) { + return this._getItems().indexOf(element); + } + _setActiveIndicatorElement(index) { + if (!this._indicatorsElement) { + return; + } + const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement); + activeIndicator.classList.remove(CLASS_NAME_ACTIVE$2); + activeIndicator.removeAttribute('aria-current'); + const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to="${index}"]`, this._indicatorsElement); + if (newActiveIndicator) { + newActiveIndicator.classList.add(CLASS_NAME_ACTIVE$2); + newActiveIndicator.setAttribute('aria-current', 'true'); + } + } + _updateInterval() { + const element = this._activeElement || this._getActive(); + if (!element) { + return; + } + const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10); + this._config.interval = elementInterval || this._config.defaultInterval; + } + _slide(order, element = null) { + if (this._isSliding) { + return; + } + const activeElement = this._getActive(); + const isNext = order === ORDER_NEXT; + const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap); + if (nextElement === activeElement) { + return; + } + const nextElementIndex = this._getItemIndex(nextElement); + const triggerEvent = eventName => { + return EventHandler.trigger(this._element, eventName, { + relatedTarget: nextElement, + direction: this._orderToDirection(order), + from: this._getItemIndex(activeElement), + to: nextElementIndex + }); + }; + const slideEvent = triggerEvent(EVENT_SLIDE); + if (slideEvent.defaultPrevented) { + return; + } + if (!activeElement || !nextElement) { + // Some weirdness is happening, so we bail + // TODO: change tests that use empty divs to avoid this check + return; + } + const isCycling = Boolean(this._interval); + this.pause(); + this._isSliding = true; + this._setActiveIndicatorElement(nextElementIndex); + this._activeElement = nextElement; + const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END; + const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV; + nextElement.classList.add(orderClassName); + reflow(nextElement); + activeElement.classList.add(directionalClassName); + nextElement.classList.add(directionalClassName); + const completeCallBack = () => { + nextElement.classList.remove(directionalClassName, orderClassName); + nextElement.classList.add(CLASS_NAME_ACTIVE$2); + activeElement.classList.remove(CLASS_NAME_ACTIVE$2, orderClassName, directionalClassName); + this._isSliding = false; + triggerEvent(EVENT_SLID); + }; + this._queueCallback(completeCallBack, activeElement, this._isAnimated()); + if (isCycling) { + this.cycle(); + } + } + _isAnimated() { + return this._element.classList.contains(CLASS_NAME_SLIDE); + } + _getActive() { + return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element); + } + _getItems() { + return SelectorEngine.find(SELECTOR_ITEM, this._element); + } + _clearInterval() { + if (this._interval) { + clearInterval(this._interval); + this._interval = null; + } + } + _directionToOrder(direction) { + if (isRTL()) { + return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT; + } + return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV; + } + _orderToDirection(order) { + if (isRTL()) { + return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT; + } + return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT; + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Carousel.getOrCreateInstance(this, config); + if (typeof config === 'number') { + data.to(config); + return; + } + if (typeof config === 'string') { + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + } + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$5, SELECTOR_DATA_SLIDE, function (event) { + const target = SelectorEngine.getElementFromSelector(this); + if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) { + return; + } + event.preventDefault(); + const carousel = Carousel.getOrCreateInstance(target); + const slideIndex = this.getAttribute('data-bs-slide-to'); + if (slideIndex) { + carousel.to(slideIndex); + carousel._maybeEnableCycle(); + return; + } + if (Manipulator.getDataAttribute(this, 'slide') === 'next') { + carousel.next(); + carousel._maybeEnableCycle(); + return; + } + carousel.prev(); + carousel._maybeEnableCycle(); + }); + EventHandler.on(window, EVENT_LOAD_DATA_API$3, () => { + const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE); + for (const carousel of carousels) { + Carousel.getOrCreateInstance(carousel); + } + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Carousel); + + /** + * -------------------------------------------------------------------------- + * Bootstrap collapse.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$b = 'collapse'; + const DATA_KEY$7 = 'bs.collapse'; + const EVENT_KEY$7 = `.${DATA_KEY$7}`; + const DATA_API_KEY$4 = '.data-api'; + const EVENT_SHOW$6 = `show${EVENT_KEY$7}`; + const EVENT_SHOWN$6 = `shown${EVENT_KEY$7}`; + const EVENT_HIDE$6 = `hide${EVENT_KEY$7}`; + const EVENT_HIDDEN$6 = `hidden${EVENT_KEY$7}`; + const EVENT_CLICK_DATA_API$4 = `click${EVENT_KEY$7}${DATA_API_KEY$4}`; + const CLASS_NAME_SHOW$7 = 'show'; + const CLASS_NAME_COLLAPSE = 'collapse'; + const CLASS_NAME_COLLAPSING = 'collapsing'; + const CLASS_NAME_COLLAPSED = 'collapsed'; + const CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`; + const CLASS_NAME_HORIZONTAL = 'collapse-horizontal'; + const WIDTH = 'width'; + const HEIGHT = 'height'; + const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'; + const SELECTOR_DATA_TOGGLE$4 = '[data-bs-toggle="collapse"]'; + const Default$a = { + parent: null, + toggle: true + }; + const DefaultType$a = { + parent: '(null|element)', + toggle: 'boolean' + }; + + /** + * Class definition + */ + + class Collapse extends BaseComponent { + constructor(element, config) { + super(element, config); + this._isTransitioning = false; + this._triggerArray = []; + const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE$4); + for (const elem of toggleList) { + const selector = SelectorEngine.getSelectorFromElement(elem); + const filterElement = SelectorEngine.find(selector).filter(foundElement => foundElement === this._element); + if (selector !== null && filterElement.length) { + this._triggerArray.push(elem); + } + } + this._initializeChildren(); + if (!this._config.parent) { + this._addAriaAndCollapsedClass(this._triggerArray, this._isShown()); + } + if (this._config.toggle) { + this.toggle(); + } + } + + // Getters + static get Default() { + return Default$a; + } + static get DefaultType() { + return DefaultType$a; + } + static get NAME() { + return NAME$b; + } + + // Public + toggle() { + if (this._isShown()) { + this.hide(); + } else { + this.show(); + } + } + show() { + if (this._isTransitioning || this._isShown()) { + return; + } + let activeChildren = []; + + // find active children + if (this._config.parent) { + activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES).filter(element => element !== this._element).map(element => Collapse.getOrCreateInstance(element, { + toggle: false + })); + } + if (activeChildren.length && activeChildren[0]._isTransitioning) { + return; + } + const startEvent = EventHandler.trigger(this._element, EVENT_SHOW$6); + if (startEvent.defaultPrevented) { + return; + } + for (const activeInstance of activeChildren) { + activeInstance.hide(); + } + const dimension = this._getDimension(); + this._element.classList.remove(CLASS_NAME_COLLAPSE); + this._element.classList.add(CLASS_NAME_COLLAPSING); + this._element.style[dimension] = 0; + this._addAriaAndCollapsedClass(this._triggerArray, true); + this._isTransitioning = true; + const complete = () => { + this._isTransitioning = false; + this._element.classList.remove(CLASS_NAME_COLLAPSING); + this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7); + this._element.style[dimension] = ''; + EventHandler.trigger(this._element, EVENT_SHOWN$6); + }; + const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1); + const scrollSize = `scroll${capitalizedDimension}`; + this._queueCallback(complete, this._element, true); + this._element.style[dimension] = `${this._element[scrollSize]}px`; + } + hide() { + if (this._isTransitioning || !this._isShown()) { + return; + } + const startEvent = EventHandler.trigger(this._element, EVENT_HIDE$6); + if (startEvent.defaultPrevented) { + return; + } + const dimension = this._getDimension(); + this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`; + reflow(this._element); + this._element.classList.add(CLASS_NAME_COLLAPSING); + this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW$7); + for (const trigger of this._triggerArray) { + const element = SelectorEngine.getElementFromSelector(trigger); + if (element && !this._isShown(element)) { + this._addAriaAndCollapsedClass([trigger], false); + } + } + this._isTransitioning = true; + const complete = () => { + this._isTransitioning = false; + this._element.classList.remove(CLASS_NAME_COLLAPSING); + this._element.classList.add(CLASS_NAME_COLLAPSE); + EventHandler.trigger(this._element, EVENT_HIDDEN$6); + }; + this._element.style[dimension] = ''; + this._queueCallback(complete, this._element, true); + } + + // Private + _isShown(element = this._element) { + return element.classList.contains(CLASS_NAME_SHOW$7); + } + _configAfterMerge(config) { + config.toggle = Boolean(config.toggle); // Coerce string values + config.parent = getElement(config.parent); + return config; + } + _getDimension() { + return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT; + } + _initializeChildren() { + if (!this._config.parent) { + return; + } + const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE$4); + for (const element of children) { + const selected = SelectorEngine.getElementFromSelector(element); + if (selected) { + this._addAriaAndCollapsedClass([element], this._isShown(selected)); + } + } + } + _getFirstLevelChildren(selector) { + const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent); + // remove children if greater depth + return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element)); + } + _addAriaAndCollapsedClass(triggerArray, isOpen) { + if (!triggerArray.length) { + return; + } + for (const element of triggerArray) { + element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen); + element.setAttribute('aria-expanded', isOpen); + } + } + + // Static + static jQueryInterface(config) { + const _config = {}; + if (typeof config === 'string' && /show|hide/.test(config)) { + _config.toggle = false; + } + return this.each(function () { + const data = Collapse.getOrCreateInstance(this, _config); + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + } + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$4, SELECTOR_DATA_TOGGLE$4, function (event) { + // preventDefault only for <a> elements (which change the URL) not inside the collapsible element + if (event.target.tagName === 'A' || event.delegateTarget && event.delegateTarget.tagName === 'A') { + event.preventDefault(); + } + for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) { + Collapse.getOrCreateInstance(element, { + toggle: false + }).toggle(); + } + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Collapse); + + /** + * -------------------------------------------------------------------------- + * Bootstrap dropdown.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$a = 'dropdown'; + const DATA_KEY$6 = 'bs.dropdown'; + const EVENT_KEY$6 = `.${DATA_KEY$6}`; + const DATA_API_KEY$3 = '.data-api'; + const ESCAPE_KEY$2 = 'Escape'; + const TAB_KEY$1 = 'Tab'; + const ARROW_UP_KEY$1 = 'ArrowUp'; + const ARROW_DOWN_KEY$1 = 'ArrowDown'; + const RIGHT_MOUSE_BUTTON = 2; // MouseEvent.button value for the secondary button, usually the right button + + const EVENT_HIDE$5 = `hide${EVENT_KEY$6}`; + const EVENT_HIDDEN$5 = `hidden${EVENT_KEY$6}`; + const EVENT_SHOW$5 = `show${EVENT_KEY$6}`; + const EVENT_SHOWN$5 = `shown${EVENT_KEY$6}`; + const EVENT_CLICK_DATA_API$3 = `click${EVENT_KEY$6}${DATA_API_KEY$3}`; + const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY$6}${DATA_API_KEY$3}`; + const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY$6}${DATA_API_KEY$3}`; + const CLASS_NAME_SHOW$6 = 'show'; + const CLASS_NAME_DROPUP = 'dropup'; + const CLASS_NAME_DROPEND = 'dropend'; + const CLASS_NAME_DROPSTART = 'dropstart'; + const CLASS_NAME_DROPUP_CENTER = 'dropup-center'; + const CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'; + const SELECTOR_DATA_TOGGLE$3 = '[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)'; + const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE$3}.${CLASS_NAME_SHOW$6}`; + const SELECTOR_MENU = '.dropdown-menu'; + const SELECTOR_NAVBAR = '.navbar'; + const SELECTOR_NAVBAR_NAV = '.navbar-nav'; + const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'; + const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'; + const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'; + const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'; + const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'; + const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'; + const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'; + const PLACEMENT_TOPCENTER = 'top'; + const PLACEMENT_BOTTOMCENTER = 'bottom'; + const Default$9 = { + autoClose: true, + boundary: 'clippingParents', + display: 'dynamic', + offset: [0, 2], + popperConfig: null, + reference: 'toggle' + }; + const DefaultType$9 = { + autoClose: '(boolean|string)', + boundary: '(string|element)', + display: 'string', + offset: '(array|string|function)', + popperConfig: '(null|object|function)', + reference: '(string|element|object)' + }; + + /** + * Class definition + */ + + class Dropdown extends BaseComponent { + constructor(element, config) { + super(element, config); + this._popper = null; + this._parent = this._element.parentNode; // dropdown wrapper + // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/ + this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] || SelectorEngine.prev(this._element, SELECTOR_MENU)[0] || SelectorEngine.findOne(SELECTOR_MENU, this._parent); + this._inNavbar = this._detectNavbar(); + } + + // Getters + static get Default() { + return Default$9; + } + static get DefaultType() { + return DefaultType$9; + } + static get NAME() { + return NAME$a; + } + + // Public + toggle() { + return this._isShown() ? this.hide() : this.show(); + } + show() { + if (isDisabled(this._element) || this._isShown()) { + return; + } + const relatedTarget = { + relatedTarget: this._element + }; + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$5, relatedTarget); + if (showEvent.defaultPrevented) { + return; + } + this._createPopper(); + + // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) { + for (const element of [].concat(...document.body.children)) { + EventHandler.on(element, 'mouseover', noop); + } + } + this._element.focus(); + this._element.setAttribute('aria-expanded', true); + this._menu.classList.add(CLASS_NAME_SHOW$6); + this._element.classList.add(CLASS_NAME_SHOW$6); + EventHandler.trigger(this._element, EVENT_SHOWN$5, relatedTarget); + } + hide() { + if (isDisabled(this._element) || !this._isShown()) { + return; + } + const relatedTarget = { + relatedTarget: this._element + }; + this._completeHide(relatedTarget); + } + dispose() { + if (this._popper) { + this._popper.destroy(); + } + super.dispose(); + } + update() { + this._inNavbar = this._detectNavbar(); + if (this._popper) { + this._popper.update(); + } + } + + // Private + _completeHide(relatedTarget) { + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$5, relatedTarget); + if (hideEvent.defaultPrevented) { + return; + } + + // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + if ('ontouchstart' in document.documentElement) { + for (const element of [].concat(...document.body.children)) { + EventHandler.off(element, 'mouseover', noop); + } + } + if (this._popper) { + this._popper.destroy(); + } + this._menu.classList.remove(CLASS_NAME_SHOW$6); + this._element.classList.remove(CLASS_NAME_SHOW$6); + this._element.setAttribute('aria-expanded', 'false'); + Manipulator.removeDataAttribute(this._menu, 'popper'); + EventHandler.trigger(this._element, EVENT_HIDDEN$5, relatedTarget); + } + _getConfig(config) { + config = super._getConfig(config); + if (typeof config.reference === 'object' && !isElement(config.reference) && typeof config.reference.getBoundingClientRect !== 'function') { + // Popper virtual elements require a getBoundingClientRect method + throw new TypeError(`${NAME$a.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`); + } + return config; + } + _createPopper() { + if (typeof Popper__namespace === 'undefined') { + throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org/docs/v2/)'); + } + let referenceElement = this._element; + if (this._config.reference === 'parent') { + referenceElement = this._parent; + } else if (isElement(this._config.reference)) { + referenceElement = getElement(this._config.reference); + } else if (typeof this._config.reference === 'object') { + referenceElement = this._config.reference; + } + const popperConfig = this._getPopperConfig(); + this._popper = Popper__namespace.createPopper(referenceElement, this._menu, popperConfig); + } + _isShown() { + return this._menu.classList.contains(CLASS_NAME_SHOW$6); + } + _getPlacement() { + const parentDropdown = this._parent; + if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) { + return PLACEMENT_RIGHT; + } + if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) { + return PLACEMENT_LEFT; + } + if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) { + return PLACEMENT_TOPCENTER; + } + if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) { + return PLACEMENT_BOTTOMCENTER; + } + + // We need to trim the value because custom properties can also include spaces + const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'; + if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) { + return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP; + } + return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM; + } + _detectNavbar() { + return this._element.closest(SELECTOR_NAVBAR) !== null; + } + _getOffset() { + const { + offset + } = this._config; + if (typeof offset === 'string') { + return offset.split(',').map(value => Number.parseInt(value, 10)); + } + if (typeof offset === 'function') { + return popperData => offset(popperData, this._element); + } + return offset; + } + _getPopperConfig() { + const defaultBsPopperConfig = { + placement: this._getPlacement(), + modifiers: [{ + name: 'preventOverflow', + options: { + boundary: this._config.boundary + } + }, { + name: 'offset', + options: { + offset: this._getOffset() + } + }] + }; + + // Disable Popper if we have a static display or Dropdown is in Navbar + if (this._inNavbar || this._config.display === 'static') { + Manipulator.setDataAttribute(this._menu, 'popper', 'static'); // TODO: v6 remove + defaultBsPopperConfig.modifiers = [{ + name: 'applyStyles', + enabled: false + }]; + } + return { + ...defaultBsPopperConfig, + ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig]) + }; + } + _selectMenuItem({ + key, + target + }) { + const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element)); + if (!items.length) { + return; + } + + // if target isn't included in items (e.g. when expanding the dropdown) + // allow cycling to get the last item in case key equals ARROW_UP_KEY + getNextActiveElement(items, target, key === ARROW_DOWN_KEY$1, !items.includes(target)).focus(); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Dropdown.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + static clearMenus(event) { + if (event.button === RIGHT_MOUSE_BUTTON || event.type === 'keyup' && event.key !== TAB_KEY$1) { + return; + } + const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN); + for (const toggle of openToggles) { + const context = Dropdown.getInstance(toggle); + if (!context || context._config.autoClose === false) { + continue; + } + const composedPath = event.composedPath(); + const isMenuTarget = composedPath.includes(context._menu); + if (composedPath.includes(context._element) || context._config.autoClose === 'inside' && !isMenuTarget || context._config.autoClose === 'outside' && isMenuTarget) { + continue; + } + + // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu + if (context._menu.contains(event.target) && (event.type === 'keyup' && event.key === TAB_KEY$1 || /input|select|option|textarea|form/i.test(event.target.tagName))) { + continue; + } + const relatedTarget = { + relatedTarget: context._element + }; + if (event.type === 'click') { + relatedTarget.clickEvent = event; + } + context._completeHide(relatedTarget); + } + } + static dataApiKeydownHandler(event) { + // If not an UP | DOWN | ESCAPE key => not a dropdown command + // If input/textarea && if key is other than ESCAPE => not a dropdown command + + const isInput = /input|textarea/i.test(event.target.tagName); + const isEscapeEvent = event.key === ESCAPE_KEY$2; + const isUpOrDownEvent = [ARROW_UP_KEY$1, ARROW_DOWN_KEY$1].includes(event.key); + if (!isUpOrDownEvent && !isEscapeEvent) { + return; + } + if (isInput && !isEscapeEvent) { + return; + } + event.preventDefault(); + + // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/ + const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE$3) ? this : SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.next(this, SELECTOR_DATA_TOGGLE$3)[0] || SelectorEngine.findOne(SELECTOR_DATA_TOGGLE$3, event.delegateTarget.parentNode); + const instance = Dropdown.getOrCreateInstance(getToggleButton); + if (isUpOrDownEvent) { + event.stopPropagation(); + instance.show(); + instance._selectMenuItem(event); + return; + } + if (instance._isShown()) { + // else is escape and we check if it is shown + event.stopPropagation(); + instance.hide(); + getToggleButton.focus(); + } + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE$3, Dropdown.dataApiKeydownHandler); + EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler); + EventHandler.on(document, EVENT_CLICK_DATA_API$3, Dropdown.clearMenus); + EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus); + EventHandler.on(document, EVENT_CLICK_DATA_API$3, SELECTOR_DATA_TOGGLE$3, function (event) { + event.preventDefault(); + Dropdown.getOrCreateInstance(this).toggle(); + }); + + /** + * jQuery + */ + + defineJQueryPlugin(Dropdown); + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/backdrop.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$9 = 'backdrop'; + const CLASS_NAME_FADE$4 = 'fade'; + const CLASS_NAME_SHOW$5 = 'show'; + const EVENT_MOUSEDOWN = `mousedown.bs.${NAME$9}`; + const Default$8 = { + className: 'modal-backdrop', + clickCallback: null, + isAnimated: false, + isVisible: true, + // if false, we use the backdrop helper without adding any element to the dom + rootElement: 'body' // give the choice to place backdrop under different elements + }; + const DefaultType$8 = { + className: 'string', + clickCallback: '(function|null)', + isAnimated: 'boolean', + isVisible: 'boolean', + rootElement: '(element|string)' + }; + + /** + * Class definition + */ + + class Backdrop extends Config { + constructor(config) { + super(); + this._config = this._getConfig(config); + this._isAppended = false; + this._element = null; + } + + // Getters + static get Default() { + return Default$8; + } + static get DefaultType() { + return DefaultType$8; + } + static get NAME() { + return NAME$9; + } + + // Public + show(callback) { + if (!this._config.isVisible) { + execute(callback); + return; + } + this._append(); + const element = this._getElement(); + if (this._config.isAnimated) { + reflow(element); + } + element.classList.add(CLASS_NAME_SHOW$5); + this._emulateAnimation(() => { + execute(callback); + }); + } + hide(callback) { + if (!this._config.isVisible) { + execute(callback); + return; + } + this._getElement().classList.remove(CLASS_NAME_SHOW$5); + this._emulateAnimation(() => { + this.dispose(); + execute(callback); + }); + } + dispose() { + if (!this._isAppended) { + return; + } + EventHandler.off(this._element, EVENT_MOUSEDOWN); + this._element.remove(); + this._isAppended = false; + } + + // Private + _getElement() { + if (!this._element) { + const backdrop = document.createElement('div'); + backdrop.className = this._config.className; + if (this._config.isAnimated) { + backdrop.classList.add(CLASS_NAME_FADE$4); + } + this._element = backdrop; + } + return this._element; + } + _configAfterMerge(config) { + // use getElement() with the default "body" to get a fresh Element on each instantiation + config.rootElement = getElement(config.rootElement); + return config; + } + _append() { + if (this._isAppended) { + return; + } + const element = this._getElement(); + this._config.rootElement.append(element); + EventHandler.on(element, EVENT_MOUSEDOWN, () => { + execute(this._config.clickCallback); + }); + this._isAppended = true; + } + _emulateAnimation(callback) { + executeAfterTransition(callback, this._getElement(), this._config.isAnimated); + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/focustrap.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$8 = 'focustrap'; + const DATA_KEY$5 = 'bs.focustrap'; + const EVENT_KEY$5 = `.${DATA_KEY$5}`; + const EVENT_FOCUSIN$2 = `focusin${EVENT_KEY$5}`; + const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY$5}`; + const TAB_KEY = 'Tab'; + const TAB_NAV_FORWARD = 'forward'; + const TAB_NAV_BACKWARD = 'backward'; + const Default$7 = { + autofocus: true, + trapElement: null // The element to trap focus inside of + }; + const DefaultType$7 = { + autofocus: 'boolean', + trapElement: 'element' + }; + + /** + * Class definition + */ + + class FocusTrap extends Config { + constructor(config) { + super(); + this._config = this._getConfig(config); + this._isActive = false; + this._lastTabNavDirection = null; + } + + // Getters + static get Default() { + return Default$7; + } + static get DefaultType() { + return DefaultType$7; + } + static get NAME() { + return NAME$8; + } + + // Public + activate() { + if (this._isActive) { + return; + } + if (this._config.autofocus) { + this._config.trapElement.focus(); + } + EventHandler.off(document, EVENT_KEY$5); // guard against infinite focus loop + EventHandler.on(document, EVENT_FOCUSIN$2, event => this._handleFocusin(event)); + EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event)); + this._isActive = true; + } + deactivate() { + if (!this._isActive) { + return; + } + this._isActive = false; + EventHandler.off(document, EVENT_KEY$5); + } + + // Private + _handleFocusin(event) { + const { + trapElement + } = this._config; + if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) { + return; + } + const elements = SelectorEngine.focusableChildren(trapElement); + if (elements.length === 0) { + trapElement.focus(); + } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) { + elements[elements.length - 1].focus(); + } else { + elements[0].focus(); + } + } + _handleKeydown(event) { + if (event.key !== TAB_KEY) { + return; + } + this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/scrollBar.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'; + const SELECTOR_STICKY_CONTENT = '.sticky-top'; + const PROPERTY_PADDING = 'padding-right'; + const PROPERTY_MARGIN = 'margin-right'; + + /** + * Class definition + */ + + class ScrollBarHelper { + constructor() { + this._element = document.body; + } + + // Public + getWidth() { + // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes + const documentWidth = document.documentElement.clientWidth; + return Math.abs(window.innerWidth - documentWidth); + } + hide() { + const width = this.getWidth(); + this._disableOverFlow(); + // give padding to element to balance the hidden scrollbar width + this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width); + // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth + this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width); + this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width); + } + reset() { + this._resetElementAttributes(this._element, 'overflow'); + this._resetElementAttributes(this._element, PROPERTY_PADDING); + this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING); + this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN); + } + isOverflowing() { + return this.getWidth() > 0; + } + + // Private + _disableOverFlow() { + this._saveInitialAttribute(this._element, 'overflow'); + this._element.style.overflow = 'hidden'; + } + _setElementAttributes(selector, styleProperty, callback) { + const scrollbarWidth = this.getWidth(); + const manipulationCallBack = element => { + if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) { + return; + } + this._saveInitialAttribute(element, styleProperty); + const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty); + element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`); + }; + this._applyManipulationCallback(selector, manipulationCallBack); + } + _saveInitialAttribute(element, styleProperty) { + const actualValue = element.style.getPropertyValue(styleProperty); + if (actualValue) { + Manipulator.setDataAttribute(element, styleProperty, actualValue); + } + } + _resetElementAttributes(selector, styleProperty) { + const manipulationCallBack = element => { + const value = Manipulator.getDataAttribute(element, styleProperty); + // We only want to remove the property if the value is `null`; the value can also be zero + if (value === null) { + element.style.removeProperty(styleProperty); + return; + } + Manipulator.removeDataAttribute(element, styleProperty); + element.style.setProperty(styleProperty, value); + }; + this._applyManipulationCallback(selector, manipulationCallBack); + } + _applyManipulationCallback(selector, callBack) { + if (isElement(selector)) { + callBack(selector); + return; + } + for (const sel of SelectorEngine.find(selector, this._element)) { + callBack(sel); + } + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap modal.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$7 = 'modal'; + const DATA_KEY$4 = 'bs.modal'; + const EVENT_KEY$4 = `.${DATA_KEY$4}`; + const DATA_API_KEY$2 = '.data-api'; + const ESCAPE_KEY$1 = 'Escape'; + const EVENT_HIDE$4 = `hide${EVENT_KEY$4}`; + const EVENT_HIDE_PREVENTED$1 = `hidePrevented${EVENT_KEY$4}`; + const EVENT_HIDDEN$4 = `hidden${EVENT_KEY$4}`; + const EVENT_SHOW$4 = `show${EVENT_KEY$4}`; + const EVENT_SHOWN$4 = `shown${EVENT_KEY$4}`; + const EVENT_RESIZE$1 = `resize${EVENT_KEY$4}`; + const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY$4}`; + const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY$4}`; + const EVENT_KEYDOWN_DISMISS$1 = `keydown.dismiss${EVENT_KEY$4}`; + const EVENT_CLICK_DATA_API$2 = `click${EVENT_KEY$4}${DATA_API_KEY$2}`; + const CLASS_NAME_OPEN = 'modal-open'; + const CLASS_NAME_FADE$3 = 'fade'; + const CLASS_NAME_SHOW$4 = 'show'; + const CLASS_NAME_STATIC = 'modal-static'; + const OPEN_SELECTOR$1 = '.modal.show'; + const SELECTOR_DIALOG = '.modal-dialog'; + const SELECTOR_MODAL_BODY = '.modal-body'; + const SELECTOR_DATA_TOGGLE$2 = '[data-bs-toggle="modal"]'; + const Default$6 = { + backdrop: true, + focus: true, + keyboard: true + }; + const DefaultType$6 = { + backdrop: '(boolean|string)', + focus: 'boolean', + keyboard: 'boolean' + }; + + /** + * Class definition + */ + + class Modal extends BaseComponent { + constructor(element, config) { + super(element, config); + this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element); + this._backdrop = this._initializeBackDrop(); + this._focustrap = this._initializeFocusTrap(); + this._isShown = false; + this._isTransitioning = false; + this._scrollBar = new ScrollBarHelper(); + this._addEventListeners(); + } + + // Getters + static get Default() { + return Default$6; + } + static get DefaultType() { + return DefaultType$6; + } + static get NAME() { + return NAME$7; + } + + // Public + toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget); + } + show(relatedTarget) { + if (this._isShown || this._isTransitioning) { + return; + } + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$4, { + relatedTarget + }); + if (showEvent.defaultPrevented) { + return; + } + this._isShown = true; + this._isTransitioning = true; + this._scrollBar.hide(); + document.body.classList.add(CLASS_NAME_OPEN); + this._adjustDialog(); + this._backdrop.show(() => this._showElement(relatedTarget)); + } + hide() { + if (!this._isShown || this._isTransitioning) { + return; + } + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$4); + if (hideEvent.defaultPrevented) { + return; + } + this._isShown = false; + this._isTransitioning = true; + this._focustrap.deactivate(); + this._element.classList.remove(CLASS_NAME_SHOW$4); + this._queueCallback(() => this._hideModal(), this._element, this._isAnimated()); + } + dispose() { + EventHandler.off(window, EVENT_KEY$4); + EventHandler.off(this._dialog, EVENT_KEY$4); + this._backdrop.dispose(); + this._focustrap.deactivate(); + super.dispose(); + } + handleUpdate() { + this._adjustDialog(); + } + + // Private + _initializeBackDrop() { + return new Backdrop({ + isVisible: Boolean(this._config.backdrop), + // 'static' option will be translated to true, and booleans will keep their value, + isAnimated: this._isAnimated() + }); + } + _initializeFocusTrap() { + return new FocusTrap({ + trapElement: this._element + }); + } + _showElement(relatedTarget) { + // try to append dynamic modal + if (!document.body.contains(this._element)) { + document.body.append(this._element); + } + this._element.style.display = 'block'; + this._element.removeAttribute('aria-hidden'); + this._element.setAttribute('aria-modal', true); + this._element.setAttribute('role', 'dialog'); + this._element.scrollTop = 0; + const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog); + if (modalBody) { + modalBody.scrollTop = 0; + } + reflow(this._element); + this._element.classList.add(CLASS_NAME_SHOW$4); + const transitionComplete = () => { + if (this._config.focus) { + this._focustrap.activate(); + } + this._isTransitioning = false; + EventHandler.trigger(this._element, EVENT_SHOWN$4, { + relatedTarget + }); + }; + this._queueCallback(transitionComplete, this._dialog, this._isAnimated()); + } + _addEventListeners() { + EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS$1, event => { + if (event.key !== ESCAPE_KEY$1) { + return; + } + if (this._config.keyboard) { + this.hide(); + return; + } + this._triggerBackdropTransition(); + }); + EventHandler.on(window, EVENT_RESIZE$1, () => { + if (this._isShown && !this._isTransitioning) { + this._adjustDialog(); + } + }); + EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => { + // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks + EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => { + if (this._element !== event.target || this._element !== event2.target) { + return; + } + if (this._config.backdrop === 'static') { + this._triggerBackdropTransition(); + return; + } + if (this._config.backdrop) { + this.hide(); + } + }); + }); + } + _hideModal() { + this._element.style.display = 'none'; + this._element.setAttribute('aria-hidden', true); + this._element.removeAttribute('aria-modal'); + this._element.removeAttribute('role'); + this._isTransitioning = false; + this._backdrop.hide(() => { + document.body.classList.remove(CLASS_NAME_OPEN); + this._resetAdjustments(); + this._scrollBar.reset(); + EventHandler.trigger(this._element, EVENT_HIDDEN$4); + }); + } + _isAnimated() { + return this._element.classList.contains(CLASS_NAME_FADE$3); + } + _triggerBackdropTransition() { + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED$1); + if (hideEvent.defaultPrevented) { + return; + } + const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; + const initialOverflowY = this._element.style.overflowY; + // return if the following background transition hasn't yet completed + if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) { + return; + } + if (!isModalOverflowing) { + this._element.style.overflowY = 'hidden'; + } + this._element.classList.add(CLASS_NAME_STATIC); + this._queueCallback(() => { + this._element.classList.remove(CLASS_NAME_STATIC); + this._queueCallback(() => { + this._element.style.overflowY = initialOverflowY; + }, this._dialog); + }, this._dialog); + this._element.focus(); + } + + /** + * The following methods are used to handle overflowing modals + */ + + _adjustDialog() { + const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight; + const scrollbarWidth = this._scrollBar.getWidth(); + const isBodyOverflowing = scrollbarWidth > 0; + if (isBodyOverflowing && !isModalOverflowing) { + const property = isRTL() ? 'paddingLeft' : 'paddingRight'; + this._element.style[property] = `${scrollbarWidth}px`; + } + if (!isBodyOverflowing && isModalOverflowing) { + const property = isRTL() ? 'paddingRight' : 'paddingLeft'; + this._element.style[property] = `${scrollbarWidth}px`; + } + } + _resetAdjustments() { + this._element.style.paddingLeft = ''; + this._element.style.paddingRight = ''; + } + + // Static + static jQueryInterface(config, relatedTarget) { + return this.each(function () { + const data = Modal.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](relatedTarget); + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$2, SELECTOR_DATA_TOGGLE$2, function (event) { + const target = SelectorEngine.getElementFromSelector(this); + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + EventHandler.one(target, EVENT_SHOW$4, showEvent => { + if (showEvent.defaultPrevented) { + // only register focus restorer if modal will actually get shown + return; + } + EventHandler.one(target, EVENT_HIDDEN$4, () => { + if (isVisible(this)) { + this.focus(); + } + }); + }); + + // avoid conflict when clicking modal toggler while another one is open + const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR$1); + if (alreadyOpen) { + Modal.getInstance(alreadyOpen).hide(); + } + const data = Modal.getOrCreateInstance(target); + data.toggle(this); + }); + enableDismissTrigger(Modal); + + /** + * jQuery + */ + + defineJQueryPlugin(Modal); + + /** + * -------------------------------------------------------------------------- + * Bootstrap offcanvas.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$6 = 'offcanvas'; + const DATA_KEY$3 = 'bs.offcanvas'; + const EVENT_KEY$3 = `.${DATA_KEY$3}`; + const DATA_API_KEY$1 = '.data-api'; + const EVENT_LOAD_DATA_API$2 = `load${EVENT_KEY$3}${DATA_API_KEY$1}`; + const ESCAPE_KEY = 'Escape'; + const CLASS_NAME_SHOW$3 = 'show'; + const CLASS_NAME_SHOWING$1 = 'showing'; + const CLASS_NAME_HIDING = 'hiding'; + const CLASS_NAME_BACKDROP = 'offcanvas-backdrop'; + const OPEN_SELECTOR = '.offcanvas.show'; + const EVENT_SHOW$3 = `show${EVENT_KEY$3}`; + const EVENT_SHOWN$3 = `shown${EVENT_KEY$3}`; + const EVENT_HIDE$3 = `hide${EVENT_KEY$3}`; + const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY$3}`; + const EVENT_HIDDEN$3 = `hidden${EVENT_KEY$3}`; + const EVENT_RESIZE = `resize${EVENT_KEY$3}`; + const EVENT_CLICK_DATA_API$1 = `click${EVENT_KEY$3}${DATA_API_KEY$1}`; + const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY$3}`; + const SELECTOR_DATA_TOGGLE$1 = '[data-bs-toggle="offcanvas"]'; + const Default$5 = { + backdrop: true, + keyboard: true, + scroll: false + }; + const DefaultType$5 = { + backdrop: '(boolean|string)', + keyboard: 'boolean', + scroll: 'boolean' + }; + + /** + * Class definition + */ + + class Offcanvas extends BaseComponent { + constructor(element, config) { + super(element, config); + this._isShown = false; + this._backdrop = this._initializeBackDrop(); + this._focustrap = this._initializeFocusTrap(); + this._addEventListeners(); + } + + // Getters + static get Default() { + return Default$5; + } + static get DefaultType() { + return DefaultType$5; + } + static get NAME() { + return NAME$6; + } + + // Public + toggle(relatedTarget) { + return this._isShown ? this.hide() : this.show(relatedTarget); + } + show(relatedTarget) { + if (this._isShown) { + return; + } + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW$3, { + relatedTarget + }); + if (showEvent.defaultPrevented) { + return; + } + this._isShown = true; + this._backdrop.show(); + if (!this._config.scroll) { + new ScrollBarHelper().hide(); + } + this._element.setAttribute('aria-modal', true); + this._element.setAttribute('role', 'dialog'); + this._element.classList.add(CLASS_NAME_SHOWING$1); + const completeCallBack = () => { + if (!this._config.scroll || this._config.backdrop) { + this._focustrap.activate(); + } + this._element.classList.add(CLASS_NAME_SHOW$3); + this._element.classList.remove(CLASS_NAME_SHOWING$1); + EventHandler.trigger(this._element, EVENT_SHOWN$3, { + relatedTarget + }); + }; + this._queueCallback(completeCallBack, this._element, true); + } + hide() { + if (!this._isShown) { + return; + } + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE$3); + if (hideEvent.defaultPrevented) { + return; + } + this._focustrap.deactivate(); + this._element.blur(); + this._isShown = false; + this._element.classList.add(CLASS_NAME_HIDING); + this._backdrop.hide(); + const completeCallback = () => { + this._element.classList.remove(CLASS_NAME_SHOW$3, CLASS_NAME_HIDING); + this._element.removeAttribute('aria-modal'); + this._element.removeAttribute('role'); + if (!this._config.scroll) { + new ScrollBarHelper().reset(); + } + EventHandler.trigger(this._element, EVENT_HIDDEN$3); + }; + this._queueCallback(completeCallback, this._element, true); + } + dispose() { + this._backdrop.dispose(); + this._focustrap.deactivate(); + super.dispose(); + } + + // Private + _initializeBackDrop() { + const clickCallback = () => { + if (this._config.backdrop === 'static') { + EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED); + return; + } + this.hide(); + }; + + // 'static' option will be translated to true, and booleans will keep their value + const isVisible = Boolean(this._config.backdrop); + return new Backdrop({ + className: CLASS_NAME_BACKDROP, + isVisible, + isAnimated: true, + rootElement: this._element.parentNode, + clickCallback: isVisible ? clickCallback : null + }); + } + _initializeFocusTrap() { + return new FocusTrap({ + trapElement: this._element + }); + } + _addEventListeners() { + EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => { + if (event.key !== ESCAPE_KEY) { + return; + } + if (this._config.keyboard) { + this.hide(); + return; + } + EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED); + }); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Offcanvas.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](this); + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API$1, SELECTOR_DATA_TOGGLE$1, function (event) { + const target = SelectorEngine.getElementFromSelector(this); + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + if (isDisabled(this)) { + return; + } + EventHandler.one(target, EVENT_HIDDEN$3, () => { + // focus on trigger when it is closed + if (isVisible(this)) { + this.focus(); + } + }); + + // avoid conflict when clicking a toggler of an offcanvas, while another is open + const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR); + if (alreadyOpen && alreadyOpen !== target) { + Offcanvas.getInstance(alreadyOpen).hide(); + } + const data = Offcanvas.getOrCreateInstance(target); + data.toggle(this); + }); + EventHandler.on(window, EVENT_LOAD_DATA_API$2, () => { + for (const selector of SelectorEngine.find(OPEN_SELECTOR)) { + Offcanvas.getOrCreateInstance(selector).show(); + } + }); + EventHandler.on(window, EVENT_RESIZE, () => { + for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) { + if (getComputedStyle(element).position !== 'fixed') { + Offcanvas.getOrCreateInstance(element).hide(); + } + } + }); + enableDismissTrigger(Offcanvas); + + /** + * jQuery + */ + + defineJQueryPlugin(Offcanvas); + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/sanitizer.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + // js-docs-start allow-list + const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i; + const DefaultAllowlist = { + // Global attributes allowed on any supplied element below. + '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN], + a: ['target', 'href', 'title', 'rel'], + area: [], + b: [], + br: [], + col: [], + code: [], + dd: [], + div: [], + dl: [], + dt: [], + em: [], + hr: [], + h1: [], + h2: [], + h3: [], + h4: [], + h5: [], + h6: [], + i: [], + img: ['src', 'srcset', 'alt', 'title', 'width', 'height'], + li: [], + ol: [], + p: [], + pre: [], + s: [], + small: [], + span: [], + sub: [], + sup: [], + strong: [], + u: [], + ul: [] + }; + // js-docs-end allow-list + + const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']); + + /** + * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation + * contexts. + * + * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38 + */ + const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i; + const allowedAttribute = (attribute, allowedAttributeList) => { + const attributeName = attribute.nodeName.toLowerCase(); + if (allowedAttributeList.includes(attributeName)) { + if (uriAttributes.has(attributeName)) { + return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue)); + } + return true; + } + + // Check if a regular expression validates the attribute. + return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName)); + }; + function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) { + if (!unsafeHtml.length) { + return unsafeHtml; + } + if (sanitizeFunction && typeof sanitizeFunction === 'function') { + return sanitizeFunction(unsafeHtml); + } + const domParser = new window.DOMParser(); + const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html'); + const elements = [].concat(...createdDocument.body.querySelectorAll('*')); + for (const element of elements) { + const elementName = element.nodeName.toLowerCase(); + if (!Object.keys(allowList).includes(elementName)) { + element.remove(); + continue; + } + const attributeList = [].concat(...element.attributes); + const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []); + for (const attribute of attributeList) { + if (!allowedAttribute(attribute, allowedAttributes)) { + element.removeAttribute(attribute.nodeName); + } + } + } + return createdDocument.body.innerHTML; + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap util/template-factory.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$5 = 'TemplateFactory'; + const Default$4 = { + allowList: DefaultAllowlist, + content: {}, + // { selector : text , selector2 : text2 , } + extraClass: '', + html: false, + sanitize: true, + sanitizeFn: null, + template: '<div></div>' + }; + const DefaultType$4 = { + allowList: 'object', + content: 'object', + extraClass: '(string|function)', + html: 'boolean', + sanitize: 'boolean', + sanitizeFn: '(null|function)', + template: 'string' + }; + const DefaultContentType = { + entry: '(string|element|function|null)', + selector: '(string|element)' + }; + + /** + * Class definition + */ + + class TemplateFactory extends Config { + constructor(config) { + super(); + this._config = this._getConfig(config); + } + + // Getters + static get Default() { + return Default$4; + } + static get DefaultType() { + return DefaultType$4; + } + static get NAME() { + return NAME$5; + } + + // Public + getContent() { + return Object.values(this._config.content).map(config => this._resolvePossibleFunction(config)).filter(Boolean); + } + hasContent() { + return this.getContent().length > 0; + } + changeContent(content) { + this._checkContent(content); + this._config.content = { + ...this._config.content, + ...content + }; + return this; + } + toHtml() { + const templateWrapper = document.createElement('div'); + templateWrapper.innerHTML = this._maybeSanitize(this._config.template); + for (const [selector, text] of Object.entries(this._config.content)) { + this._setContent(templateWrapper, text, selector); + } + const template = templateWrapper.children[0]; + const extraClass = this._resolvePossibleFunction(this._config.extraClass); + if (extraClass) { + template.classList.add(...extraClass.split(' ')); + } + return template; + } + + // Private + _typeCheckConfig(config) { + super._typeCheckConfig(config); + this._checkContent(config.content); + } + _checkContent(arg) { + for (const [selector, content] of Object.entries(arg)) { + super._typeCheckConfig({ + selector, + entry: content + }, DefaultContentType); + } + } + _setContent(template, content, selector) { + const templateElement = SelectorEngine.findOne(selector, template); + if (!templateElement) { + return; + } + content = this._resolvePossibleFunction(content); + if (!content) { + templateElement.remove(); + return; + } + if (isElement(content)) { + this._putElementInTemplate(getElement(content), templateElement); + return; + } + if (this._config.html) { + templateElement.innerHTML = this._maybeSanitize(content); + return; + } + templateElement.textContent = content; + } + _maybeSanitize(arg) { + return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg; + } + _resolvePossibleFunction(arg) { + return execute(arg, [undefined, this]); + } + _putElementInTemplate(element, templateElement) { + if (this._config.html) { + templateElement.innerHTML = ''; + templateElement.append(element); + return; + } + templateElement.textContent = element.textContent; + } + } + + /** + * -------------------------------------------------------------------------- + * Bootstrap tooltip.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$4 = 'tooltip'; + const DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn']); + const CLASS_NAME_FADE$2 = 'fade'; + const CLASS_NAME_MODAL = 'modal'; + const CLASS_NAME_SHOW$2 = 'show'; + const SELECTOR_TOOLTIP_INNER = '.tooltip-inner'; + const SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`; + const EVENT_MODAL_HIDE = 'hide.bs.modal'; + const TRIGGER_HOVER = 'hover'; + const TRIGGER_FOCUS = 'focus'; + const TRIGGER_CLICK = 'click'; + const TRIGGER_MANUAL = 'manual'; + const EVENT_HIDE$2 = 'hide'; + const EVENT_HIDDEN$2 = 'hidden'; + const EVENT_SHOW$2 = 'show'; + const EVENT_SHOWN$2 = 'shown'; + const EVENT_INSERTED = 'inserted'; + const EVENT_CLICK$1 = 'click'; + const EVENT_FOCUSIN$1 = 'focusin'; + const EVENT_FOCUSOUT$1 = 'focusout'; + const EVENT_MOUSEENTER = 'mouseenter'; + const EVENT_MOUSELEAVE = 'mouseleave'; + const AttachmentMap = { + AUTO: 'auto', + TOP: 'top', + RIGHT: isRTL() ? 'left' : 'right', + BOTTOM: 'bottom', + LEFT: isRTL() ? 'right' : 'left' + }; + const Default$3 = { + allowList: DefaultAllowlist, + animation: true, + boundary: 'clippingParents', + container: false, + customClass: '', + delay: 0, + fallbackPlacements: ['top', 'right', 'bottom', 'left'], + html: false, + offset: [0, 6], + placement: 'top', + popperConfig: null, + sanitize: true, + sanitizeFn: null, + selector: false, + template: '<div class="tooltip" role="tooltip">' + '<div class="tooltip-arrow"></div>' + '<div class="tooltip-inner"></div>' + '</div>', + title: '', + trigger: 'hover focus' + }; + const DefaultType$3 = { + allowList: 'object', + animation: 'boolean', + boundary: '(string|element)', + container: '(string|element|boolean)', + customClass: '(string|function)', + delay: '(number|object)', + fallbackPlacements: 'array', + html: 'boolean', + offset: '(array|string|function)', + placement: '(string|function)', + popperConfig: '(null|object|function)', + sanitize: 'boolean', + sanitizeFn: '(null|function)', + selector: '(string|boolean)', + template: 'string', + title: '(string|element|function)', + trigger: 'string' + }; + + /** + * Class definition + */ + + class Tooltip extends BaseComponent { + constructor(element, config) { + if (typeof Popper__namespace === 'undefined') { + throw new TypeError('Bootstrap\'s tooltips require Popper (https://popper.js.org/docs/v2/)'); + } + super(element, config); + + // Private + this._isEnabled = true; + this._timeout = 0; + this._isHovered = null; + this._activeTrigger = {}; + this._popper = null; + this._templateFactory = null; + this._newContent = null; + + // Protected + this.tip = null; + this._setListeners(); + if (!this._config.selector) { + this._fixTitle(); + } + } + + // Getters + static get Default() { + return Default$3; + } + static get DefaultType() { + return DefaultType$3; + } + static get NAME() { + return NAME$4; + } + + // Public + enable() { + this._isEnabled = true; + } + disable() { + this._isEnabled = false; + } + toggleEnabled() { + this._isEnabled = !this._isEnabled; + } + toggle() { + if (!this._isEnabled) { + return; + } + if (this._isShown()) { + this._leave(); + return; + } + this._enter(); + } + dispose() { + clearTimeout(this._timeout); + EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); + if (this._element.getAttribute('data-bs-original-title')) { + this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title')); + } + this._disposePopper(); + super.dispose(); + } + show() { + if (this._element.style.display === 'none') { + throw new Error('Please use show on visible elements'); + } + if (!(this._isWithContent() && this._isEnabled)) { + return; + } + const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW$2)); + const shadowRoot = findShadowRoot(this._element); + const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element); + if (showEvent.defaultPrevented || !isInTheDom) { + return; + } + + // TODO: v6 remove this or make it optional + this._disposePopper(); + const tip = this._getTipElement(); + this._element.setAttribute('aria-describedby', tip.getAttribute('id')); + const { + container + } = this._config; + if (!this._element.ownerDocument.documentElement.contains(this.tip)) { + container.append(tip); + EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED)); + } + this._popper = this._createPopper(tip); + tip.classList.add(CLASS_NAME_SHOW$2); + + // If this is a touch-enabled device we add extra + // empty mouseover listeners to the body's immediate children; + // only needed because of broken event delegation on iOS + // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html + if ('ontouchstart' in document.documentElement) { + for (const element of [].concat(...document.body.children)) { + EventHandler.on(element, 'mouseover', noop); + } + } + const complete = () => { + EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN$2)); + if (this._isHovered === false) { + this._leave(); + } + this._isHovered = false; + }; + this._queueCallback(complete, this.tip, this._isAnimated()); + } + hide() { + if (!this._isShown()) { + return; + } + const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE$2)); + if (hideEvent.defaultPrevented) { + return; + } + const tip = this._getTipElement(); + tip.classList.remove(CLASS_NAME_SHOW$2); + + // If this is a touch-enabled device we remove the extra + // empty mouseover listeners we added for iOS support + if ('ontouchstart' in document.documentElement) { + for (const element of [].concat(...document.body.children)) { + EventHandler.off(element, 'mouseover', noop); + } + } + this._activeTrigger[TRIGGER_CLICK] = false; + this._activeTrigger[TRIGGER_FOCUS] = false; + this._activeTrigger[TRIGGER_HOVER] = false; + this._isHovered = null; // it is a trick to support manual triggering + + const complete = () => { + if (this._isWithActiveTrigger()) { + return; + } + if (!this._isHovered) { + this._disposePopper(); + } + this._element.removeAttribute('aria-describedby'); + EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN$2)); + }; + this._queueCallback(complete, this.tip, this._isAnimated()); + } + update() { + if (this._popper) { + this._popper.update(); + } + } + + // Protected + _isWithContent() { + return Boolean(this._getTitle()); + } + _getTipElement() { + if (!this.tip) { + this.tip = this._createTipElement(this._newContent || this._getContentForTemplate()); + } + return this.tip; + } + _createTipElement(content) { + const tip = this._getTemplateFactory(content).toHtml(); + + // TODO: remove this check in v6 + if (!tip) { + return null; + } + tip.classList.remove(CLASS_NAME_FADE$2, CLASS_NAME_SHOW$2); + // TODO: v6 the following can be achieved with CSS only + tip.classList.add(`bs-${this.constructor.NAME}-auto`); + const tipId = getUID(this.constructor.NAME).toString(); + tip.setAttribute('id', tipId); + if (this._isAnimated()) { + tip.classList.add(CLASS_NAME_FADE$2); + } + return tip; + } + setContent(content) { + this._newContent = content; + if (this._isShown()) { + this._disposePopper(); + this.show(); + } + } + _getTemplateFactory(content) { + if (this._templateFactory) { + this._templateFactory.changeContent(content); + } else { + this._templateFactory = new TemplateFactory({ + ...this._config, + // the `content` var has to be after `this._config` + // to override config.content in case of popover + content, + extraClass: this._resolvePossibleFunction(this._config.customClass) + }); + } + return this._templateFactory; + } + _getContentForTemplate() { + return { + [SELECTOR_TOOLTIP_INNER]: this._getTitle() + }; + } + _getTitle() { + return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title'); + } + + // Private + _initializeOnDelegatedTarget(event) { + return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig()); + } + _isAnimated() { + return this._config.animation || this.tip && this.tip.classList.contains(CLASS_NAME_FADE$2); + } + _isShown() { + return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW$2); + } + _createPopper(tip) { + const placement = execute(this._config.placement, [this, tip, this._element]); + const attachment = AttachmentMap[placement.toUpperCase()]; + return Popper__namespace.createPopper(this._element, tip, this._getPopperConfig(attachment)); + } + _getOffset() { + const { + offset + } = this._config; + if (typeof offset === 'string') { + return offset.split(',').map(value => Number.parseInt(value, 10)); + } + if (typeof offset === 'function') { + return popperData => offset(popperData, this._element); + } + return offset; + } + _resolvePossibleFunction(arg) { + return execute(arg, [this._element, this._element]); + } + _getPopperConfig(attachment) { + const defaultBsPopperConfig = { + placement: attachment, + modifiers: [{ + name: 'flip', + options: { + fallbackPlacements: this._config.fallbackPlacements + } + }, { + name: 'offset', + options: { + offset: this._getOffset() + } + }, { + name: 'preventOverflow', + options: { + boundary: this._config.boundary + } + }, { + name: 'arrow', + options: { + element: `.${this.constructor.NAME}-arrow` + } + }, { + name: 'preSetPlacement', + enabled: true, + phase: 'beforeMain', + fn: data => { + // Pre-set Popper's placement attribute in order to read the arrow sizes properly. + // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement + this._getTipElement().setAttribute('data-popper-placement', data.state.placement); + } + }] + }; + return { + ...defaultBsPopperConfig, + ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig]) + }; + } + _setListeners() { + const triggers = this._config.trigger.split(' '); + for (const trigger of triggers) { + if (trigger === 'click') { + EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK$1), this._config.selector, event => { + const context = this._initializeOnDelegatedTarget(event); + context._activeTrigger[TRIGGER_CLICK] = !(context._isShown() && context._activeTrigger[TRIGGER_CLICK]); + context.toggle(); + }); + } else if (trigger !== TRIGGER_MANUAL) { + const eventIn = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSEENTER) : this.constructor.eventName(EVENT_FOCUSIN$1); + const eventOut = trigger === TRIGGER_HOVER ? this.constructor.eventName(EVENT_MOUSELEAVE) : this.constructor.eventName(EVENT_FOCUSOUT$1); + EventHandler.on(this._element, eventIn, this._config.selector, event => { + const context = this._initializeOnDelegatedTarget(event); + context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true; + context._enter(); + }); + EventHandler.on(this._element, eventOut, this._config.selector, event => { + const context = this._initializeOnDelegatedTarget(event); + context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] = context._element.contains(event.relatedTarget); + context._leave(); + }); + } + } + this._hideModalHandler = () => { + if (this._element) { + this.hide(); + } + }; + EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler); + } + _fixTitle() { + const title = this._element.getAttribute('title'); + if (!title) { + return; + } + if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) { + this._element.setAttribute('aria-label', title); + } + this._element.setAttribute('data-bs-original-title', title); // DO NOT USE IT. Is only for backwards compatibility + this._element.removeAttribute('title'); + } + _enter() { + if (this._isShown() || this._isHovered) { + this._isHovered = true; + return; + } + this._isHovered = true; + this._setTimeout(() => { + if (this._isHovered) { + this.show(); + } + }, this._config.delay.show); + } + _leave() { + if (this._isWithActiveTrigger()) { + return; + } + this._isHovered = false; + this._setTimeout(() => { + if (!this._isHovered) { + this.hide(); + } + }, this._config.delay.hide); + } + _setTimeout(handler, timeout) { + clearTimeout(this._timeout); + this._timeout = setTimeout(handler, timeout); + } + _isWithActiveTrigger() { + return Object.values(this._activeTrigger).includes(true); + } + _getConfig(config) { + const dataAttributes = Manipulator.getDataAttributes(this._element); + for (const dataAttribute of Object.keys(dataAttributes)) { + if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) { + delete dataAttributes[dataAttribute]; + } + } + config = { + ...dataAttributes, + ...(typeof config === 'object' && config ? config : {}) + }; + config = this._mergeConfigObj(config); + config = this._configAfterMerge(config); + this._typeCheckConfig(config); + return config; + } + _configAfterMerge(config) { + config.container = config.container === false ? document.body : getElement(config.container); + if (typeof config.delay === 'number') { + config.delay = { + show: config.delay, + hide: config.delay + }; + } + if (typeof config.title === 'number') { + config.title = config.title.toString(); + } + if (typeof config.content === 'number') { + config.content = config.content.toString(); + } + return config; + } + _getDelegateConfig() { + const config = {}; + for (const [key, value] of Object.entries(this._config)) { + if (this.constructor.Default[key] !== value) { + config[key] = value; + } + } + config.selector = false; + config.trigger = 'manual'; + + // In the future can be replaced with: + // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]]) + // `Object.fromEntries(keysWithDifferentValues)` + return config; + } + _disposePopper() { + if (this._popper) { + this._popper.destroy(); + this._popper = null; + } + if (this.tip) { + this.tip.remove(); + this.tip = null; + } + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Tooltip.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + } + + /** + * jQuery + */ + + defineJQueryPlugin(Tooltip); + + /** + * -------------------------------------------------------------------------- + * Bootstrap popover.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$3 = 'popover'; + const SELECTOR_TITLE = '.popover-header'; + const SELECTOR_CONTENT = '.popover-body'; + const Default$2 = { + ...Tooltip.Default, + content: '', + offset: [0, 8], + placement: 'right', + template: '<div class="popover" role="tooltip">' + '<div class="popover-arrow"></div>' + '<h3 class="popover-header"></h3>' + '<div class="popover-body"></div>' + '</div>', + trigger: 'click' + }; + const DefaultType$2 = { + ...Tooltip.DefaultType, + content: '(null|string|element|function)' + }; + + /** + * Class definition + */ + + class Popover extends Tooltip { + // Getters + static get Default() { + return Default$2; + } + static get DefaultType() { + return DefaultType$2; + } + static get NAME() { + return NAME$3; + } + + // Overrides + _isWithContent() { + return this._getTitle() || this._getContent(); + } + + // Private + _getContentForTemplate() { + return { + [SELECTOR_TITLE]: this._getTitle(), + [SELECTOR_CONTENT]: this._getContent() + }; + } + _getContent() { + return this._resolvePossibleFunction(this._config.content); + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Popover.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + } + + /** + * jQuery + */ + + defineJQueryPlugin(Popover); + + /** + * -------------------------------------------------------------------------- + * Bootstrap scrollspy.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$2 = 'scrollspy'; + const DATA_KEY$2 = 'bs.scrollspy'; + const EVENT_KEY$2 = `.${DATA_KEY$2}`; + const DATA_API_KEY = '.data-api'; + const EVENT_ACTIVATE = `activate${EVENT_KEY$2}`; + const EVENT_CLICK = `click${EVENT_KEY$2}`; + const EVENT_LOAD_DATA_API$1 = `load${EVENT_KEY$2}${DATA_API_KEY}`; + const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'; + const CLASS_NAME_ACTIVE$1 = 'active'; + const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]'; + const SELECTOR_TARGET_LINKS = '[href]'; + const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'; + const SELECTOR_NAV_LINKS = '.nav-link'; + const SELECTOR_NAV_ITEMS = '.nav-item'; + const SELECTOR_LIST_ITEMS = '.list-group-item'; + const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`; + const SELECTOR_DROPDOWN = '.dropdown'; + const SELECTOR_DROPDOWN_TOGGLE$1 = '.dropdown-toggle'; + const Default$1 = { + offset: null, + // TODO: v6 @deprecated, keep it for backwards compatibility reasons + rootMargin: '0px 0px -25%', + smoothScroll: false, + target: null, + threshold: [0.1, 0.5, 1] + }; + const DefaultType$1 = { + offset: '(number|null)', + // TODO v6 @deprecated, keep it for backwards compatibility reasons + rootMargin: 'string', + smoothScroll: 'boolean', + target: 'element', + threshold: 'array' + }; + + /** + * Class definition + */ + + class ScrollSpy extends BaseComponent { + constructor(element, config) { + super(element, config); + + // this._element is the observablesContainer and config.target the menu links wrapper + this._targetLinks = new Map(); + this._observableSections = new Map(); + this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element; + this._activeTarget = null; + this._observer = null; + this._previousScrollData = { + visibleEntryTop: 0, + parentScrollTop: 0 + }; + this.refresh(); // initialize + } + + // Getters + static get Default() { + return Default$1; + } + static get DefaultType() { + return DefaultType$1; + } + static get NAME() { + return NAME$2; + } + + // Public + refresh() { + this._initializeTargetsAndObservables(); + this._maybeEnableSmoothScroll(); + if (this._observer) { + this._observer.disconnect(); + } else { + this._observer = this._getNewObserver(); + } + for (const section of this._observableSections.values()) { + this._observer.observe(section); + } + } + dispose() { + this._observer.disconnect(); + super.dispose(); + } + + // Private + _configAfterMerge(config) { + // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case + config.target = getElement(config.target) || document.body; + + // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only + config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin; + if (typeof config.threshold === 'string') { + config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value)); + } + return config; + } + _maybeEnableSmoothScroll() { + if (!this._config.smoothScroll) { + return; + } + + // unregister any previous listeners + EventHandler.off(this._config.target, EVENT_CLICK); + EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => { + const observableSection = this._observableSections.get(event.target.hash); + if (observableSection) { + event.preventDefault(); + const root = this._rootElement || window; + const height = observableSection.offsetTop - this._element.offsetTop; + if (root.scrollTo) { + root.scrollTo({ + top: height, + behavior: 'smooth' + }); + return; + } + + // Chrome 60 doesn't support `scrollTo` + root.scrollTop = height; + } + }); + } + _getNewObserver() { + const options = { + root: this._rootElement, + threshold: this._config.threshold, + rootMargin: this._config.rootMargin + }; + return new IntersectionObserver(entries => this._observerCallback(entries), options); + } + + // The logic of selection + _observerCallback(entries) { + const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`); + const activate = entry => { + this._previousScrollData.visibleEntryTop = entry.target.offsetTop; + this._process(targetElement(entry)); + }; + const parentScrollTop = (this._rootElement || document.documentElement).scrollTop; + const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop; + this._previousScrollData.parentScrollTop = parentScrollTop; + for (const entry of entries) { + if (!entry.isIntersecting) { + this._activeTarget = null; + this._clearActiveClass(targetElement(entry)); + continue; + } + const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop; + // if we are scrolling down, pick the bigger offsetTop + if (userScrollsDown && entryIsLowerThanPrevious) { + activate(entry); + // if parent isn't scrolled, let's keep the first visible item, breaking the iteration + if (!parentScrollTop) { + return; + } + continue; + } + + // if we are scrolling up, pick the smallest offsetTop + if (!userScrollsDown && !entryIsLowerThanPrevious) { + activate(entry); + } + } + } + _initializeTargetsAndObservables() { + this._targetLinks = new Map(); + this._observableSections = new Map(); + const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target); + for (const anchor of targetLinks) { + // ensure that the anchor has an id and is not disabled + if (!anchor.hash || isDisabled(anchor)) { + continue; + } + const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element); + + // ensure that the observableSection exists & is visible + if (isVisible(observableSection)) { + this._targetLinks.set(decodeURI(anchor.hash), anchor); + this._observableSections.set(anchor.hash, observableSection); + } + } + } + _process(target) { + if (this._activeTarget === target) { + return; + } + this._clearActiveClass(this._config.target); + this._activeTarget = target; + target.classList.add(CLASS_NAME_ACTIVE$1); + this._activateParents(target); + EventHandler.trigger(this._element, EVENT_ACTIVATE, { + relatedTarget: target + }); + } + _activateParents(target) { + // Activate dropdown parents + if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) { + SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE$1, target.closest(SELECTOR_DROPDOWN)).classList.add(CLASS_NAME_ACTIVE$1); + return; + } + for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) { + // Set triggered links parents as active + // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor + for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) { + item.classList.add(CLASS_NAME_ACTIVE$1); + } + } + } + _clearActiveClass(parent) { + parent.classList.remove(CLASS_NAME_ACTIVE$1); + const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE$1}`, parent); + for (const node of activeNodes) { + node.classList.remove(CLASS_NAME_ACTIVE$1); + } + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = ScrollSpy.getOrCreateInstance(this, config); + if (typeof config !== 'string') { + return; + } + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(window, EVENT_LOAD_DATA_API$1, () => { + for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) { + ScrollSpy.getOrCreateInstance(spy); + } + }); + + /** + * jQuery + */ + + defineJQueryPlugin(ScrollSpy); + + /** + * -------------------------------------------------------------------------- + * Bootstrap tab.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME$1 = 'tab'; + const DATA_KEY$1 = 'bs.tab'; + const EVENT_KEY$1 = `.${DATA_KEY$1}`; + const EVENT_HIDE$1 = `hide${EVENT_KEY$1}`; + const EVENT_HIDDEN$1 = `hidden${EVENT_KEY$1}`; + const EVENT_SHOW$1 = `show${EVENT_KEY$1}`; + const EVENT_SHOWN$1 = `shown${EVENT_KEY$1}`; + const EVENT_CLICK_DATA_API = `click${EVENT_KEY$1}`; + const EVENT_KEYDOWN = `keydown${EVENT_KEY$1}`; + const EVENT_LOAD_DATA_API = `load${EVENT_KEY$1}`; + const ARROW_LEFT_KEY = 'ArrowLeft'; + const ARROW_RIGHT_KEY = 'ArrowRight'; + const ARROW_UP_KEY = 'ArrowUp'; + const ARROW_DOWN_KEY = 'ArrowDown'; + const HOME_KEY = 'Home'; + const END_KEY = 'End'; + const CLASS_NAME_ACTIVE = 'active'; + const CLASS_NAME_FADE$1 = 'fade'; + const CLASS_NAME_SHOW$1 = 'show'; + const CLASS_DROPDOWN = 'dropdown'; + const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'; + const SELECTOR_DROPDOWN_MENU = '.dropdown-menu'; + const NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`; + const SELECTOR_TAB_PANEL = '.list-group, .nav, [role="tablist"]'; + const SELECTOR_OUTER = '.nav-item, .list-group-item'; + const SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`; + const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]'; // TODO: could only be `tab` in v6 + const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`; + const SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle="tab"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="pill"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="list"]`; + + /** + * Class definition + */ + + class Tab extends BaseComponent { + constructor(element) { + super(element); + this._parent = this._element.closest(SELECTOR_TAB_PANEL); + if (!this._parent) { + return; + // TODO: should throw exception in v6 + // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`) + } + + // Set up initial aria attributes + this._setInitialAttributes(this._parent, this._getChildren()); + EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event)); + } + + // Getters + static get NAME() { + return NAME$1; + } + + // Public + show() { + // Shows this elem and deactivate the active sibling if exists + const innerElem = this._element; + if (this._elemIsActive(innerElem)) { + return; + } + + // Search for active tab on same parent to deactivate it + const active = this._getActiveElem(); + const hideEvent = active ? EventHandler.trigger(active, EVENT_HIDE$1, { + relatedTarget: innerElem + }) : null; + const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW$1, { + relatedTarget: active + }); + if (showEvent.defaultPrevented || hideEvent && hideEvent.defaultPrevented) { + return; + } + this._deactivate(active, innerElem); + this._activate(innerElem, active); + } + + // Private + _activate(element, relatedElem) { + if (!element) { + return; + } + element.classList.add(CLASS_NAME_ACTIVE); + this._activate(SelectorEngine.getElementFromSelector(element)); // Search and activate/show the proper section + + const complete = () => { + if (element.getAttribute('role') !== 'tab') { + element.classList.add(CLASS_NAME_SHOW$1); + return; + } + element.removeAttribute('tabindex'); + element.setAttribute('aria-selected', true); + this._toggleDropDown(element, true); + EventHandler.trigger(element, EVENT_SHOWN$1, { + relatedTarget: relatedElem + }); + }; + this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE$1)); + } + _deactivate(element, relatedElem) { + if (!element) { + return; + } + element.classList.remove(CLASS_NAME_ACTIVE); + element.blur(); + this._deactivate(SelectorEngine.getElementFromSelector(element)); // Search and deactivate the shown section too + + const complete = () => { + if (element.getAttribute('role') !== 'tab') { + element.classList.remove(CLASS_NAME_SHOW$1); + return; + } + element.setAttribute('aria-selected', false); + element.setAttribute('tabindex', '-1'); + this._toggleDropDown(element, false); + EventHandler.trigger(element, EVENT_HIDDEN$1, { + relatedTarget: relatedElem + }); + }; + this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE$1)); + } + _keydown(event) { + if (![ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key)) { + return; + } + event.stopPropagation(); // stopPropagation/preventDefault both added to support up/down keys without scrolling the page + event.preventDefault(); + const children = this._getChildren().filter(element => !isDisabled(element)); + let nextActiveElement; + if ([HOME_KEY, END_KEY].includes(event.key)) { + nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]; + } else { + const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key); + nextActiveElement = getNextActiveElement(children, event.target, isNext, true); + } + if (nextActiveElement) { + nextActiveElement.focus({ + preventScroll: true + }); + Tab.getOrCreateInstance(nextActiveElement).show(); + } + } + _getChildren() { + // collection of inner elements + return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent); + } + _getActiveElem() { + return this._getChildren().find(child => this._elemIsActive(child)) || null; + } + _setInitialAttributes(parent, children) { + this._setAttributeIfNotExists(parent, 'role', 'tablist'); + for (const child of children) { + this._setInitialAttributesOnChild(child); + } + } + _setInitialAttributesOnChild(child) { + child = this._getInnerElement(child); + const isActive = this._elemIsActive(child); + const outerElem = this._getOuterElement(child); + child.setAttribute('aria-selected', isActive); + if (outerElem !== child) { + this._setAttributeIfNotExists(outerElem, 'role', 'presentation'); + } + if (!isActive) { + child.setAttribute('tabindex', '-1'); + } + this._setAttributeIfNotExists(child, 'role', 'tab'); + + // set attributes to the related panel too + this._setInitialAttributesOnTargetPanel(child); + } + _setInitialAttributesOnTargetPanel(child) { + const target = SelectorEngine.getElementFromSelector(child); + if (!target) { + return; + } + this._setAttributeIfNotExists(target, 'role', 'tabpanel'); + if (child.id) { + this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`); + } + } + _toggleDropDown(element, open) { + const outerElem = this._getOuterElement(element); + if (!outerElem.classList.contains(CLASS_DROPDOWN)) { + return; + } + const toggle = (selector, className) => { + const element = SelectorEngine.findOne(selector, outerElem); + if (element) { + element.classList.toggle(className, open); + } + }; + toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE); + toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW$1); + outerElem.setAttribute('aria-expanded', open); + } + _setAttributeIfNotExists(element, attribute, value) { + if (!element.hasAttribute(attribute)) { + element.setAttribute(attribute, value); + } + } + _elemIsActive(elem) { + return elem.classList.contains(CLASS_NAME_ACTIVE); + } + + // Try to get the inner element (usually the .nav-link) + _getInnerElement(elem) { + return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem); + } + + // Try to get the outer element (usually the .nav-item) + _getOuterElement(elem) { + return elem.closest(SELECTOR_OUTER) || elem; + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Tab.getOrCreateInstance(this); + if (typeof config !== 'string') { + return; + } + if (data[config] === undefined || config.startsWith('_') || config === 'constructor') { + throw new TypeError(`No method named "${config}"`); + } + data[config](); + }); + } + } + + /** + * Data API implementation + */ + + EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) { + if (['A', 'AREA'].includes(this.tagName)) { + event.preventDefault(); + } + if (isDisabled(this)) { + return; + } + Tab.getOrCreateInstance(this).show(); + }); + + /** + * Initialize on focus + */ + EventHandler.on(window, EVENT_LOAD_DATA_API, () => { + for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) { + Tab.getOrCreateInstance(element); + } + }); + /** + * jQuery + */ + + defineJQueryPlugin(Tab); + + /** + * -------------------------------------------------------------------------- + * Bootstrap toast.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + + /** + * Constants + */ + + const NAME = 'toast'; + const DATA_KEY = 'bs.toast'; + const EVENT_KEY = `.${DATA_KEY}`; + const EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`; + const EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`; + const EVENT_FOCUSIN = `focusin${EVENT_KEY}`; + const EVENT_FOCUSOUT = `focusout${EVENT_KEY}`; + const EVENT_HIDE = `hide${EVENT_KEY}`; + const EVENT_HIDDEN = `hidden${EVENT_KEY}`; + const EVENT_SHOW = `show${EVENT_KEY}`; + const EVENT_SHOWN = `shown${EVENT_KEY}`; + const CLASS_NAME_FADE = 'fade'; + const CLASS_NAME_HIDE = 'hide'; // @deprecated - kept here only for backwards compatibility + const CLASS_NAME_SHOW = 'show'; + const CLASS_NAME_SHOWING = 'showing'; + const DefaultType = { + animation: 'boolean', + autohide: 'boolean', + delay: 'number' + }; + const Default = { + animation: true, + autohide: true, + delay: 5000 + }; + + /** + * Class definition + */ + + class Toast extends BaseComponent { + constructor(element, config) { + super(element, config); + this._timeout = null; + this._hasMouseInteraction = false; + this._hasKeyboardInteraction = false; + this._setListeners(); + } + + // Getters + static get Default() { + return Default; + } + static get DefaultType() { + return DefaultType; + } + static get NAME() { + return NAME; + } + + // Public + show() { + const showEvent = EventHandler.trigger(this._element, EVENT_SHOW); + if (showEvent.defaultPrevented) { + return; + } + this._clearTimeout(); + if (this._config.animation) { + this._element.classList.add(CLASS_NAME_FADE); + } + const complete = () => { + this._element.classList.remove(CLASS_NAME_SHOWING); + EventHandler.trigger(this._element, EVENT_SHOWN); + this._maybeScheduleHide(); + }; + this._element.classList.remove(CLASS_NAME_HIDE); // @deprecated + reflow(this._element); + this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING); + this._queueCallback(complete, this._element, this._config.animation); + } + hide() { + if (!this.isShown()) { + return; + } + const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE); + if (hideEvent.defaultPrevented) { + return; + } + const complete = () => { + this._element.classList.add(CLASS_NAME_HIDE); // @deprecated + this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW); + EventHandler.trigger(this._element, EVENT_HIDDEN); + }; + this._element.classList.add(CLASS_NAME_SHOWING); + this._queueCallback(complete, this._element, this._config.animation); + } + dispose() { + this._clearTimeout(); + if (this.isShown()) { + this._element.classList.remove(CLASS_NAME_SHOW); + } + super.dispose(); + } + isShown() { + return this._element.classList.contains(CLASS_NAME_SHOW); + } + + // Private + _maybeScheduleHide() { + if (!this._config.autohide) { + return; + } + if (this._hasMouseInteraction || this._hasKeyboardInteraction) { + return; + } + this._timeout = setTimeout(() => { + this.hide(); + }, this._config.delay); + } + _onInteraction(event, isInteracting) { + switch (event.type) { + case 'mouseover': + case 'mouseout': + { + this._hasMouseInteraction = isInteracting; + break; + } + case 'focusin': + case 'focusout': + { + this._hasKeyboardInteraction = isInteracting; + break; + } + } + if (isInteracting) { + this._clearTimeout(); + return; + } + const nextElement = event.relatedTarget; + if (this._element === nextElement || this._element.contains(nextElement)) { + return; + } + this._maybeScheduleHide(); + } + _setListeners() { + EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true)); + EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false)); + EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true)); + EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false)); + } + _clearTimeout() { + clearTimeout(this._timeout); + this._timeout = null; + } + + // Static + static jQueryInterface(config) { + return this.each(function () { + const data = Toast.getOrCreateInstance(this, config); + if (typeof config === 'string') { + if (typeof data[config] === 'undefined') { + throw new TypeError(`No method named "${config}"`); + } + data[config](this); + } + }); + } + } + + /** + * Data API implementation + */ + + enableDismissTrigger(Toast); + + /** + * jQuery + */ + + defineJQueryPlugin(Toast); + + /** + * -------------------------------------------------------------------------- + * Bootstrap index.umd.js + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + * -------------------------------------------------------------------------- + */ + + const index_umd = { + Alert, + Button, + Carousel, + Collapse, + Dropdown, + Modal, + Offcanvas, + Popover, + ScrollSpy, + Tab, + Toast, + Tooltip + }; + + return index_umd; + +})); +//# sourceMappingURL=bootstrap.js.map diff --git a/extensions/pagetop-bootsier/static/js/bootstrap.js.map b/extensions/pagetop-bootsier/static/js/bootstrap.js.map new file mode 100644 index 0000000..062cdd5 --- /dev/null +++ b/extensions/pagetop-bootsier/static/js/bootstrap.js.map @@ -0,0 +1 @@ +{"version":3,"file":"bootstrap.js","sources":["../../js/src/dom/data.js","../../js/src/util/index.js","../../js/src/dom/event-handler.js","../../js/src/dom/manipulator.js","../../js/src/util/config.js","../../js/src/base-component.js","../../js/src/dom/selector-engine.js","../../js/src/util/component-functions.js","../../js/src/alert.js","../../js/src/button.js","../../js/src/util/swipe.js","../../js/src/carousel.js","../../js/src/collapse.js","../../js/src/dropdown.js","../../js/src/util/backdrop.js","../../js/src/util/focustrap.js","../../js/src/util/scrollbar.js","../../js/src/modal.js","../../js/src/offcanvas.js","../../js/src/util/sanitizer.js","../../js/src/util/template-factory.js","../../js/src/tooltip.js","../../js/src/popover.js","../../js/src/scrollspy.js","../../js/src/tab.js","../../js/src/toast.js","../../js/index.umd.js"],"sourcesContent":["/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/data.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n/**\n * Constants\n */\n\nconst elementMap = new Map()\n\nexport default {\n set(element, key, instance) {\n if (!elementMap.has(element)) {\n elementMap.set(element, new Map())\n }\n\n const instanceMap = elementMap.get(element)\n\n // make it clear we only want one instance per element\n // can be removed later when multiple key/instances are fine to be used\n if (!instanceMap.has(key) && instanceMap.size !== 0) {\n // eslint-disable-next-line no-console\n console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)\n return\n }\n\n instanceMap.set(key, instance)\n },\n\n get(element, key) {\n if (elementMap.has(element)) {\n return elementMap.get(element).get(key) || null\n }\n\n return null\n },\n\n remove(element, key) {\n if (!elementMap.has(element)) {\n return\n }\n\n const instanceMap = elementMap.get(element)\n\n instanceMap.delete(key)\n\n // free up element references if there are no instances left for an element\n if (instanceMap.size === 0) {\n elementMap.delete(element)\n }\n }\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/index.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nconst MAX_UID = 1_000_000\nconst MILLISECONDS_MULTIPLIER = 1000\nconst TRANSITION_END = 'transitionend'\n\n/**\n * Properly escape IDs selectors to handle weird IDs\n * @param {string} selector\n * @returns {string}\n */\nconst parseSelector = selector => {\n if (selector && window.CSS && window.CSS.escape) {\n // document.querySelector needs escaping to handle IDs (html5+) containing for instance /\n selector = selector.replace(/#([^\\s\"#']+)/g, (match, id) => `#${CSS.escape(id)}`)\n }\n\n return selector\n}\n\n// Shout-out Angus Croll (https://goo.gl/pxwQGp)\nconst toType = object => {\n if (object === null || object === undefined) {\n return `${object}`\n }\n\n return Object.prototype.toString.call(object).match(/\\s([a-z]+)/i)[1].toLowerCase()\n}\n\n/**\n * Public Util API\n */\n\nconst getUID = prefix => {\n do {\n prefix += Math.floor(Math.random() * MAX_UID)\n } while (document.getElementById(prefix))\n\n return prefix\n}\n\nconst getTransitionDurationFromElement = element => {\n if (!element) {\n return 0\n }\n\n // Get transition-duration of the element\n let { transitionDuration, transitionDelay } = window.getComputedStyle(element)\n\n const floatTransitionDuration = Number.parseFloat(transitionDuration)\n const floatTransitionDelay = Number.parseFloat(transitionDelay)\n\n // Return 0 if element or transition duration is not found\n if (!floatTransitionDuration && !floatTransitionDelay) {\n return 0\n }\n\n // If multiple durations are defined, take the first\n transitionDuration = transitionDuration.split(',')[0]\n transitionDelay = transitionDelay.split(',')[0]\n\n return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER\n}\n\nconst triggerTransitionEnd = element => {\n element.dispatchEvent(new Event(TRANSITION_END))\n}\n\nconst isElement = object => {\n if (!object || typeof object !== 'object') {\n return false\n }\n\n if (typeof object.jquery !== 'undefined') {\n object = object[0]\n }\n\n return typeof object.nodeType !== 'undefined'\n}\n\nconst getElement = object => {\n // it's a jQuery object or a node element\n if (isElement(object)) {\n return object.jquery ? object[0] : object\n }\n\n if (typeof object === 'string' && object.length > 0) {\n return document.querySelector(parseSelector(object))\n }\n\n return null\n}\n\nconst isVisible = element => {\n if (!isElement(element) || element.getClientRects().length === 0) {\n return false\n }\n\n const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'\n // Handle `details` element as its content may falsie appear visible when it is closed\n const closedDetails = element.closest('details:not([open])')\n\n if (!closedDetails) {\n return elementIsVisible\n }\n\n if (closedDetails !== element) {\n const summary = element.closest('summary')\n if (summary && summary.parentNode !== closedDetails) {\n return false\n }\n\n if (summary === null) {\n return false\n }\n }\n\n return elementIsVisible\n}\n\nconst isDisabled = element => {\n if (!element || element.nodeType !== Node.ELEMENT_NODE) {\n return true\n }\n\n if (element.classList.contains('disabled')) {\n return true\n }\n\n if (typeof element.disabled !== 'undefined') {\n return element.disabled\n }\n\n return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'\n}\n\nconst findShadowRoot = element => {\n if (!document.documentElement.attachShadow) {\n return null\n }\n\n // Can find the shadow root otherwise it'll return the document\n if (typeof element.getRootNode === 'function') {\n const root = element.getRootNode()\n return root instanceof ShadowRoot ? root : null\n }\n\n if (element instanceof ShadowRoot) {\n return element\n }\n\n // when we don't find a shadow root\n if (!element.parentNode) {\n return null\n }\n\n return findShadowRoot(element.parentNode)\n}\n\nconst noop = () => {}\n\n/**\n * Trick to restart an element's animation\n *\n * @param {HTMLElement} element\n * @return void\n *\n * @see https://www.harrytheo.com/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation\n */\nconst reflow = element => {\n element.offsetHeight // eslint-disable-line no-unused-expressions\n}\n\nconst getjQuery = () => {\n if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {\n return window.jQuery\n }\n\n return null\n}\n\nconst DOMContentLoadedCallbacks = []\n\nconst onDOMContentLoaded = callback => {\n if (document.readyState === 'loading') {\n // add listener on the first call when the document is in loading state\n if (!DOMContentLoadedCallbacks.length) {\n document.addEventListener('DOMContentLoaded', () => {\n for (const callback of DOMContentLoadedCallbacks) {\n callback()\n }\n })\n }\n\n DOMContentLoadedCallbacks.push(callback)\n } else {\n callback()\n }\n}\n\nconst isRTL = () => document.documentElement.dir === 'rtl'\n\nconst defineJQueryPlugin = plugin => {\n onDOMContentLoaded(() => {\n const $ = getjQuery()\n /* istanbul ignore if */\n if ($) {\n const name = plugin.NAME\n const JQUERY_NO_CONFLICT = $.fn[name]\n $.fn[name] = plugin.jQueryInterface\n $.fn[name].Constructor = plugin\n $.fn[name].noConflict = () => {\n $.fn[name] = JQUERY_NO_CONFLICT\n return plugin.jQueryInterface\n }\n }\n })\n}\n\nconst execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {\n return typeof possibleCallback === 'function' ? possibleCallback.call(...args) : defaultValue\n}\n\nconst executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {\n if (!waitForTransition) {\n execute(callback)\n return\n }\n\n const durationPadding = 5\n const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding\n\n let called = false\n\n const handler = ({ target }) => {\n if (target !== transitionElement) {\n return\n }\n\n called = true\n transitionElement.removeEventListener(TRANSITION_END, handler)\n execute(callback)\n }\n\n transitionElement.addEventListener(TRANSITION_END, handler)\n setTimeout(() => {\n if (!called) {\n triggerTransitionEnd(transitionElement)\n }\n }, emulatedDuration)\n}\n\n/**\n * Return the previous/next element of a list.\n *\n * @param {array} list The list of elements\n * @param activeElement The active element\n * @param shouldGetNext Choose to get next or previous element\n * @param isCycleAllowed\n * @return {Element|elem} The proper element\n */\nconst getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {\n const listLength = list.length\n let index = list.indexOf(activeElement)\n\n // if the element does not exist in the list return an element\n // depending on the direction and if cycle is allowed\n if (index === -1) {\n return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]\n }\n\n index += shouldGetNext ? 1 : -1\n\n if (isCycleAllowed) {\n index = (index + listLength) % listLength\n }\n\n return list[Math.max(0, Math.min(index, listLength - 1))]\n}\n\nexport {\n defineJQueryPlugin,\n execute,\n executeAfterTransition,\n findShadowRoot,\n getElement,\n getjQuery,\n getNextActiveElement,\n getTransitionDurationFromElement,\n getUID,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop,\n onDOMContentLoaded,\n parseSelector,\n reflow,\n triggerTransitionEnd,\n toType\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/event-handler.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { getjQuery } from '../util/index.js'\n\n/**\n * Constants\n */\n\nconst namespaceRegex = /[^.]*(?=\\..*)\\.|.*/\nconst stripNameRegex = /\\..*/\nconst stripUidRegex = /::\\d+$/\nconst eventRegistry = {} // Events storage\nlet uidEvent = 1\nconst customEvents = {\n mouseenter: 'mouseover',\n mouseleave: 'mouseout'\n}\n\nconst nativeEvents = new Set([\n 'click',\n 'dblclick',\n 'mouseup',\n 'mousedown',\n 'contextmenu',\n 'mousewheel',\n 'DOMMouseScroll',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'selectstart',\n 'selectend',\n 'keydown',\n 'keypress',\n 'keyup',\n 'orientationchange',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'touchcancel',\n 'pointerdown',\n 'pointermove',\n 'pointerup',\n 'pointerleave',\n 'pointercancel',\n 'gesturestart',\n 'gesturechange',\n 'gestureend',\n 'focus',\n 'blur',\n 'change',\n 'reset',\n 'select',\n 'submit',\n 'focusin',\n 'focusout',\n 'load',\n 'unload',\n 'beforeunload',\n 'resize',\n 'move',\n 'DOMContentLoaded',\n 'readystatechange',\n 'error',\n 'abort',\n 'scroll'\n])\n\n/**\n * Private methods\n */\n\nfunction makeEventUid(element, uid) {\n return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++\n}\n\nfunction getElementEvents(element) {\n const uid = makeEventUid(element)\n\n element.uidEvent = uid\n eventRegistry[uid] = eventRegistry[uid] || {}\n\n return eventRegistry[uid]\n}\n\nfunction bootstrapHandler(element, fn) {\n return function handler(event) {\n hydrateObj(event, { delegateTarget: element })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, fn)\n }\n\n return fn.apply(element, [event])\n }\n}\n\nfunction bootstrapDelegationHandler(element, selector, fn) {\n return function handler(event) {\n const domElements = element.querySelectorAll(selector)\n\n for (let { target } = event; target && target !== this; target = target.parentNode) {\n for (const domElement of domElements) {\n if (domElement !== target) {\n continue\n }\n\n hydrateObj(event, { delegateTarget: target })\n\n if (handler.oneOff) {\n EventHandler.off(element, event.type, selector, fn)\n }\n\n return fn.apply(target, [event])\n }\n }\n }\n}\n\nfunction findHandler(events, callable, delegationSelector = null) {\n return Object.values(events)\n .find(event => event.callable === callable && event.delegationSelector === delegationSelector)\n}\n\nfunction normalizeParameters(originalTypeEvent, handler, delegationFunction) {\n const isDelegated = typeof handler === 'string'\n // TODO: tooltip passes `false` instead of selector, so we need to check\n const callable = isDelegated ? delegationFunction : (handler || delegationFunction)\n let typeEvent = getTypeEvent(originalTypeEvent)\n\n if (!nativeEvents.has(typeEvent)) {\n typeEvent = originalTypeEvent\n }\n\n return [isDelegated, callable, typeEvent]\n}\n\nfunction addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n\n // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position\n // this prevents the handler from being dispatched the same way as mouseover or mouseout does\n if (originalTypeEvent in customEvents) {\n const wrapFunction = fn => {\n return function (event) {\n if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {\n return fn.call(this, event)\n }\n }\n }\n\n callable = wrapFunction(callable)\n }\n\n const events = getElementEvents(element)\n const handlers = events[typeEvent] || (events[typeEvent] = {})\n const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)\n\n if (previousFunction) {\n previousFunction.oneOff = previousFunction.oneOff && oneOff\n\n return\n }\n\n const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))\n const fn = isDelegated ?\n bootstrapDelegationHandler(element, handler, callable) :\n bootstrapHandler(element, callable)\n\n fn.delegationSelector = isDelegated ? handler : null\n fn.callable = callable\n fn.oneOff = oneOff\n fn.uidEvent = uid\n handlers[uid] = fn\n\n element.addEventListener(typeEvent, fn, isDelegated)\n}\n\nfunction removeHandler(element, events, typeEvent, handler, delegationSelector) {\n const fn = findHandler(events[typeEvent], handler, delegationSelector)\n\n if (!fn) {\n return\n }\n\n element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))\n delete events[typeEvent][fn.uidEvent]\n}\n\nfunction removeNamespacedHandlers(element, events, typeEvent, namespace) {\n const storeElementEvent = events[typeEvent] || {}\n\n for (const [handlerKey, event] of Object.entries(storeElementEvent)) {\n if (handlerKey.includes(namespace)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n}\n\nfunction getTypeEvent(event) {\n // allow to get the native events from namespaced events ('click.bs.button' --> 'click')\n event = event.replace(stripNameRegex, '')\n return customEvents[event] || event\n}\n\nconst EventHandler = {\n on(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, false)\n },\n\n one(element, event, handler, delegationFunction) {\n addHandler(element, event, handler, delegationFunction, true)\n },\n\n off(element, originalTypeEvent, handler, delegationFunction) {\n if (typeof originalTypeEvent !== 'string' || !element) {\n return\n }\n\n const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)\n const inNamespace = typeEvent !== originalTypeEvent\n const events = getElementEvents(element)\n const storeElementEvent = events[typeEvent] || {}\n const isNamespace = originalTypeEvent.startsWith('.')\n\n if (typeof callable !== 'undefined') {\n // Simplest case: handler is passed, remove that listener ONLY.\n if (!Object.keys(storeElementEvent).length) {\n return\n }\n\n removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)\n return\n }\n\n if (isNamespace) {\n for (const elementEvent of Object.keys(events)) {\n removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))\n }\n }\n\n for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {\n const handlerKey = keyHandlers.replace(stripUidRegex, '')\n\n if (!inNamespace || originalTypeEvent.includes(handlerKey)) {\n removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)\n }\n }\n },\n\n trigger(element, event, args) {\n if (typeof event !== 'string' || !element) {\n return null\n }\n\n const $ = getjQuery()\n const typeEvent = getTypeEvent(event)\n const inNamespace = event !== typeEvent\n\n let jQueryEvent = null\n let bubbles = true\n let nativeDispatch = true\n let defaultPrevented = false\n\n if (inNamespace && $) {\n jQueryEvent = $.Event(event, args)\n\n $(element).trigger(jQueryEvent)\n bubbles = !jQueryEvent.isPropagationStopped()\n nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()\n defaultPrevented = jQueryEvent.isDefaultPrevented()\n }\n\n const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)\n\n if (defaultPrevented) {\n evt.preventDefault()\n }\n\n if (nativeDispatch) {\n element.dispatchEvent(evt)\n }\n\n if (evt.defaultPrevented && jQueryEvent) {\n jQueryEvent.preventDefault()\n }\n\n return evt\n }\n}\n\nfunction hydrateObj(obj, meta = {}) {\n for (const [key, value] of Object.entries(meta)) {\n try {\n obj[key] = value\n } catch {\n Object.defineProperty(obj, key, {\n configurable: true,\n get() {\n return value\n }\n })\n }\n }\n\n return obj\n}\n\nexport default EventHandler\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/manipulator.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nfunction normalizeData(value) {\n if (value === 'true') {\n return true\n }\n\n if (value === 'false') {\n return false\n }\n\n if (value === Number(value).toString()) {\n return Number(value)\n }\n\n if (value === '' || value === 'null') {\n return null\n }\n\n if (typeof value !== 'string') {\n return value\n }\n\n try {\n return JSON.parse(decodeURIComponent(value))\n } catch {\n return value\n }\n}\n\nfunction normalizeDataKey(key) {\n return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)\n}\n\nconst Manipulator = {\n setDataAttribute(element, key, value) {\n element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)\n },\n\n removeDataAttribute(element, key) {\n element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)\n },\n\n getDataAttributes(element) {\n if (!element) {\n return {}\n }\n\n const attributes = {}\n const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))\n\n for (const key of bsKeys) {\n let pureKey = key.replace(/^bs/, '')\n pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1)\n attributes[pureKey] = normalizeData(element.dataset[key])\n }\n\n return attributes\n },\n\n getDataAttribute(element, key) {\n return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))\n }\n}\n\nexport default Manipulator\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/config.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport { isElement, toType } from './index.js'\n\n/**\n * Class definition\n */\n\nclass Config {\n // Getters\n static get Default() {\n return {}\n }\n\n static get DefaultType() {\n return {}\n }\n\n static get NAME() {\n throw new Error('You have to implement the static method \"NAME\", for each component!')\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n return config\n }\n\n _mergeConfigObj(config, element) {\n const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse\n\n return {\n ...this.constructor.Default,\n ...(typeof jsonConfig === 'object' ? jsonConfig : {}),\n ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),\n ...(typeof config === 'object' ? config : {})\n }\n }\n\n _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {\n for (const [property, expectedTypes] of Object.entries(configTypes)) {\n const value = config[property]\n const valueType = isElement(value) ? 'element' : toType(value)\n\n if (!new RegExp(expectedTypes).test(valueType)) {\n throw new TypeError(\n `${this.constructor.NAME.toUpperCase()}: Option \"${property}\" provided type \"${valueType}\" but expected type \"${expectedTypes}\".`\n )\n }\n }\n }\n}\n\nexport default Config\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap base-component.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Data from './dom/data.js'\nimport EventHandler from './dom/event-handler.js'\nimport Config from './util/config.js'\nimport { executeAfterTransition, getElement } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst VERSION = '5.3.8'\n\n/**\n * Class definition\n */\n\nclass BaseComponent extends Config {\n constructor(element, config) {\n super()\n\n element = getElement(element)\n if (!element) {\n return\n }\n\n this._element = element\n this._config = this._getConfig(config)\n\n Data.set(this._element, this.constructor.DATA_KEY, this)\n }\n\n // Public\n dispose() {\n Data.remove(this._element, this.constructor.DATA_KEY)\n EventHandler.off(this._element, this.constructor.EVENT_KEY)\n\n for (const propertyName of Object.getOwnPropertyNames(this)) {\n this[propertyName] = null\n }\n }\n\n // Private\n _queueCallback(callback, element, isAnimated = true) {\n executeAfterTransition(callback, element, isAnimated)\n }\n\n _getConfig(config) {\n config = this._mergeConfigObj(config, this._element)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n // Static\n static getInstance(element) {\n return Data.get(getElement(element), this.DATA_KEY)\n }\n\n static getOrCreateInstance(element, config = {}) {\n return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)\n }\n\n static get VERSION() {\n return VERSION\n }\n\n static get DATA_KEY() {\n return `bs.${this.NAME}`\n }\n\n static get EVENT_KEY() {\n return `.${this.DATA_KEY}`\n }\n\n static eventName(name) {\n return `${name}${this.EVENT_KEY}`\n }\n}\n\nexport default BaseComponent\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dom/selector-engine.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport { isDisabled, isVisible, parseSelector } from '../util/index.js'\n\nconst getSelector = element => {\n let selector = element.getAttribute('data-bs-target')\n\n if (!selector || selector === '#') {\n let hrefAttribute = element.getAttribute('href')\n\n // The only valid content that could double as a selector are IDs or classes,\n // so everything starting with `#` or `.`. If a \"real\" URL is used as the selector,\n // `document.querySelector` will rightfully complain it is invalid.\n // See https://github.com/twbs/bootstrap/issues/32273\n if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {\n return null\n }\n\n // Just in case some CMS puts out a full URL with the anchor appended\n if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {\n hrefAttribute = `#${hrefAttribute.split('#')[1]}`\n }\n\n selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null\n }\n\n return selector ? selector.split(',').map(sel => parseSelector(sel)).join(',') : null\n}\n\nconst SelectorEngine = {\n find(selector, element = document.documentElement) {\n return [].concat(...Element.prototype.querySelectorAll.call(element, selector))\n },\n\n findOne(selector, element = document.documentElement) {\n return Element.prototype.querySelector.call(element, selector)\n },\n\n children(element, selector) {\n return [].concat(...element.children).filter(child => child.matches(selector))\n },\n\n parents(element, selector) {\n const parents = []\n let ancestor = element.parentNode.closest(selector)\n\n while (ancestor) {\n parents.push(ancestor)\n ancestor = ancestor.parentNode.closest(selector)\n }\n\n return parents\n },\n\n prev(element, selector) {\n let previous = element.previousElementSibling\n\n while (previous) {\n if (previous.matches(selector)) {\n return [previous]\n }\n\n previous = previous.previousElementSibling\n }\n\n return []\n },\n // TODO: this is now unused; remove later along with prev()\n next(element, selector) {\n let next = element.nextElementSibling\n\n while (next) {\n if (next.matches(selector)) {\n return [next]\n }\n\n next = next.nextElementSibling\n }\n\n return []\n },\n\n focusableChildren(element) {\n const focusables = [\n 'a',\n 'button',\n 'input',\n 'textarea',\n 'select',\n 'details',\n '[tabindex]',\n '[contenteditable=\"true\"]'\n ].map(selector => `${selector}:not([tabindex^=\"-\"])`).join(',')\n\n return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))\n },\n\n getSelectorFromElement(element) {\n const selector = getSelector(element)\n\n if (selector) {\n return SelectorEngine.findOne(selector) ? selector : null\n }\n\n return null\n },\n\n getElementFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.findOne(selector) : null\n },\n\n getMultipleElementsFromSelector(element) {\n const selector = getSelector(element)\n\n return selector ? SelectorEngine.find(selector) : []\n }\n}\n\nexport default SelectorEngine\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/component-functions.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isDisabled } from './index.js'\n\nconst enableDismissTrigger = (component, method = 'hide') => {\n const clickEvent = `click.dismiss${component.EVENT_KEY}`\n const name = component.NAME\n\n EventHandler.on(document, clickEvent, `[data-bs-dismiss=\"${name}\"]`, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)\n const instance = component.getOrCreateInstance(target)\n\n // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method\n instance[method]()\n })\n}\n\nexport {\n enableDismissTrigger\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap alert.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'alert'\nconst DATA_KEY = 'bs.alert'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_CLOSE = `close${EVENT_KEY}`\nconst EVENT_CLOSED = `closed${EVENT_KEY}`\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\n\n/**\n * Class definition\n */\n\nclass Alert extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n close() {\n const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)\n\n if (closeEvent.defaultPrevented) {\n return\n }\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)\n this._queueCallback(() => this._destroyElement(), this._element, isAnimated)\n }\n\n // Private\n _destroyElement() {\n this._element.remove()\n EventHandler.trigger(this._element, EVENT_CLOSED)\n this.dispose()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Alert.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Alert, 'close')\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Alert)\n\nexport default Alert\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap button.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'button'\nconst DATA_KEY = 'bs.button'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"button\"]'\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\n/**\n * Class definition\n */\n\nclass Button extends BaseComponent {\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method\n this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Button.getOrCreateInstance(this)\n\n if (config === 'toggle') {\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {\n event.preventDefault()\n\n const button = event.target.closest(SELECTOR_DATA_TOGGLE)\n const data = Button.getOrCreateInstance(button)\n\n data.toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Button)\n\nexport default Button\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/swipe.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport { execute } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'swipe'\nconst EVENT_KEY = '.bs.swipe'\nconst EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`\nconst EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`\nconst EVENT_TOUCHEND = `touchend${EVENT_KEY}`\nconst EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`\nconst EVENT_POINTERUP = `pointerup${EVENT_KEY}`\nconst POINTER_TYPE_TOUCH = 'touch'\nconst POINTER_TYPE_PEN = 'pen'\nconst CLASS_NAME_POINTER_EVENT = 'pointer-event'\nconst SWIPE_THRESHOLD = 40\n\nconst Default = {\n endCallback: null,\n leftCallback: null,\n rightCallback: null\n}\n\nconst DefaultType = {\n endCallback: '(function|null)',\n leftCallback: '(function|null)',\n rightCallback: '(function|null)'\n}\n\n/**\n * Class definition\n */\n\nclass Swipe extends Config {\n constructor(element, config) {\n super()\n this._element = element\n\n if (!element || !Swipe.isSupported()) {\n return\n }\n\n this._config = this._getConfig(config)\n this._deltaX = 0\n this._supportPointerEvents = Boolean(window.PointerEvent)\n this._initEvents()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n dispose() {\n EventHandler.off(this._element, EVENT_KEY)\n }\n\n // Private\n _start(event) {\n if (!this._supportPointerEvents) {\n this._deltaX = event.touches[0].clientX\n\n return\n }\n\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX\n }\n }\n\n _end(event) {\n if (this._eventIsPointerPenTouch(event)) {\n this._deltaX = event.clientX - this._deltaX\n }\n\n this._handleSwipe()\n execute(this._config.endCallback)\n }\n\n _move(event) {\n this._deltaX = event.touches && event.touches.length > 1 ?\n 0 :\n event.touches[0].clientX - this._deltaX\n }\n\n _handleSwipe() {\n const absDeltaX = Math.abs(this._deltaX)\n\n if (absDeltaX <= SWIPE_THRESHOLD) {\n return\n }\n\n const direction = absDeltaX / this._deltaX\n\n this._deltaX = 0\n\n if (!direction) {\n return\n }\n\n execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)\n }\n\n _initEvents() {\n if (this._supportPointerEvents) {\n EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))\n EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))\n\n this._element.classList.add(CLASS_NAME_POINTER_EVENT)\n } else {\n EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))\n EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))\n EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))\n }\n }\n\n _eventIsPointerPenTouch(event) {\n return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)\n }\n\n // Static\n static isSupported() {\n return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0\n }\n}\n\nexport default Swipe\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap carousel.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getNextActiveElement,\n isRTL,\n isVisible,\n reflow,\n triggerTransitionEnd\n} from './util/index.js'\nimport Swipe from './util/swipe.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'carousel'\nconst DATA_KEY = 'bs.carousel'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch\n\nconst ORDER_NEXT = 'next'\nconst ORDER_PREV = 'prev'\nconst DIRECTION_LEFT = 'left'\nconst DIRECTION_RIGHT = 'right'\n\nconst EVENT_SLIDE = `slide${EVENT_KEY}`\nconst EVENT_SLID = `slid${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`\nconst EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`\nconst EVENT_DRAG_START = `dragstart${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_CAROUSEL = 'carousel'\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_SLIDE = 'slide'\nconst CLASS_NAME_END = 'carousel-item-end'\nconst CLASS_NAME_START = 'carousel-item-start'\nconst CLASS_NAME_NEXT = 'carousel-item-next'\nconst CLASS_NAME_PREV = 'carousel-item-prev'\n\nconst SELECTOR_ACTIVE = '.active'\nconst SELECTOR_ITEM = '.carousel-item'\nconst SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM\nconst SELECTOR_ITEM_IMG = '.carousel-item img'\nconst SELECTOR_INDICATORS = '.carousel-indicators'\nconst SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'\nconst SELECTOR_DATA_RIDE = '[data-bs-ride=\"carousel\"]'\n\nconst KEY_TO_DIRECTION = {\n [ARROW_LEFT_KEY]: DIRECTION_RIGHT,\n [ARROW_RIGHT_KEY]: DIRECTION_LEFT\n}\n\nconst Default = {\n interval: 5000,\n keyboard: true,\n pause: 'hover',\n ride: false,\n touch: true,\n wrap: true\n}\n\nconst DefaultType = {\n interval: '(number|boolean)', // TODO:v6 remove boolean support\n keyboard: 'boolean',\n pause: '(string|boolean)',\n ride: '(boolean|string)',\n touch: 'boolean',\n wrap: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Carousel extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._interval = null\n this._activeElement = null\n this._isSliding = false\n this.touchTimeout = null\n this._swipeHelper = null\n\n this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)\n this._addEventListeners()\n\n if (this._config.ride === CLASS_NAME_CAROUSEL) {\n this.cycle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n next() {\n this._slide(ORDER_NEXT)\n }\n\n nextWhenVisible() {\n // FIXME TODO use `document.visibilityState`\n // Don't call next when the page isn't visible\n // or the carousel or its parent isn't visible\n if (!document.hidden && isVisible(this._element)) {\n this.next()\n }\n }\n\n prev() {\n this._slide(ORDER_PREV)\n }\n\n pause() {\n if (this._isSliding) {\n triggerTransitionEnd(this._element)\n }\n\n this._clearInterval()\n }\n\n cycle() {\n this._clearInterval()\n this._updateInterval()\n\n this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)\n }\n\n _maybeEnableCycle() {\n if (!this._config.ride) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.cycle())\n return\n }\n\n this.cycle()\n }\n\n to(index) {\n const items = this._getItems()\n if (index > items.length - 1 || index < 0) {\n return\n }\n\n if (this._isSliding) {\n EventHandler.one(this._element, EVENT_SLID, () => this.to(index))\n return\n }\n\n const activeIndex = this._getItemIndex(this._getActive())\n if (activeIndex === index) {\n return\n }\n\n const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV\n\n this._slide(order, items[index])\n }\n\n dispose() {\n if (this._swipeHelper) {\n this._swipeHelper.dispose()\n }\n\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n config.defaultInterval = config.interval\n return config\n }\n\n _addEventListeners() {\n if (this._config.keyboard) {\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n if (this._config.pause === 'hover') {\n EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())\n EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())\n }\n\n if (this._config.touch && Swipe.isSupported()) {\n this._addTouchEventListeners()\n }\n }\n\n _addTouchEventListeners() {\n for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {\n EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())\n }\n\n const endCallBack = () => {\n if (this._config.pause !== 'hover') {\n return\n }\n\n // If it's a touch-enabled device, mouseenter/leave are fired as\n // part of the mouse compatibility events on first tap - the carousel\n // would stop cycling until user tapped out of it;\n // here, we listen for touchend, explicitly pause the carousel\n // (as if it's the second time we tap on it, mouseenter compat event\n // is NOT fired) and after a timeout (to allow for mouse compatibility\n // events to fire) we explicitly restart cycling\n\n this.pause()\n if (this.touchTimeout) {\n clearTimeout(this.touchTimeout)\n }\n\n this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)\n }\n\n const swipeConfig = {\n leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),\n rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),\n endCallback: endCallBack\n }\n\n this._swipeHelper = new Swipe(this._element, swipeConfig)\n }\n\n _keydown(event) {\n if (/input|textarea/i.test(event.target.tagName)) {\n return\n }\n\n const direction = KEY_TO_DIRECTION[event.key]\n if (direction) {\n event.preventDefault()\n this._slide(this._directionToOrder(direction))\n }\n }\n\n _getItemIndex(element) {\n return this._getItems().indexOf(element)\n }\n\n _setActiveIndicatorElement(index) {\n if (!this._indicatorsElement) {\n return\n }\n\n const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)\n\n activeIndicator.classList.remove(CLASS_NAME_ACTIVE)\n activeIndicator.removeAttribute('aria-current')\n\n const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to=\"${index}\"]`, this._indicatorsElement)\n\n if (newActiveIndicator) {\n newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)\n newActiveIndicator.setAttribute('aria-current', 'true')\n }\n }\n\n _updateInterval() {\n const element = this._activeElement || this._getActive()\n\n if (!element) {\n return\n }\n\n const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)\n\n this._config.interval = elementInterval || this._config.defaultInterval\n }\n\n _slide(order, element = null) {\n if (this._isSliding) {\n return\n }\n\n const activeElement = this._getActive()\n const isNext = order === ORDER_NEXT\n const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)\n\n if (nextElement === activeElement) {\n return\n }\n\n const nextElementIndex = this._getItemIndex(nextElement)\n\n const triggerEvent = eventName => {\n return EventHandler.trigger(this._element, eventName, {\n relatedTarget: nextElement,\n direction: this._orderToDirection(order),\n from: this._getItemIndex(activeElement),\n to: nextElementIndex\n })\n }\n\n const slideEvent = triggerEvent(EVENT_SLIDE)\n\n if (slideEvent.defaultPrevented) {\n return\n }\n\n if (!activeElement || !nextElement) {\n // Some weirdness is happening, so we bail\n // TODO: change tests that use empty divs to avoid this check\n return\n }\n\n const isCycling = Boolean(this._interval)\n this.pause()\n\n this._isSliding = true\n\n this._setActiveIndicatorElement(nextElementIndex)\n this._activeElement = nextElement\n\n const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END\n const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV\n\n nextElement.classList.add(orderClassName)\n\n reflow(nextElement)\n\n activeElement.classList.add(directionalClassName)\n nextElement.classList.add(directionalClassName)\n\n const completeCallBack = () => {\n nextElement.classList.remove(directionalClassName, orderClassName)\n nextElement.classList.add(CLASS_NAME_ACTIVE)\n\n activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)\n\n this._isSliding = false\n\n triggerEvent(EVENT_SLID)\n }\n\n this._queueCallback(completeCallBack, activeElement, this._isAnimated())\n\n if (isCycling) {\n this.cycle()\n }\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_SLIDE)\n }\n\n _getActive() {\n return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)\n }\n\n _getItems() {\n return SelectorEngine.find(SELECTOR_ITEM, this._element)\n }\n\n _clearInterval() {\n if (this._interval) {\n clearInterval(this._interval)\n this._interval = null\n }\n }\n\n _directionToOrder(direction) {\n if (isRTL()) {\n return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT\n }\n\n return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV\n }\n\n _orderToDirection(order) {\n if (isRTL()) {\n return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT\n }\n\n return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Carousel.getOrCreateInstance(this, config)\n\n if (typeof config === 'number') {\n data.to(config)\n return\n }\n\n if (typeof config === 'string') {\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {\n return\n }\n\n event.preventDefault()\n\n const carousel = Carousel.getOrCreateInstance(target)\n const slideIndex = this.getAttribute('data-bs-slide-to')\n\n if (slideIndex) {\n carousel.to(slideIndex)\n carousel._maybeEnableCycle()\n return\n }\n\n if (Manipulator.getDataAttribute(this, 'slide') === 'next') {\n carousel.next()\n carousel._maybeEnableCycle()\n return\n }\n\n carousel.prev()\n carousel._maybeEnableCycle()\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)\n\n for (const carousel of carousels) {\n Carousel.getOrCreateInstance(carousel)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Carousel)\n\nexport default Carousel\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap collapse.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n getElement,\n reflow\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'collapse'\nconst DATA_KEY = 'bs.collapse'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_COLLAPSE = 'collapse'\nconst CLASS_NAME_COLLAPSING = 'collapsing'\nconst CLASS_NAME_COLLAPSED = 'collapsed'\nconst CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`\nconst CLASS_NAME_HORIZONTAL = 'collapse-horizontal'\n\nconst WIDTH = 'width'\nconst HEIGHT = 'height'\n\nconst SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"collapse\"]'\n\nconst Default = {\n parent: null,\n toggle: true\n}\n\nconst DefaultType = {\n parent: '(null|element)',\n toggle: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Collapse extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isTransitioning = false\n this._triggerArray = []\n\n const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)\n\n for (const elem of toggleList) {\n const selector = SelectorEngine.getSelectorFromElement(elem)\n const filterElement = SelectorEngine.find(selector)\n .filter(foundElement => foundElement === this._element)\n\n if (selector !== null && filterElement.length) {\n this._triggerArray.push(elem)\n }\n }\n\n this._initializeChildren()\n\n if (!this._config.parent) {\n this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())\n }\n\n if (this._config.toggle) {\n this.toggle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n if (this._isShown()) {\n this.hide()\n } else {\n this.show()\n }\n }\n\n show() {\n if (this._isTransitioning || this._isShown()) {\n return\n }\n\n let activeChildren = []\n\n // find active children\n if (this._config.parent) {\n activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)\n .filter(element => element !== this._element)\n .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))\n }\n\n if (activeChildren.length && activeChildren[0]._isTransitioning) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n if (startEvent.defaultPrevented) {\n return\n }\n\n for (const activeInstance of activeChildren) {\n activeInstance.hide()\n }\n\n const dimension = this._getDimension()\n\n this._element.classList.remove(CLASS_NAME_COLLAPSE)\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n\n this._element.style[dimension] = 0\n\n this._addAriaAndCollapsedClass(this._triggerArray, true)\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n this._element.style[dimension] = ''\n\n EventHandler.trigger(this._element, EVENT_SHOWN)\n }\n\n const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)\n const scrollSize = `scroll${capitalizedDimension}`\n\n this._queueCallback(complete, this._element, true)\n this._element.style[dimension] = `${this._element[scrollSize]}px`\n }\n\n hide() {\n if (this._isTransitioning || !this._isShown()) {\n return\n }\n\n const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n if (startEvent.defaultPrevented) {\n return\n }\n\n const dimension = this._getDimension()\n\n this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_COLLAPSING)\n this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)\n\n for (const trigger of this._triggerArray) {\n const element = SelectorEngine.getElementFromSelector(trigger)\n\n if (element && !this._isShown(element)) {\n this._addAriaAndCollapsedClass([trigger], false)\n }\n }\n\n this._isTransitioning = true\n\n const complete = () => {\n this._isTransitioning = false\n this._element.classList.remove(CLASS_NAME_COLLAPSING)\n this._element.classList.add(CLASS_NAME_COLLAPSE)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.style[dimension] = ''\n\n this._queueCallback(complete, this._element, true)\n }\n\n // Private\n _isShown(element = this._element) {\n return element.classList.contains(CLASS_NAME_SHOW)\n }\n\n _configAfterMerge(config) {\n config.toggle = Boolean(config.toggle) // Coerce string values\n config.parent = getElement(config.parent)\n return config\n }\n\n _getDimension() {\n return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT\n }\n\n _initializeChildren() {\n if (!this._config.parent) {\n return\n }\n\n const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)\n\n for (const element of children) {\n const selected = SelectorEngine.getElementFromSelector(element)\n\n if (selected) {\n this._addAriaAndCollapsedClass([element], this._isShown(selected))\n }\n }\n }\n\n _getFirstLevelChildren(selector) {\n const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)\n // remove children if greater depth\n return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))\n }\n\n _addAriaAndCollapsedClass(triggerArray, isOpen) {\n if (!triggerArray.length) {\n return\n }\n\n for (const element of triggerArray) {\n element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)\n element.setAttribute('aria-expanded', isOpen)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n const _config = {}\n if (typeof config === 'string' && /show|hide/.test(config)) {\n _config.toggle = false\n }\n\n return this.each(function () {\n const data = Collapse.getOrCreateInstance(this, _config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n // preventDefault only for <a> elements (which change the URL) not inside the collapsible element\n if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {\n event.preventDefault()\n }\n\n for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {\n Collapse.getOrCreateInstance(element, { toggle: false }).toggle()\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Collapse)\n\nexport default Collapse\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap dropdown.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin,\n execute,\n getElement,\n getNextActiveElement,\n isDisabled,\n isElement,\n isRTL,\n isVisible,\n noop\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'dropdown'\nconst DATA_KEY = 'bs.dropdown'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst ESCAPE_KEY = 'Escape'\nconst TAB_KEY = 'Tab'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_DROPUP = 'dropup'\nconst CLASS_NAME_DROPEND = 'dropend'\nconst CLASS_NAME_DROPSTART = 'dropstart'\nconst CLASS_NAME_DROPUP_CENTER = 'dropup-center'\nconst CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"dropdown\"]:not(.disabled):not(:disabled)'\nconst SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`\nconst SELECTOR_MENU = '.dropdown-menu'\nconst SELECTOR_NAVBAR = '.navbar'\nconst SELECTOR_NAVBAR_NAV = '.navbar-nav'\nconst SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'\n\nconst PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'\nconst PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'\nconst PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'\nconst PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'\nconst PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'\nconst PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'\nconst PLACEMENT_TOPCENTER = 'top'\nconst PLACEMENT_BOTTOMCENTER = 'bottom'\n\nconst Default = {\n autoClose: true,\n boundary: 'clippingParents',\n display: 'dynamic',\n offset: [0, 2],\n popperConfig: null,\n reference: 'toggle'\n}\n\nconst DefaultType = {\n autoClose: '(boolean|string)',\n boundary: '(string|element)',\n display: 'string',\n offset: '(array|string|function)',\n popperConfig: '(null|object|function)',\n reference: '(string|element|object)'\n}\n\n/**\n * Class definition\n */\n\nclass Dropdown extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._popper = null\n this._parent = this._element.parentNode // dropdown wrapper\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||\n SelectorEngine.findOne(SELECTOR_MENU, this._parent)\n this._inNavbar = this._detectNavbar()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle() {\n return this._isShown() ? this.hide() : this.show()\n }\n\n show() {\n if (isDisabled(this._element) || this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._createPopper()\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n this._element.focus()\n this._element.setAttribute('aria-expanded', true)\n\n this._menu.classList.add(CLASS_NAME_SHOW)\n this._element.classList.add(CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)\n }\n\n hide() {\n if (isDisabled(this._element) || !this._isShown()) {\n return\n }\n\n const relatedTarget = {\n relatedTarget: this._element\n }\n\n this._completeHide(relatedTarget)\n }\n\n dispose() {\n if (this._popper) {\n this._popper.destroy()\n }\n\n super.dispose()\n }\n\n update() {\n this._inNavbar = this._detectNavbar()\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Private\n _completeHide(relatedTarget) {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n if (this._popper) {\n this._popper.destroy()\n }\n\n this._menu.classList.remove(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOW)\n this._element.setAttribute('aria-expanded', 'false')\n Manipulator.removeDataAttribute(this._menu, 'popper')\n EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)\n }\n\n _getConfig(config) {\n config = super._getConfig(config)\n\n if (typeof config.reference === 'object' && !isElement(config.reference) &&\n typeof config.reference.getBoundingClientRect !== 'function'\n ) {\n // Popper virtual elements require a getBoundingClientRect method\n throw new TypeError(`${NAME.toUpperCase()}: Option \"reference\" provided type \"object\" without a required \"getBoundingClientRect\" method.`)\n }\n\n return config\n }\n\n _createPopper() {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s dropdowns require Popper (https://popper.js.org/docs/v2/)')\n }\n\n let referenceElement = this._element\n\n if (this._config.reference === 'parent') {\n referenceElement = this._parent\n } else if (isElement(this._config.reference)) {\n referenceElement = getElement(this._config.reference)\n } else if (typeof this._config.reference === 'object') {\n referenceElement = this._config.reference\n }\n\n const popperConfig = this._getPopperConfig()\n this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)\n }\n\n _isShown() {\n return this._menu.classList.contains(CLASS_NAME_SHOW)\n }\n\n _getPlacement() {\n const parentDropdown = this._parent\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {\n return PLACEMENT_RIGHT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {\n return PLACEMENT_LEFT\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {\n return PLACEMENT_TOPCENTER\n }\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {\n return PLACEMENT_BOTTOMCENTER\n }\n\n // We need to trim the value because custom properties can also include spaces\n const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'\n\n if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {\n return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP\n }\n\n return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM\n }\n\n _detectNavbar() {\n return this._element.closest(SELECTOR_NAVBAR) !== null\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _getPopperConfig() {\n const defaultBsPopperConfig = {\n placement: this._getPlacement(),\n modifiers: [{\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n }]\n }\n\n // Disable Popper if we have a static display or Dropdown is in Navbar\n if (this._inNavbar || this._config.display === 'static') {\n Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove\n defaultBsPopperConfig.modifiers = [{\n name: 'applyStyles',\n enabled: false\n }]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _selectMenuItem({ key, target }) {\n const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))\n\n if (!items.length) {\n return\n }\n\n // if target isn't included in items (e.g. when expanding the dropdown)\n // allow cycling to get the last item in case key equals ARROW_UP_KEY\n getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Dropdown.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n\n static clearMenus(event) {\n if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {\n return\n }\n\n const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)\n\n for (const toggle of openToggles) {\n const context = Dropdown.getInstance(toggle)\n if (!context || context._config.autoClose === false) {\n continue\n }\n\n const composedPath = event.composedPath()\n const isMenuTarget = composedPath.includes(context._menu)\n if (\n composedPath.includes(context._element) ||\n (context._config.autoClose === 'inside' && !isMenuTarget) ||\n (context._config.autoClose === 'outside' && isMenuTarget)\n ) {\n continue\n }\n\n // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu\n if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {\n continue\n }\n\n const relatedTarget = { relatedTarget: context._element }\n\n if (event.type === 'click') {\n relatedTarget.clickEvent = event\n }\n\n context._completeHide(relatedTarget)\n }\n }\n\n static dataApiKeydownHandler(event) {\n // If not an UP | DOWN | ESCAPE key => not a dropdown command\n // If input/textarea && if key is other than ESCAPE => not a dropdown command\n\n const isInput = /input|textarea/i.test(event.target.tagName)\n const isEscapeEvent = event.key === ESCAPE_KEY\n const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)\n\n if (!isUpOrDownEvent && !isEscapeEvent) {\n return\n }\n\n if (isInput && !isEscapeEvent) {\n return\n }\n\n event.preventDefault()\n\n // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/\n const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?\n this :\n (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||\n SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))\n\n const instance = Dropdown.getOrCreateInstance(getToggleButton)\n\n if (isUpOrDownEvent) {\n event.stopPropagation()\n instance.show()\n instance._selectMenuItem(event)\n return\n }\n\n if (instance._isShown()) { // else is escape and we check if it is shown\n event.stopPropagation()\n instance.hide()\n getToggleButton.focus()\n }\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)\nEventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n event.preventDefault()\n Dropdown.getOrCreateInstance(this).toggle()\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Dropdown)\n\nexport default Dropdown\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/backdrop.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport Config from './config.js'\nimport {\n execute, executeAfterTransition, getElement, reflow\n} from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'backdrop'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`\n\nconst Default = {\n className: 'modal-backdrop',\n clickCallback: null,\n isAnimated: false,\n isVisible: true, // if false, we use the backdrop helper without adding any element to the dom\n rootElement: 'body' // give the choice to place backdrop under different elements\n}\n\nconst DefaultType = {\n className: 'string',\n clickCallback: '(function|null)',\n isAnimated: 'boolean',\n isVisible: 'boolean',\n rootElement: '(element|string)'\n}\n\n/**\n * Class definition\n */\n\nclass Backdrop extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isAppended = false\n this._element = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._append()\n\n const element = this._getElement()\n if (this._config.isAnimated) {\n reflow(element)\n }\n\n element.classList.add(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n execute(callback)\n })\n }\n\n hide(callback) {\n if (!this._config.isVisible) {\n execute(callback)\n return\n }\n\n this._getElement().classList.remove(CLASS_NAME_SHOW)\n\n this._emulateAnimation(() => {\n this.dispose()\n execute(callback)\n })\n }\n\n dispose() {\n if (!this._isAppended) {\n return\n }\n\n EventHandler.off(this._element, EVENT_MOUSEDOWN)\n\n this._element.remove()\n this._isAppended = false\n }\n\n // Private\n _getElement() {\n if (!this._element) {\n const backdrop = document.createElement('div')\n backdrop.className = this._config.className\n if (this._config.isAnimated) {\n backdrop.classList.add(CLASS_NAME_FADE)\n }\n\n this._element = backdrop\n }\n\n return this._element\n }\n\n _configAfterMerge(config) {\n // use getElement() with the default \"body\" to get a fresh Element on each instantiation\n config.rootElement = getElement(config.rootElement)\n return config\n }\n\n _append() {\n if (this._isAppended) {\n return\n }\n\n const element = this._getElement()\n this._config.rootElement.append(element)\n\n EventHandler.on(element, EVENT_MOUSEDOWN, () => {\n execute(this._config.clickCallback)\n })\n\n this._isAppended = true\n }\n\n _emulateAnimation(callback) {\n executeAfterTransition(callback, this._getElement(), this._config.isAnimated)\n }\n}\n\nexport default Backdrop\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/focustrap.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport EventHandler from '../dom/event-handler.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'focustrap'\nconst DATA_KEY = 'bs.focustrap'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`\n\nconst TAB_KEY = 'Tab'\nconst TAB_NAV_FORWARD = 'forward'\nconst TAB_NAV_BACKWARD = 'backward'\n\nconst Default = {\n autofocus: true,\n trapElement: null // The element to trap focus inside of\n}\n\nconst DefaultType = {\n autofocus: 'boolean',\n trapElement: 'element'\n}\n\n/**\n * Class definition\n */\n\nclass FocusTrap extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n this._isActive = false\n this._lastTabNavDirection = null\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n activate() {\n if (this._isActive) {\n return\n }\n\n if (this._config.autofocus) {\n this._config.trapElement.focus()\n }\n\n EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop\n EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))\n EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))\n\n this._isActive = true\n }\n\n deactivate() {\n if (!this._isActive) {\n return\n }\n\n this._isActive = false\n EventHandler.off(document, EVENT_KEY)\n }\n\n // Private\n _handleFocusin(event) {\n const { trapElement } = this._config\n\n if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {\n return\n }\n\n const elements = SelectorEngine.focusableChildren(trapElement)\n\n if (elements.length === 0) {\n trapElement.focus()\n } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {\n elements[elements.length - 1].focus()\n } else {\n elements[0].focus()\n }\n }\n\n _handleKeydown(event) {\n if (event.key !== TAB_KEY) {\n return\n }\n\n this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD\n }\n}\n\nexport default FocusTrap\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/scrollBar.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Manipulator from '../dom/manipulator.js'\nimport SelectorEngine from '../dom/selector-engine.js'\nimport { isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'\nconst SELECTOR_STICKY_CONTENT = '.sticky-top'\nconst PROPERTY_PADDING = 'padding-right'\nconst PROPERTY_MARGIN = 'margin-right'\n\n/**\n * Class definition\n */\n\nclass ScrollBarHelper {\n constructor() {\n this._element = document.body\n }\n\n // Public\n getWidth() {\n // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes\n const documentWidth = document.documentElement.clientWidth\n return Math.abs(window.innerWidth - documentWidth)\n }\n\n hide() {\n const width = this.getWidth()\n this._disableOverFlow()\n // give padding to element to balance the hidden scrollbar width\n this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth\n this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)\n this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)\n }\n\n reset() {\n this._resetElementAttributes(this._element, 'overflow')\n this._resetElementAttributes(this._element, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)\n this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)\n }\n\n isOverflowing() {\n return this.getWidth() > 0\n }\n\n // Private\n _disableOverFlow() {\n this._saveInitialAttribute(this._element, 'overflow')\n this._element.style.overflow = 'hidden'\n }\n\n _setElementAttributes(selector, styleProperty, callback) {\n const scrollbarWidth = this.getWidth()\n const manipulationCallBack = element => {\n if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {\n return\n }\n\n this._saveInitialAttribute(element, styleProperty)\n const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)\n element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _saveInitialAttribute(element, styleProperty) {\n const actualValue = element.style.getPropertyValue(styleProperty)\n if (actualValue) {\n Manipulator.setDataAttribute(element, styleProperty, actualValue)\n }\n }\n\n _resetElementAttributes(selector, styleProperty) {\n const manipulationCallBack = element => {\n const value = Manipulator.getDataAttribute(element, styleProperty)\n // We only want to remove the property if the value is `null`; the value can also be zero\n if (value === null) {\n element.style.removeProperty(styleProperty)\n return\n }\n\n Manipulator.removeDataAttribute(element, styleProperty)\n element.style.setProperty(styleProperty, value)\n }\n\n this._applyManipulationCallback(selector, manipulationCallBack)\n }\n\n _applyManipulationCallback(selector, callBack) {\n if (isElement(selector)) {\n callBack(selector)\n return\n }\n\n for (const sel of SelectorEngine.find(selector, this._element)) {\n callBack(sel)\n }\n }\n}\n\nexport default ScrollBarHelper\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap modal.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin, isRTL, isVisible, reflow\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'modal'\nconst DATA_KEY = 'bs.modal'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst ESCAPE_KEY = 'Escape'\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`\nconst EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_OPEN = 'modal-open'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_STATIC = 'modal-static'\n\nconst OPEN_SELECTOR = '.modal.show'\nconst SELECTOR_DIALOG = '.modal-dialog'\nconst SELECTOR_MODAL_BODY = '.modal-body'\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"modal\"]'\n\nconst Default = {\n backdrop: true,\n focus: true,\n keyboard: true\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n focus: 'boolean',\n keyboard: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Modal extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._isShown = false\n this._isTransitioning = false\n this._scrollBar = new ScrollBarHelper()\n\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown || this._isTransitioning) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {\n relatedTarget\n })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._isTransitioning = true\n\n this._scrollBar.hide()\n\n document.body.classList.add(CLASS_NAME_OPEN)\n\n this._adjustDialog()\n\n this._backdrop.show(() => this._showElement(relatedTarget))\n }\n\n hide() {\n if (!this._isShown || this._isTransitioning) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._isShown = false\n this._isTransitioning = true\n this._focustrap.deactivate()\n\n this._element.classList.remove(CLASS_NAME_SHOW)\n\n this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())\n }\n\n dispose() {\n EventHandler.off(window, EVENT_KEY)\n EventHandler.off(this._dialog, EVENT_KEY)\n\n this._backdrop.dispose()\n this._focustrap.deactivate()\n\n super.dispose()\n }\n\n handleUpdate() {\n this._adjustDialog()\n }\n\n // Private\n _initializeBackDrop() {\n return new Backdrop({\n isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,\n isAnimated: this._isAnimated()\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _showElement(relatedTarget) {\n // try to append dynamic modal\n if (!document.body.contains(this._element)) {\n document.body.append(this._element)\n }\n\n this._element.style.display = 'block'\n this._element.removeAttribute('aria-hidden')\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.scrollTop = 0\n\n const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)\n if (modalBody) {\n modalBody.scrollTop = 0\n }\n\n reflow(this._element)\n\n this._element.classList.add(CLASS_NAME_SHOW)\n\n const transitionComplete = () => {\n if (this._config.focus) {\n this._focustrap.activate()\n }\n\n this._isTransitioning = false\n EventHandler.trigger(this._element, EVENT_SHOWN, {\n relatedTarget\n })\n }\n\n this._queueCallback(transitionComplete, this._dialog, this._isAnimated())\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n this._triggerBackdropTransition()\n })\n\n EventHandler.on(window, EVENT_RESIZE, () => {\n if (this._isShown && !this._isTransitioning) {\n this._adjustDialog()\n }\n })\n\n EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {\n // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks\n EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {\n if (this._element !== event.target || this._element !== event2.target) {\n return\n }\n\n if (this._config.backdrop === 'static') {\n this._triggerBackdropTransition()\n return\n }\n\n if (this._config.backdrop) {\n this.hide()\n }\n })\n })\n }\n\n _hideModal() {\n this._element.style.display = 'none'\n this._element.setAttribute('aria-hidden', true)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n this._isTransitioning = false\n\n this._backdrop.hide(() => {\n document.body.classList.remove(CLASS_NAME_OPEN)\n this._resetAdjustments()\n this._scrollBar.reset()\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n })\n }\n\n _isAnimated() {\n return this._element.classList.contains(CLASS_NAME_FADE)\n }\n\n _triggerBackdropTransition() {\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const initialOverflowY = this._element.style.overflowY\n // return if the following background transition hasn't yet completed\n if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {\n return\n }\n\n if (!isModalOverflowing) {\n this._element.style.overflowY = 'hidden'\n }\n\n this._element.classList.add(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.classList.remove(CLASS_NAME_STATIC)\n this._queueCallback(() => {\n this._element.style.overflowY = initialOverflowY\n }, this._dialog)\n }, this._dialog)\n\n this._element.focus()\n }\n\n /**\n * The following methods are used to handle overflowing modals\n */\n\n _adjustDialog() {\n const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight\n const scrollbarWidth = this._scrollBar.getWidth()\n const isBodyOverflowing = scrollbarWidth > 0\n\n if (isBodyOverflowing && !isModalOverflowing) {\n const property = isRTL() ? 'paddingLeft' : 'paddingRight'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n\n if (!isBodyOverflowing && isModalOverflowing) {\n const property = isRTL() ? 'paddingRight' : 'paddingLeft'\n this._element.style[property] = `${scrollbarWidth}px`\n }\n }\n\n _resetAdjustments() {\n this._element.style.paddingLeft = ''\n this._element.style.paddingRight = ''\n }\n\n // Static\n static jQueryInterface(config, relatedTarget) {\n return this.each(function () {\n const data = Modal.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](relatedTarget)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n EventHandler.one(target, EVENT_SHOW, showEvent => {\n if (showEvent.defaultPrevented) {\n // only register focus restorer if modal will actually get shown\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n if (isVisible(this)) {\n this.focus()\n }\n })\n })\n\n // avoid conflict when clicking modal toggler while another one is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen) {\n Modal.getInstance(alreadyOpen).hide()\n }\n\n const data = Modal.getOrCreateInstance(target)\n\n data.toggle(this)\n})\n\nenableDismissTrigger(Modal)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Modal)\n\nexport default Modal\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap offcanvas.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport Backdrop from './util/backdrop.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport FocusTrap from './util/focustrap.js'\nimport {\n defineJQueryPlugin,\n isDisabled,\n isVisible\n} from './util/index.js'\nimport ScrollBarHelper from './util/scrollbar.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'offcanvas'\nconst DATA_KEY = 'bs.offcanvas'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\nconst ESCAPE_KEY = 'Escape'\n\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\nconst CLASS_NAME_HIDING = 'hiding'\nconst CLASS_NAME_BACKDROP = 'offcanvas-backdrop'\nconst OPEN_SELECTOR = '.offcanvas.show'\n\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_RESIZE = `resize${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`\nconst EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`\n\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"offcanvas\"]'\n\nconst Default = {\n backdrop: true,\n keyboard: true,\n scroll: false\n}\n\nconst DefaultType = {\n backdrop: '(boolean|string)',\n keyboard: 'boolean',\n scroll: 'boolean'\n}\n\n/**\n * Class definition\n */\n\nclass Offcanvas extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._isShown = false\n this._backdrop = this._initializeBackDrop()\n this._focustrap = this._initializeFocusTrap()\n this._addEventListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n toggle(relatedTarget) {\n return this._isShown ? this.hide() : this.show(relatedTarget)\n }\n\n show(relatedTarget) {\n if (this._isShown) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._isShown = true\n this._backdrop.show()\n\n if (!this._config.scroll) {\n new ScrollBarHelper().hide()\n }\n\n this._element.setAttribute('aria-modal', true)\n this._element.setAttribute('role', 'dialog')\n this._element.classList.add(CLASS_NAME_SHOWING)\n\n const completeCallBack = () => {\n if (!this._config.scroll || this._config.backdrop) {\n this._focustrap.activate()\n }\n\n this._element.classList.add(CLASS_NAME_SHOW)\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })\n }\n\n this._queueCallback(completeCallBack, this._element, true)\n }\n\n hide() {\n if (!this._isShown) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n this._focustrap.deactivate()\n this._element.blur()\n this._isShown = false\n this._element.classList.add(CLASS_NAME_HIDING)\n this._backdrop.hide()\n\n const completeCallback = () => {\n this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)\n this._element.removeAttribute('aria-modal')\n this._element.removeAttribute('role')\n\n if (!this._config.scroll) {\n new ScrollBarHelper().reset()\n }\n\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._queueCallback(completeCallback, this._element, true)\n }\n\n dispose() {\n this._backdrop.dispose()\n this._focustrap.deactivate()\n super.dispose()\n }\n\n // Private\n _initializeBackDrop() {\n const clickCallback = () => {\n if (this._config.backdrop === 'static') {\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n return\n }\n\n this.hide()\n }\n\n // 'static' option will be translated to true, and booleans will keep their value\n const isVisible = Boolean(this._config.backdrop)\n\n return new Backdrop({\n className: CLASS_NAME_BACKDROP,\n isVisible,\n isAnimated: true,\n rootElement: this._element.parentNode,\n clickCallback: isVisible ? clickCallback : null\n })\n }\n\n _initializeFocusTrap() {\n return new FocusTrap({\n trapElement: this._element\n })\n }\n\n _addEventListeners() {\n EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {\n if (event.key !== ESCAPE_KEY) {\n return\n }\n\n if (this._config.keyboard) {\n this.hide()\n return\n }\n\n EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)\n })\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Offcanvas.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n const target = SelectorEngine.getElementFromSelector(this)\n\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n EventHandler.one(target, EVENT_HIDDEN, () => {\n // focus on trigger when it is closed\n if (isVisible(this)) {\n this.focus()\n }\n })\n\n // avoid conflict when clicking a toggler of an offcanvas, while another is open\n const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)\n if (alreadyOpen && alreadyOpen !== target) {\n Offcanvas.getInstance(alreadyOpen).hide()\n }\n\n const data = Offcanvas.getOrCreateInstance(target)\n data.toggle(this)\n})\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {\n Offcanvas.getOrCreateInstance(selector).show()\n }\n})\n\nEventHandler.on(window, EVENT_RESIZE, () => {\n for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {\n if (getComputedStyle(element).position !== 'fixed') {\n Offcanvas.getOrCreateInstance(element).hide()\n }\n }\n})\n\nenableDismissTrigger(Offcanvas)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Offcanvas)\n\nexport default Offcanvas\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/sanitizer.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\n// js-docs-start allow-list\nconst ARIA_ATTRIBUTE_PATTERN = /^aria-[\\w-]*$/i\n\nexport const DefaultAllowlist = {\n // Global attributes allowed on any supplied element below.\n '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],\n a: ['target', 'href', 'title', 'rel'],\n area: [],\n b: [],\n br: [],\n col: [],\n code: [],\n dd: [],\n div: [],\n dl: [],\n dt: [],\n em: [],\n hr: [],\n h1: [],\n h2: [],\n h3: [],\n h4: [],\n h5: [],\n h6: [],\n i: [],\n img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],\n li: [],\n ol: [],\n p: [],\n pre: [],\n s: [],\n small: [],\n span: [],\n sub: [],\n sup: [],\n strong: [],\n u: [],\n ul: []\n}\n// js-docs-end allow-list\n\nconst uriAttributes = new Set([\n 'background',\n 'cite',\n 'href',\n 'itemtype',\n 'longdesc',\n 'poster',\n 'src',\n 'xlink:href'\n])\n\n/**\n * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation\n * contexts.\n *\n * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38\n */\nconst SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i\n\nconst allowedAttribute = (attribute, allowedAttributeList) => {\n const attributeName = attribute.nodeName.toLowerCase()\n\n if (allowedAttributeList.includes(attributeName)) {\n if (uriAttributes.has(attributeName)) {\n return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))\n }\n\n return true\n }\n\n // Check if a regular expression validates the attribute.\n return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)\n .some(regex => regex.test(attributeName))\n}\n\nexport function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {\n if (!unsafeHtml.length) {\n return unsafeHtml\n }\n\n if (sanitizeFunction && typeof sanitizeFunction === 'function') {\n return sanitizeFunction(unsafeHtml)\n }\n\n const domParser = new window.DOMParser()\n const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')\n const elements = [].concat(...createdDocument.body.querySelectorAll('*'))\n\n for (const element of elements) {\n const elementName = element.nodeName.toLowerCase()\n\n if (!Object.keys(allowList).includes(elementName)) {\n element.remove()\n continue\n }\n\n const attributeList = [].concat(...element.attributes)\n const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])\n\n for (const attribute of attributeList) {\n if (!allowedAttribute(attribute, allowedAttributes)) {\n element.removeAttribute(attribute.nodeName)\n }\n }\n }\n\n return createdDocument.body.innerHTML\n}\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap util/template-factory.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport SelectorEngine from '../dom/selector-engine.js'\nimport Config from './config.js'\nimport { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'\nimport { execute, getElement, isElement } from './index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'TemplateFactory'\n\nconst Default = {\n allowList: DefaultAllowlist,\n content: {}, // { selector : text , selector2 : text2 , }\n extraClass: '',\n html: false,\n sanitize: true,\n sanitizeFn: null,\n template: '<div></div>'\n}\n\nconst DefaultType = {\n allowList: 'object',\n content: 'object',\n extraClass: '(string|function)',\n html: 'boolean',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n template: 'string'\n}\n\nconst DefaultContentType = {\n entry: '(string|element|function|null)',\n selector: '(string|element)'\n}\n\n/**\n * Class definition\n */\n\nclass TemplateFactory extends Config {\n constructor(config) {\n super()\n this._config = this._getConfig(config)\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n getContent() {\n return Object.values(this._config.content)\n .map(config => this._resolvePossibleFunction(config))\n .filter(Boolean)\n }\n\n hasContent() {\n return this.getContent().length > 0\n }\n\n changeContent(content) {\n this._checkContent(content)\n this._config.content = { ...this._config.content, ...content }\n return this\n }\n\n toHtml() {\n const templateWrapper = document.createElement('div')\n templateWrapper.innerHTML = this._maybeSanitize(this._config.template)\n\n for (const [selector, text] of Object.entries(this._config.content)) {\n this._setContent(templateWrapper, text, selector)\n }\n\n const template = templateWrapper.children[0]\n const extraClass = this._resolvePossibleFunction(this._config.extraClass)\n\n if (extraClass) {\n template.classList.add(...extraClass.split(' '))\n }\n\n return template\n }\n\n // Private\n _typeCheckConfig(config) {\n super._typeCheckConfig(config)\n this._checkContent(config.content)\n }\n\n _checkContent(arg) {\n for (const [selector, content] of Object.entries(arg)) {\n super._typeCheckConfig({ selector, entry: content }, DefaultContentType)\n }\n }\n\n _setContent(template, content, selector) {\n const templateElement = SelectorEngine.findOne(selector, template)\n\n if (!templateElement) {\n return\n }\n\n content = this._resolvePossibleFunction(content)\n\n if (!content) {\n templateElement.remove()\n return\n }\n\n if (isElement(content)) {\n this._putElementInTemplate(getElement(content), templateElement)\n return\n }\n\n if (this._config.html) {\n templateElement.innerHTML = this._maybeSanitize(content)\n return\n }\n\n templateElement.textContent = content\n }\n\n _maybeSanitize(arg) {\n return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [undefined, this])\n }\n\n _putElementInTemplate(element, templateElement) {\n if (this._config.html) {\n templateElement.innerHTML = ''\n templateElement.append(element)\n return\n }\n\n templateElement.textContent = element.textContent\n }\n}\n\nexport default TemplateFactory\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tooltip.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport * as Popper from '@popperjs/core'\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport Manipulator from './dom/manipulator.js'\nimport {\n defineJQueryPlugin, execute, findShadowRoot, getElement, getUID, isRTL, noop\n} from './util/index.js'\nimport { DefaultAllowlist } from './util/sanitizer.js'\nimport TemplateFactory from './util/template-factory.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tooltip'\nconst DISALLOWED_ATTRIBUTES = new Set(['sanitize', 'allowList', 'sanitizeFn'])\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_MODAL = 'modal'\nconst CLASS_NAME_SHOW = 'show'\n\nconst SELECTOR_TOOLTIP_INNER = '.tooltip-inner'\nconst SELECTOR_MODAL = `.${CLASS_NAME_MODAL}`\n\nconst EVENT_MODAL_HIDE = 'hide.bs.modal'\n\nconst TRIGGER_HOVER = 'hover'\nconst TRIGGER_FOCUS = 'focus'\nconst TRIGGER_CLICK = 'click'\nconst TRIGGER_MANUAL = 'manual'\n\nconst EVENT_HIDE = 'hide'\nconst EVENT_HIDDEN = 'hidden'\nconst EVENT_SHOW = 'show'\nconst EVENT_SHOWN = 'shown'\nconst EVENT_INSERTED = 'inserted'\nconst EVENT_CLICK = 'click'\nconst EVENT_FOCUSIN = 'focusin'\nconst EVENT_FOCUSOUT = 'focusout'\nconst EVENT_MOUSEENTER = 'mouseenter'\nconst EVENT_MOUSELEAVE = 'mouseleave'\n\nconst AttachmentMap = {\n AUTO: 'auto',\n TOP: 'top',\n RIGHT: isRTL() ? 'left' : 'right',\n BOTTOM: 'bottom',\n LEFT: isRTL() ? 'right' : 'left'\n}\n\nconst Default = {\n allowList: DefaultAllowlist,\n animation: true,\n boundary: 'clippingParents',\n container: false,\n customClass: '',\n delay: 0,\n fallbackPlacements: ['top', 'right', 'bottom', 'left'],\n html: false,\n offset: [0, 6],\n placement: 'top',\n popperConfig: null,\n sanitize: true,\n sanitizeFn: null,\n selector: false,\n template: '<div class=\"tooltip\" role=\"tooltip\">' +\n '<div class=\"tooltip-arrow\"></div>' +\n '<div class=\"tooltip-inner\"></div>' +\n '</div>',\n title: '',\n trigger: 'hover focus'\n}\n\nconst DefaultType = {\n allowList: 'object',\n animation: 'boolean',\n boundary: '(string|element)',\n container: '(string|element|boolean)',\n customClass: '(string|function)',\n delay: '(number|object)',\n fallbackPlacements: 'array',\n html: 'boolean',\n offset: '(array|string|function)',\n placement: '(string|function)',\n popperConfig: '(null|object|function)',\n sanitize: 'boolean',\n sanitizeFn: '(null|function)',\n selector: '(string|boolean)',\n template: 'string',\n title: '(string|element|function)',\n trigger: 'string'\n}\n\n/**\n * Class definition\n */\n\nclass Tooltip extends BaseComponent {\n constructor(element, config) {\n if (typeof Popper === 'undefined') {\n throw new TypeError('Bootstrap\\'s tooltips require Popper (https://popper.js.org/docs/v2/)')\n }\n\n super(element, config)\n\n // Private\n this._isEnabled = true\n this._timeout = 0\n this._isHovered = null\n this._activeTrigger = {}\n this._popper = null\n this._templateFactory = null\n this._newContent = null\n\n // Protected\n this.tip = null\n\n this._setListeners()\n\n if (!this._config.selector) {\n this._fixTitle()\n }\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n enable() {\n this._isEnabled = true\n }\n\n disable() {\n this._isEnabled = false\n }\n\n toggleEnabled() {\n this._isEnabled = !this._isEnabled\n }\n\n toggle() {\n if (!this._isEnabled) {\n return\n }\n\n if (this._isShown()) {\n this._leave()\n return\n }\n\n this._enter()\n }\n\n dispose() {\n clearTimeout(this._timeout)\n\n EventHandler.off(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n\n if (this._element.getAttribute('data-bs-original-title')) {\n this._element.setAttribute('title', this._element.getAttribute('data-bs-original-title'))\n }\n\n this._disposePopper()\n super.dispose()\n }\n\n show() {\n if (this._element.style.display === 'none') {\n throw new Error('Please use show on visible elements')\n }\n\n if (!(this._isWithContent() && this._isEnabled)) {\n return\n }\n\n const showEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOW))\n const shadowRoot = findShadowRoot(this._element)\n const isInTheDom = (shadowRoot || this._element.ownerDocument.documentElement).contains(this._element)\n\n if (showEvent.defaultPrevented || !isInTheDom) {\n return\n }\n\n // TODO: v6 remove this or make it optional\n this._disposePopper()\n\n const tip = this._getTipElement()\n\n this._element.setAttribute('aria-describedby', tip.getAttribute('id'))\n\n const { container } = this._config\n\n if (!this._element.ownerDocument.documentElement.contains(this.tip)) {\n container.append(tip)\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_INSERTED))\n }\n\n this._popper = this._createPopper(tip)\n\n tip.classList.add(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we add extra\n // empty mouseover listeners to the body's immediate children;\n // only needed because of broken event delegation on iOS\n // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.on(element, 'mouseover', noop)\n }\n }\n\n const complete = () => {\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_SHOWN))\n\n if (this._isHovered === false) {\n this._leave()\n }\n\n this._isHovered = false\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n hide() {\n if (!this._isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDE))\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const tip = this._getTipElement()\n tip.classList.remove(CLASS_NAME_SHOW)\n\n // If this is a touch-enabled device we remove the extra\n // empty mouseover listeners we added for iOS support\n if ('ontouchstart' in document.documentElement) {\n for (const element of [].concat(...document.body.children)) {\n EventHandler.off(element, 'mouseover', noop)\n }\n }\n\n this._activeTrigger[TRIGGER_CLICK] = false\n this._activeTrigger[TRIGGER_FOCUS] = false\n this._activeTrigger[TRIGGER_HOVER] = false\n this._isHovered = null // it is a trick to support manual triggering\n\n const complete = () => {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n if (!this._isHovered) {\n this._disposePopper()\n }\n\n this._element.removeAttribute('aria-describedby')\n EventHandler.trigger(this._element, this.constructor.eventName(EVENT_HIDDEN))\n }\n\n this._queueCallback(complete, this.tip, this._isAnimated())\n }\n\n update() {\n if (this._popper) {\n this._popper.update()\n }\n }\n\n // Protected\n _isWithContent() {\n return Boolean(this._getTitle())\n }\n\n _getTipElement() {\n if (!this.tip) {\n this.tip = this._createTipElement(this._newContent || this._getContentForTemplate())\n }\n\n return this.tip\n }\n\n _createTipElement(content) {\n const tip = this._getTemplateFactory(content).toHtml()\n\n // TODO: remove this check in v6\n if (!tip) {\n return null\n }\n\n tip.classList.remove(CLASS_NAME_FADE, CLASS_NAME_SHOW)\n // TODO: v6 the following can be achieved with CSS only\n tip.classList.add(`bs-${this.constructor.NAME}-auto`)\n\n const tipId = getUID(this.constructor.NAME).toString()\n\n tip.setAttribute('id', tipId)\n\n if (this._isAnimated()) {\n tip.classList.add(CLASS_NAME_FADE)\n }\n\n return tip\n }\n\n setContent(content) {\n this._newContent = content\n if (this._isShown()) {\n this._disposePopper()\n this.show()\n }\n }\n\n _getTemplateFactory(content) {\n if (this._templateFactory) {\n this._templateFactory.changeContent(content)\n } else {\n this._templateFactory = new TemplateFactory({\n ...this._config,\n // the `content` var has to be after `this._config`\n // to override config.content in case of popover\n content,\n extraClass: this._resolvePossibleFunction(this._config.customClass)\n })\n }\n\n return this._templateFactory\n }\n\n _getContentForTemplate() {\n return {\n [SELECTOR_TOOLTIP_INNER]: this._getTitle()\n }\n }\n\n _getTitle() {\n return this._resolvePossibleFunction(this._config.title) || this._element.getAttribute('data-bs-original-title')\n }\n\n // Private\n _initializeOnDelegatedTarget(event) {\n return this.constructor.getOrCreateInstance(event.delegateTarget, this._getDelegateConfig())\n }\n\n _isAnimated() {\n return this._config.animation || (this.tip && this.tip.classList.contains(CLASS_NAME_FADE))\n }\n\n _isShown() {\n return this.tip && this.tip.classList.contains(CLASS_NAME_SHOW)\n }\n\n _createPopper(tip) {\n const placement = execute(this._config.placement, [this, tip, this._element])\n const attachment = AttachmentMap[placement.toUpperCase()]\n return Popper.createPopper(this._element, tip, this._getPopperConfig(attachment))\n }\n\n _getOffset() {\n const { offset } = this._config\n\n if (typeof offset === 'string') {\n return offset.split(',').map(value => Number.parseInt(value, 10))\n }\n\n if (typeof offset === 'function') {\n return popperData => offset(popperData, this._element)\n }\n\n return offset\n }\n\n _resolvePossibleFunction(arg) {\n return execute(arg, [this._element, this._element])\n }\n\n _getPopperConfig(attachment) {\n const defaultBsPopperConfig = {\n placement: attachment,\n modifiers: [\n {\n name: 'flip',\n options: {\n fallbackPlacements: this._config.fallbackPlacements\n }\n },\n {\n name: 'offset',\n options: {\n offset: this._getOffset()\n }\n },\n {\n name: 'preventOverflow',\n options: {\n boundary: this._config.boundary\n }\n },\n {\n name: 'arrow',\n options: {\n element: `.${this.constructor.NAME}-arrow`\n }\n },\n {\n name: 'preSetPlacement',\n enabled: true,\n phase: 'beforeMain',\n fn: data => {\n // Pre-set Popper's placement attribute in order to read the arrow sizes properly.\n // Otherwise, Popper mixes up the width and height dimensions since the initial arrow style is for top placement\n this._getTipElement().setAttribute('data-popper-placement', data.state.placement)\n }\n }\n ]\n }\n\n return {\n ...defaultBsPopperConfig,\n ...execute(this._config.popperConfig, [undefined, defaultBsPopperConfig])\n }\n }\n\n _setListeners() {\n const triggers = this._config.trigger.split(' ')\n\n for (const trigger of triggers) {\n if (trigger === 'click') {\n EventHandler.on(this._element, this.constructor.eventName(EVENT_CLICK), this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[TRIGGER_CLICK] = !(context._isShown() && context._activeTrigger[TRIGGER_CLICK])\n context.toggle()\n })\n } else if (trigger !== TRIGGER_MANUAL) {\n const eventIn = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSEENTER) :\n this.constructor.eventName(EVENT_FOCUSIN)\n const eventOut = trigger === TRIGGER_HOVER ?\n this.constructor.eventName(EVENT_MOUSELEAVE) :\n this.constructor.eventName(EVENT_FOCUSOUT)\n\n EventHandler.on(this._element, eventIn, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusin' ? TRIGGER_FOCUS : TRIGGER_HOVER] = true\n context._enter()\n })\n EventHandler.on(this._element, eventOut, this._config.selector, event => {\n const context = this._initializeOnDelegatedTarget(event)\n context._activeTrigger[event.type === 'focusout' ? TRIGGER_FOCUS : TRIGGER_HOVER] =\n context._element.contains(event.relatedTarget)\n\n context._leave()\n })\n }\n }\n\n this._hideModalHandler = () => {\n if (this._element) {\n this.hide()\n }\n }\n\n EventHandler.on(this._element.closest(SELECTOR_MODAL), EVENT_MODAL_HIDE, this._hideModalHandler)\n }\n\n _fixTitle() {\n const title = this._element.getAttribute('title')\n\n if (!title) {\n return\n }\n\n if (!this._element.getAttribute('aria-label') && !this._element.textContent.trim()) {\n this._element.setAttribute('aria-label', title)\n }\n\n this._element.setAttribute('data-bs-original-title', title) // DO NOT USE IT. Is only for backwards compatibility\n this._element.removeAttribute('title')\n }\n\n _enter() {\n if (this._isShown() || this._isHovered) {\n this._isHovered = true\n return\n }\n\n this._isHovered = true\n\n this._setTimeout(() => {\n if (this._isHovered) {\n this.show()\n }\n }, this._config.delay.show)\n }\n\n _leave() {\n if (this._isWithActiveTrigger()) {\n return\n }\n\n this._isHovered = false\n\n this._setTimeout(() => {\n if (!this._isHovered) {\n this.hide()\n }\n }, this._config.delay.hide)\n }\n\n _setTimeout(handler, timeout) {\n clearTimeout(this._timeout)\n this._timeout = setTimeout(handler, timeout)\n }\n\n _isWithActiveTrigger() {\n return Object.values(this._activeTrigger).includes(true)\n }\n\n _getConfig(config) {\n const dataAttributes = Manipulator.getDataAttributes(this._element)\n\n for (const dataAttribute of Object.keys(dataAttributes)) {\n if (DISALLOWED_ATTRIBUTES.has(dataAttribute)) {\n delete dataAttributes[dataAttribute]\n }\n }\n\n config = {\n ...dataAttributes,\n ...(typeof config === 'object' && config ? config : {})\n }\n config = this._mergeConfigObj(config)\n config = this._configAfterMerge(config)\n this._typeCheckConfig(config)\n return config\n }\n\n _configAfterMerge(config) {\n config.container = config.container === false ? document.body : getElement(config.container)\n\n if (typeof config.delay === 'number') {\n config.delay = {\n show: config.delay,\n hide: config.delay\n }\n }\n\n if (typeof config.title === 'number') {\n config.title = config.title.toString()\n }\n\n if (typeof config.content === 'number') {\n config.content = config.content.toString()\n }\n\n return config\n }\n\n _getDelegateConfig() {\n const config = {}\n\n for (const [key, value] of Object.entries(this._config)) {\n if (this.constructor.Default[key] !== value) {\n config[key] = value\n }\n }\n\n config.selector = false\n config.trigger = 'manual'\n\n // In the future can be replaced with:\n // const keysWithDifferentValues = Object.entries(this._config).filter(entry => this.constructor.Default[entry[0]] !== this._config[entry[0]])\n // `Object.fromEntries(keysWithDifferentValues)`\n return config\n }\n\n _disposePopper() {\n if (this._popper) {\n this._popper.destroy()\n this._popper = null\n }\n\n if (this.tip) {\n this.tip.remove()\n this.tip = null\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tooltip.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tooltip)\n\nexport default Tooltip\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap popover.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Tooltip from './tooltip.js'\nimport { defineJQueryPlugin } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'popover'\n\nconst SELECTOR_TITLE = '.popover-header'\nconst SELECTOR_CONTENT = '.popover-body'\n\nconst Default = {\n ...Tooltip.Default,\n content: '',\n offset: [0, 8],\n placement: 'right',\n template: '<div class=\"popover\" role=\"tooltip\">' +\n '<div class=\"popover-arrow\"></div>' +\n '<h3 class=\"popover-header\"></h3>' +\n '<div class=\"popover-body\"></div>' +\n '</div>',\n trigger: 'click'\n}\n\nconst DefaultType = {\n ...Tooltip.DefaultType,\n content: '(null|string|element|function)'\n}\n\n/**\n * Class definition\n */\n\nclass Popover extends Tooltip {\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Overrides\n _isWithContent() {\n return this._getTitle() || this._getContent()\n }\n\n // Private\n _getContentForTemplate() {\n return {\n [SELECTOR_TITLE]: this._getTitle(),\n [SELECTOR_CONTENT]: this._getContent()\n }\n }\n\n _getContent() {\n return this._resolvePossibleFunction(this._config.content)\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Popover.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Popover)\n\nexport default Popover\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap scrollspy.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport {\n defineJQueryPlugin, getElement, isDisabled, isVisible\n} from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'scrollspy'\nconst DATA_KEY = 'bs.scrollspy'\nconst EVENT_KEY = `.${DATA_KEY}`\nconst DATA_API_KEY = '.data-api'\n\nconst EVENT_ACTIVATE = `activate${EVENT_KEY}`\nconst EVENT_CLICK = `click${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`\n\nconst CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'\nconst CLASS_NAME_ACTIVE = 'active'\n\nconst SELECTOR_DATA_SPY = '[data-bs-spy=\"scroll\"]'\nconst SELECTOR_TARGET_LINKS = '[href]'\nconst SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'\nconst SELECTOR_NAV_LINKS = '.nav-link'\nconst SELECTOR_NAV_ITEMS = '.nav-item'\nconst SELECTOR_LIST_ITEMS = '.list-group-item'\nconst SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`\nconst SELECTOR_DROPDOWN = '.dropdown'\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\n\nconst Default = {\n offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: '0px 0px -25%',\n smoothScroll: false,\n target: null,\n threshold: [0.1, 0.5, 1]\n}\n\nconst DefaultType = {\n offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons\n rootMargin: 'string',\n smoothScroll: 'boolean',\n target: 'element',\n threshold: 'array'\n}\n\n/**\n * Class definition\n */\n\nclass ScrollSpy extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n // this._element is the observablesContainer and config.target the menu links wrapper\n this._targetLinks = new Map()\n this._observableSections = new Map()\n this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element\n this._activeTarget = null\n this._observer = null\n this._previousScrollData = {\n visibleEntryTop: 0,\n parentScrollTop: 0\n }\n this.refresh() // initialize\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n refresh() {\n this._initializeTargetsAndObservables()\n this._maybeEnableSmoothScroll()\n\n if (this._observer) {\n this._observer.disconnect()\n } else {\n this._observer = this._getNewObserver()\n }\n\n for (const section of this._observableSections.values()) {\n this._observer.observe(section)\n }\n }\n\n dispose() {\n this._observer.disconnect()\n super.dispose()\n }\n\n // Private\n _configAfterMerge(config) {\n // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case\n config.target = getElement(config.target) || document.body\n\n // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only\n config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin\n\n if (typeof config.threshold === 'string') {\n config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))\n }\n\n return config\n }\n\n _maybeEnableSmoothScroll() {\n if (!this._config.smoothScroll) {\n return\n }\n\n // unregister any previous listeners\n EventHandler.off(this._config.target, EVENT_CLICK)\n\n EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {\n const observableSection = this._observableSections.get(event.target.hash)\n if (observableSection) {\n event.preventDefault()\n const root = this._rootElement || window\n const height = observableSection.offsetTop - this._element.offsetTop\n if (root.scrollTo) {\n root.scrollTo({ top: height, behavior: 'smooth' })\n return\n }\n\n // Chrome 60 doesn't support `scrollTo`\n root.scrollTop = height\n }\n })\n }\n\n _getNewObserver() {\n const options = {\n root: this._rootElement,\n threshold: this._config.threshold,\n rootMargin: this._config.rootMargin\n }\n\n return new IntersectionObserver(entries => this._observerCallback(entries), options)\n }\n\n // The logic of selection\n _observerCallback(entries) {\n const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)\n const activate = entry => {\n this._previousScrollData.visibleEntryTop = entry.target.offsetTop\n this._process(targetElement(entry))\n }\n\n const parentScrollTop = (this._rootElement || document.documentElement).scrollTop\n const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop\n this._previousScrollData.parentScrollTop = parentScrollTop\n\n for (const entry of entries) {\n if (!entry.isIntersecting) {\n this._activeTarget = null\n this._clearActiveClass(targetElement(entry))\n\n continue\n }\n\n const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop\n // if we are scrolling down, pick the bigger offsetTop\n if (userScrollsDown && entryIsLowerThanPrevious) {\n activate(entry)\n // if parent isn't scrolled, let's keep the first visible item, breaking the iteration\n if (!parentScrollTop) {\n return\n }\n\n continue\n }\n\n // if we are scrolling up, pick the smallest offsetTop\n if (!userScrollsDown && !entryIsLowerThanPrevious) {\n activate(entry)\n }\n }\n }\n\n _initializeTargetsAndObservables() {\n this._targetLinks = new Map()\n this._observableSections = new Map()\n\n const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)\n\n for (const anchor of targetLinks) {\n // ensure that the anchor has an id and is not disabled\n if (!anchor.hash || isDisabled(anchor)) {\n continue\n }\n\n const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)\n\n // ensure that the observableSection exists & is visible\n if (isVisible(observableSection)) {\n this._targetLinks.set(decodeURI(anchor.hash), anchor)\n this._observableSections.set(anchor.hash, observableSection)\n }\n }\n }\n\n _process(target) {\n if (this._activeTarget === target) {\n return\n }\n\n this._clearActiveClass(this._config.target)\n this._activeTarget = target\n target.classList.add(CLASS_NAME_ACTIVE)\n this._activateParents(target)\n\n EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })\n }\n\n _activateParents(target) {\n // Activate dropdown parents\n if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {\n SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))\n .classList.add(CLASS_NAME_ACTIVE)\n return\n }\n\n for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {\n // Set triggered links parents as active\n // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor\n for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {\n item.classList.add(CLASS_NAME_ACTIVE)\n }\n }\n }\n\n _clearActiveClass(parent) {\n parent.classList.remove(CLASS_NAME_ACTIVE)\n\n const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)\n for (const node of activeNodes) {\n node.classList.remove(CLASS_NAME_ACTIVE)\n }\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = ScrollSpy.getOrCreateInstance(this, config)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {\n ScrollSpy.getOrCreateInstance(spy)\n }\n})\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(ScrollSpy)\n\nexport default ScrollSpy\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap tab.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport SelectorEngine from './dom/selector-engine.js'\nimport { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'tab'\nconst DATA_KEY = 'bs.tab'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\nconst EVENT_CLICK_DATA_API = `click${EVENT_KEY}`\nconst EVENT_KEYDOWN = `keydown${EVENT_KEY}`\nconst EVENT_LOAD_DATA_API = `load${EVENT_KEY}`\n\nconst ARROW_LEFT_KEY = 'ArrowLeft'\nconst ARROW_RIGHT_KEY = 'ArrowRight'\nconst ARROW_UP_KEY = 'ArrowUp'\nconst ARROW_DOWN_KEY = 'ArrowDown'\nconst HOME_KEY = 'Home'\nconst END_KEY = 'End'\n\nconst CLASS_NAME_ACTIVE = 'active'\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_DROPDOWN = 'dropdown'\n\nconst SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'\nconst SELECTOR_DROPDOWN_MENU = '.dropdown-menu'\nconst NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`\n\nconst SELECTOR_TAB_PANEL = '.list-group, .nav, [role=\"tablist\"]'\nconst SELECTOR_OUTER = '.nav-item, .list-group-item'\nconst SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role=\"tab\"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`\nconst SELECTOR_DATA_TOGGLE = '[data-bs-toggle=\"tab\"], [data-bs-toggle=\"pill\"], [data-bs-toggle=\"list\"]' // TODO: could only be `tab` in v6\nconst SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`\n\nconst SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle=\"tab\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"pill\"], .${CLASS_NAME_ACTIVE}[data-bs-toggle=\"list\"]`\n\n/**\n * Class definition\n */\n\nclass Tab extends BaseComponent {\n constructor(element) {\n super(element)\n this._parent = this._element.closest(SELECTOR_TAB_PANEL)\n\n if (!this._parent) {\n return\n // TODO: should throw exception in v6\n // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)\n }\n\n // Set up initial aria attributes\n this._setInitialAttributes(this._parent, this._getChildren())\n\n EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))\n }\n\n // Getters\n static get NAME() {\n return NAME\n }\n\n // Public\n show() { // Shows this elem and deactivate the active sibling if exists\n const innerElem = this._element\n if (this._elemIsActive(innerElem)) {\n return\n }\n\n // Search for active tab on same parent to deactivate it\n const active = this._getActiveElem()\n\n const hideEvent = active ?\n EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :\n null\n\n const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })\n\n if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {\n return\n }\n\n this._deactivate(active, innerElem)\n this._activate(innerElem, active)\n }\n\n // Private\n _activate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.add(CLASS_NAME_ACTIVE)\n\n this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.add(CLASS_NAME_SHOW)\n return\n }\n\n element.removeAttribute('tabindex')\n element.setAttribute('aria-selected', true)\n this._toggleDropDown(element, true)\n EventHandler.trigger(element, EVENT_SHOWN, {\n relatedTarget: relatedElem\n })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _deactivate(element, relatedElem) {\n if (!element) {\n return\n }\n\n element.classList.remove(CLASS_NAME_ACTIVE)\n element.blur()\n\n this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too\n\n const complete = () => {\n if (element.getAttribute('role') !== 'tab') {\n element.classList.remove(CLASS_NAME_SHOW)\n return\n }\n\n element.setAttribute('aria-selected', false)\n element.setAttribute('tabindex', '-1')\n this._toggleDropDown(element, false)\n EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })\n }\n\n this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))\n }\n\n _keydown(event) {\n if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {\n return\n }\n\n event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page\n event.preventDefault()\n\n const children = this._getChildren().filter(element => !isDisabled(element))\n let nextActiveElement\n\n if ([HOME_KEY, END_KEY].includes(event.key)) {\n nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]\n } else {\n const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)\n nextActiveElement = getNextActiveElement(children, event.target, isNext, true)\n }\n\n if (nextActiveElement) {\n nextActiveElement.focus({ preventScroll: true })\n Tab.getOrCreateInstance(nextActiveElement).show()\n }\n }\n\n _getChildren() { // collection of inner elements\n return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)\n }\n\n _getActiveElem() {\n return this._getChildren().find(child => this._elemIsActive(child)) || null\n }\n\n _setInitialAttributes(parent, children) {\n this._setAttributeIfNotExists(parent, 'role', 'tablist')\n\n for (const child of children) {\n this._setInitialAttributesOnChild(child)\n }\n }\n\n _setInitialAttributesOnChild(child) {\n child = this._getInnerElement(child)\n const isActive = this._elemIsActive(child)\n const outerElem = this._getOuterElement(child)\n child.setAttribute('aria-selected', isActive)\n\n if (outerElem !== child) {\n this._setAttributeIfNotExists(outerElem, 'role', 'presentation')\n }\n\n if (!isActive) {\n child.setAttribute('tabindex', '-1')\n }\n\n this._setAttributeIfNotExists(child, 'role', 'tab')\n\n // set attributes to the related panel too\n this._setInitialAttributesOnTargetPanel(child)\n }\n\n _setInitialAttributesOnTargetPanel(child) {\n const target = SelectorEngine.getElementFromSelector(child)\n\n if (!target) {\n return\n }\n\n this._setAttributeIfNotExists(target, 'role', 'tabpanel')\n\n if (child.id) {\n this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)\n }\n }\n\n _toggleDropDown(element, open) {\n const outerElem = this._getOuterElement(element)\n if (!outerElem.classList.contains(CLASS_DROPDOWN)) {\n return\n }\n\n const toggle = (selector, className) => {\n const element = SelectorEngine.findOne(selector, outerElem)\n if (element) {\n element.classList.toggle(className, open)\n }\n }\n\n toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)\n toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)\n outerElem.setAttribute('aria-expanded', open)\n }\n\n _setAttributeIfNotExists(element, attribute, value) {\n if (!element.hasAttribute(attribute)) {\n element.setAttribute(attribute, value)\n }\n }\n\n _elemIsActive(elem) {\n return elem.classList.contains(CLASS_NAME_ACTIVE)\n }\n\n // Try to get the inner element (usually the .nav-link)\n _getInnerElement(elem) {\n return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)\n }\n\n // Try to get the outer element (usually the .nav-item)\n _getOuterElement(elem) {\n return elem.closest(SELECTOR_OUTER) || elem\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Tab.getOrCreateInstance(this)\n\n if (typeof config !== 'string') {\n return\n }\n\n if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config]()\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nEventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {\n if (['A', 'AREA'].includes(this.tagName)) {\n event.preventDefault()\n }\n\n if (isDisabled(this)) {\n return\n }\n\n Tab.getOrCreateInstance(this).show()\n})\n\n/**\n * Initialize on focus\n */\nEventHandler.on(window, EVENT_LOAD_DATA_API, () => {\n for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {\n Tab.getOrCreateInstance(element)\n }\n})\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Tab)\n\nexport default Tab\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap toast.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport BaseComponent from './base-component.js'\nimport EventHandler from './dom/event-handler.js'\nimport { enableDismissTrigger } from './util/component-functions.js'\nimport { defineJQueryPlugin, reflow } from './util/index.js'\n\n/**\n * Constants\n */\n\nconst NAME = 'toast'\nconst DATA_KEY = 'bs.toast'\nconst EVENT_KEY = `.${DATA_KEY}`\n\nconst EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`\nconst EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`\nconst EVENT_FOCUSIN = `focusin${EVENT_KEY}`\nconst EVENT_FOCUSOUT = `focusout${EVENT_KEY}`\nconst EVENT_HIDE = `hide${EVENT_KEY}`\nconst EVENT_HIDDEN = `hidden${EVENT_KEY}`\nconst EVENT_SHOW = `show${EVENT_KEY}`\nconst EVENT_SHOWN = `shown${EVENT_KEY}`\n\nconst CLASS_NAME_FADE = 'fade'\nconst CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility\nconst CLASS_NAME_SHOW = 'show'\nconst CLASS_NAME_SHOWING = 'showing'\n\nconst DefaultType = {\n animation: 'boolean',\n autohide: 'boolean',\n delay: 'number'\n}\n\nconst Default = {\n animation: true,\n autohide: true,\n delay: 5000\n}\n\n/**\n * Class definition\n */\n\nclass Toast extends BaseComponent {\n constructor(element, config) {\n super(element, config)\n\n this._timeout = null\n this._hasMouseInteraction = false\n this._hasKeyboardInteraction = false\n this._setListeners()\n }\n\n // Getters\n static get Default() {\n return Default\n }\n\n static get DefaultType() {\n return DefaultType\n }\n\n static get NAME() {\n return NAME\n }\n\n // Public\n show() {\n const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)\n\n if (showEvent.defaultPrevented) {\n return\n }\n\n this._clearTimeout()\n\n if (this._config.animation) {\n this._element.classList.add(CLASS_NAME_FADE)\n }\n\n const complete = () => {\n this._element.classList.remove(CLASS_NAME_SHOWING)\n EventHandler.trigger(this._element, EVENT_SHOWN)\n\n this._maybeScheduleHide()\n }\n\n this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated\n reflow(this._element)\n this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)\n\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n hide() {\n if (!this.isShown()) {\n return\n }\n\n const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)\n\n if (hideEvent.defaultPrevented) {\n return\n }\n\n const complete = () => {\n this._element.classList.add(CLASS_NAME_HIDE) // @deprecated\n this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)\n EventHandler.trigger(this._element, EVENT_HIDDEN)\n }\n\n this._element.classList.add(CLASS_NAME_SHOWING)\n this._queueCallback(complete, this._element, this._config.animation)\n }\n\n dispose() {\n this._clearTimeout()\n\n if (this.isShown()) {\n this._element.classList.remove(CLASS_NAME_SHOW)\n }\n\n super.dispose()\n }\n\n isShown() {\n return this._element.classList.contains(CLASS_NAME_SHOW)\n }\n\n // Private\n _maybeScheduleHide() {\n if (!this._config.autohide) {\n return\n }\n\n if (this._hasMouseInteraction || this._hasKeyboardInteraction) {\n return\n }\n\n this._timeout = setTimeout(() => {\n this.hide()\n }, this._config.delay)\n }\n\n _onInteraction(event, isInteracting) {\n switch (event.type) {\n case 'mouseover':\n case 'mouseout': {\n this._hasMouseInteraction = isInteracting\n break\n }\n\n case 'focusin':\n case 'focusout': {\n this._hasKeyboardInteraction = isInteracting\n break\n }\n\n default: {\n break\n }\n }\n\n if (isInteracting) {\n this._clearTimeout()\n return\n }\n\n const nextElement = event.relatedTarget\n if (this._element === nextElement || this._element.contains(nextElement)) {\n return\n }\n\n this._maybeScheduleHide()\n }\n\n _setListeners() {\n EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))\n EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))\n EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))\n }\n\n _clearTimeout() {\n clearTimeout(this._timeout)\n this._timeout = null\n }\n\n // Static\n static jQueryInterface(config) {\n return this.each(function () {\n const data = Toast.getOrCreateInstance(this, config)\n\n if (typeof config === 'string') {\n if (typeof data[config] === 'undefined') {\n throw new TypeError(`No method named \"${config}\"`)\n }\n\n data[config](this)\n }\n })\n }\n}\n\n/**\n * Data API implementation\n */\n\nenableDismissTrigger(Toast)\n\n/**\n * jQuery\n */\n\ndefineJQueryPlugin(Toast)\n\nexport default Toast\n","/**\n * --------------------------------------------------------------------------\n * Bootstrap index.umd.js\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n * --------------------------------------------------------------------------\n */\n\nimport Alert from './src/alert.js'\nimport Button from './src/button.js'\nimport Carousel from './src/carousel.js'\nimport Collapse from './src/collapse.js'\nimport Dropdown from './src/dropdown.js'\nimport Modal from './src/modal.js'\nimport Offcanvas from './src/offcanvas.js'\nimport Popover from './src/popover.js'\nimport ScrollSpy from './src/scrollspy.js'\nimport Tab from './src/tab.js'\nimport Toast from './src/toast.js'\nimport Tooltip from './src/tooltip.js'\n\nexport default {\n Alert,\n Button,\n Carousel,\n Collapse,\n Dropdown,\n Modal,\n Offcanvas,\n Popover,\n ScrollSpy,\n Tab,\n Toast,\n Tooltip\n}\n"],"names":["elementMap","Map","set","element","key","instance","has","instanceMap","get","size","console","error","Array","from","keys","remove","delete","MAX_UID","MILLISECONDS_MULTIPLIER","TRANSITION_END","parseSelector","selector","window","CSS","escape","replace","match","id","toType","object","undefined","Object","prototype","toString","call","toLowerCase","getUID","prefix","Math","floor","random","document","getElementById","getTransitionDurationFromElement","transitionDuration","transitionDelay","getComputedStyle","floatTransitionDuration","Number","parseFloat","floatTransitionDelay","split","triggerTransitionEnd","dispatchEvent","Event","isElement","jquery","nodeType","getElement","length","querySelector","isVisible","getClientRects","elementIsVisible","getPropertyValue","closedDetails","closest","summary","parentNode","isDisabled","Node","ELEMENT_NODE","classList","contains","disabled","hasAttribute","getAttribute","findShadowRoot","documentElement","attachShadow","getRootNode","root","ShadowRoot","noop","reflow","offsetHeight","getjQuery","jQuery","body","DOMContentLoadedCallbacks","onDOMContentLoaded","callback","readyState","addEventListener","push","isRTL","dir","defineJQueryPlugin","plugin","$","name","NAME","JQUERY_NO_CONFLICT","fn","jQueryInterface","Constructor","noConflict","execute","possibleCallback","args","defaultValue","executeAfterTransition","transitionElement","waitForTransition","durationPadding","emulatedDuration","called","handler","target","removeEventListener","setTimeout","getNextActiveElement","list","activeElement","shouldGetNext","isCycleAllowed","listLength","index","indexOf","max","min","namespaceRegex","stripNameRegex","stripUidRegex","eventRegistry","uidEvent","customEvents","mouseenter","mouseleave","nativeEvents","Set","makeEventUid","uid","getElementEvents","bootstrapHandler","event","hydrateObj","delegateTarget","oneOff","EventHandler","off","type","apply","bootstrapDelegationHandler","domElements","querySelectorAll","domElement","findHandler","events","callable","delegationSelector","values","find","normalizeParameters","originalTypeEvent","delegationFunction","isDelegated","typeEvent","getTypeEvent","addHandler","wrapFunction","relatedTarget","handlers","previousFunction","removeHandler","Boolean","removeNamespacedHandlers","namespace","storeElementEvent","handlerKey","entries","includes","on","one","inNamespace","isNamespace","startsWith","elementEvent","slice","keyHandlers","trigger","jQueryEvent","bubbles","nativeDispatch","defaultPrevented","isPropagationStopped","isImmediatePropagationStopped","isDefaultPrevented","evt","cancelable","preventDefault","obj","meta","value","_unused","defineProperty","configurable","normalizeData","JSON","parse","decodeURIComponent","normalizeDataKey","chr","Manipulator","setDataAttribute","setAttribute","removeDataAttribute","removeAttribute","getDataAttributes","attributes","bsKeys","dataset","filter","pureKey","charAt","getDataAttribute","Config","Default","DefaultType","Error","_getConfig","config","_mergeConfigObj","_configAfterMerge","_typeCheckConfig","jsonConfig","constructor","configTypes","property","expectedTypes","valueType","RegExp","test","TypeError","toUpperCase","VERSION","BaseComponent","_element","_config","Data","DATA_KEY","dispose","EVENT_KEY","propertyName","getOwnPropertyNames","_queueCallback","isAnimated","getInstance","getOrCreateInstance","eventName","getSelector","hrefAttribute","trim","map","sel","join","SelectorEngine","concat","Element","findOne","children","child","matches","parents","ancestor","prev","previous","previousElementSibling","next","nextElementSibling","focusableChildren","focusables","el","getSelectorFromElement","getElementFromSelector","getMultipleElementsFromSelector","enableDismissTrigger","component","method","clickEvent","tagName","EVENT_CLOSE","EVENT_CLOSED","CLASS_NAME_FADE","CLASS_NAME_SHOW","Alert","close","closeEvent","_destroyElement","each","data","DATA_API_KEY","CLASS_NAME_ACTIVE","SELECTOR_DATA_TOGGLE","EVENT_CLICK_DATA_API","Button","toggle","button","EVENT_TOUCHSTART","EVENT_TOUCHMOVE","EVENT_TOUCHEND","EVENT_POINTERDOWN","EVENT_POINTERUP","POINTER_TYPE_TOUCH","POINTER_TYPE_PEN","CLASS_NAME_POINTER_EVENT","SWIPE_THRESHOLD","endCallback","leftCallback","rightCallback","Swipe","isSupported","_deltaX","_supportPointerEvents","PointerEvent","_initEvents","_start","touches","clientX","_eventIsPointerPenTouch","_end","_handleSwipe","_move","absDeltaX","abs","direction","add","pointerType","navigator","maxTouchPoints","ARROW_LEFT_KEY","ARROW_RIGHT_KEY","TOUCHEVENT_COMPAT_WAIT","ORDER_NEXT","ORDER_PREV","DIRECTION_LEFT","DIRECTION_RIGHT","EVENT_SLIDE","EVENT_SLID","EVENT_KEYDOWN","EVENT_MOUSEENTER","EVENT_MOUSELEAVE","EVENT_DRAG_START","EVENT_LOAD_DATA_API","CLASS_NAME_CAROUSEL","CLASS_NAME_SLIDE","CLASS_NAME_END","CLASS_NAME_START","CLASS_NAME_NEXT","CLASS_NAME_PREV","SELECTOR_ACTIVE","SELECTOR_ITEM","SELECTOR_ACTIVE_ITEM","SELECTOR_ITEM_IMG","SELECTOR_INDICATORS","SELECTOR_DATA_SLIDE","SELECTOR_DATA_RIDE","KEY_TO_DIRECTION","interval","keyboard","pause","ride","touch","wrap","Carousel","_interval","_activeElement","_isSliding","touchTimeout","_swipeHelper","_indicatorsElement","_addEventListeners","cycle","_slide","nextWhenVisible","hidden","_clearInterval","_updateInterval","setInterval","_maybeEnableCycle","to","items","_getItems","activeIndex","_getItemIndex","_getActive","order","defaultInterval","_keydown","_addTouchEventListeners","img","endCallBack","clearTimeout","swipeConfig","_directionToOrder","_setActiveIndicatorElement","activeIndicator","newActiveIndicator","elementInterval","parseInt","isNext","nextElement","nextElementIndex","triggerEvent","_orderToDirection","slideEvent","isCycling","directionalClassName","orderClassName","completeCallBack","_isAnimated","clearInterval","carousel","slideIndex","carousels","EVENT_SHOW","EVENT_SHOWN","EVENT_HIDE","EVENT_HIDDEN","CLASS_NAME_COLLAPSE","CLASS_NAME_COLLAPSING","CLASS_NAME_COLLAPSED","CLASS_NAME_DEEPER_CHILDREN","CLASS_NAME_HORIZONTAL","WIDTH","HEIGHT","SELECTOR_ACTIVES","parent","Collapse","_isTransitioning","_triggerArray","toggleList","elem","filterElement","foundElement","_initializeChildren","_addAriaAndCollapsedClass","_isShown","hide","show","activeChildren","_getFirstLevelChildren","startEvent","activeInstance","dimension","_getDimension","style","complete","capitalizedDimension","scrollSize","getBoundingClientRect","selected","triggerArray","isOpen","ESCAPE_KEY","TAB_KEY","ARROW_UP_KEY","ARROW_DOWN_KEY","RIGHT_MOUSE_BUTTON","EVENT_KEYDOWN_DATA_API","EVENT_KEYUP_DATA_API","CLASS_NAME_DROPUP","CLASS_NAME_DROPEND","CLASS_NAME_DROPSTART","CLASS_NAME_DROPUP_CENTER","CLASS_NAME_DROPDOWN_CENTER","SELECTOR_DATA_TOGGLE_SHOWN","SELECTOR_MENU","SELECTOR_NAVBAR","SELECTOR_NAVBAR_NAV","SELECTOR_VISIBLE_ITEMS","PLACEMENT_TOP","PLACEMENT_TOPEND","PLACEMENT_BOTTOM","PLACEMENT_BOTTOMEND","PLACEMENT_RIGHT","PLACEMENT_LEFT","PLACEMENT_TOPCENTER","PLACEMENT_BOTTOMCENTER","autoClose","boundary","display","offset","popperConfig","reference","Dropdown","_popper","_parent","_menu","_inNavbar","_detectNavbar","showEvent","_createPopper","focus","_completeHide","destroy","update","hideEvent","Popper","referenceElement","_getPopperConfig","createPopper","_getPlacement","parentDropdown","isEnd","_getOffset","popperData","defaultBsPopperConfig","placement","modifiers","options","enabled","_selectMenuItem","clearMenus","openToggles","context","composedPath","isMenuTarget","dataApiKeydownHandler","isInput","isEscapeEvent","isUpOrDownEvent","getToggleButton","stopPropagation","EVENT_MOUSEDOWN","className","clickCallback","rootElement","Backdrop","_isAppended","_append","_getElement","_emulateAnimation","backdrop","createElement","append","EVENT_FOCUSIN","EVENT_KEYDOWN_TAB","TAB_NAV_FORWARD","TAB_NAV_BACKWARD","autofocus","trapElement","FocusTrap","_isActive","_lastTabNavDirection","activate","_handleFocusin","_handleKeydown","deactivate","elements","shiftKey","SELECTOR_FIXED_CONTENT","SELECTOR_STICKY_CONTENT","PROPERTY_PADDING","PROPERTY_MARGIN","ScrollBarHelper","getWidth","documentWidth","clientWidth","innerWidth","width","_disableOverFlow","_setElementAttributes","calculatedValue","reset","_resetElementAttributes","isOverflowing","_saveInitialAttribute","overflow","styleProperty","scrollbarWidth","manipulationCallBack","setProperty","_applyManipulationCallback","actualValue","removeProperty","callBack","EVENT_HIDE_PREVENTED","EVENT_RESIZE","EVENT_CLICK_DISMISS","EVENT_MOUSEDOWN_DISMISS","EVENT_KEYDOWN_DISMISS","CLASS_NAME_OPEN","CLASS_NAME_STATIC","OPEN_SELECTOR","SELECTOR_DIALOG","SELECTOR_MODAL_BODY","Modal","_dialog","_backdrop","_initializeBackDrop","_focustrap","_initializeFocusTrap","_scrollBar","_adjustDialog","_showElement","_hideModal","handleUpdate","scrollTop","modalBody","transitionComplete","_triggerBackdropTransition","event2","_resetAdjustments","isModalOverflowing","scrollHeight","clientHeight","initialOverflowY","overflowY","isBodyOverflowing","paddingLeft","paddingRight","alreadyOpen","CLASS_NAME_SHOWING","CLASS_NAME_HIDING","CLASS_NAME_BACKDROP","scroll","Offcanvas","blur","completeCallback","position","ARIA_ATTRIBUTE_PATTERN","DefaultAllowlist","a","area","b","br","col","code","dd","div","dl","dt","em","hr","h1","h2","h3","h4","h5","h6","i","li","ol","p","pre","s","small","span","sub","sup","strong","u","ul","uriAttributes","SAFE_URL_PATTERN","allowedAttribute","attribute","allowedAttributeList","attributeName","nodeName","nodeValue","attributeRegex","some","regex","sanitizeHtml","unsafeHtml","allowList","sanitizeFunction","domParser","DOMParser","createdDocument","parseFromString","elementName","attributeList","allowedAttributes","innerHTML","content","extraClass","html","sanitize","sanitizeFn","template","DefaultContentType","entry","TemplateFactory","getContent","_resolvePossibleFunction","hasContent","changeContent","_checkContent","toHtml","templateWrapper","_maybeSanitize","text","_setContent","arg","templateElement","_putElementInTemplate","textContent","DISALLOWED_ATTRIBUTES","CLASS_NAME_MODAL","SELECTOR_TOOLTIP_INNER","SELECTOR_MODAL","EVENT_MODAL_HIDE","TRIGGER_HOVER","TRIGGER_FOCUS","TRIGGER_CLICK","TRIGGER_MANUAL","EVENT_INSERTED","EVENT_CLICK","EVENT_FOCUSOUT","AttachmentMap","AUTO","TOP","RIGHT","BOTTOM","LEFT","animation","container","customClass","delay","fallbackPlacements","title","Tooltip","_isEnabled","_timeout","_isHovered","_activeTrigger","_templateFactory","_newContent","tip","_setListeners","_fixTitle","enable","disable","toggleEnabled","_leave","_enter","_hideModalHandler","_disposePopper","_isWithContent","shadowRoot","isInTheDom","ownerDocument","_getTipElement","_isWithActiveTrigger","_getTitle","_createTipElement","_getContentForTemplate","_getTemplateFactory","tipId","setContent","_initializeOnDelegatedTarget","_getDelegateConfig","attachment","phase","state","triggers","eventIn","eventOut","_setTimeout","timeout","dataAttributes","dataAttribute","SELECTOR_TITLE","SELECTOR_CONTENT","Popover","_getContent","EVENT_ACTIVATE","CLASS_NAME_DROPDOWN_ITEM","SELECTOR_DATA_SPY","SELECTOR_TARGET_LINKS","SELECTOR_NAV_LIST_GROUP","SELECTOR_NAV_LINKS","SELECTOR_NAV_ITEMS","SELECTOR_LIST_ITEMS","SELECTOR_LINK_ITEMS","SELECTOR_DROPDOWN","SELECTOR_DROPDOWN_TOGGLE","rootMargin","smoothScroll","threshold","ScrollSpy","_targetLinks","_observableSections","_rootElement","_activeTarget","_observer","_previousScrollData","visibleEntryTop","parentScrollTop","refresh","_initializeTargetsAndObservables","_maybeEnableSmoothScroll","disconnect","_getNewObserver","section","observe","observableSection","hash","height","offsetTop","scrollTo","top","behavior","IntersectionObserver","_observerCallback","targetElement","_process","userScrollsDown","isIntersecting","_clearActiveClass","entryIsLowerThanPrevious","targetLinks","anchor","decodeURI","_activateParents","listGroup","item","activeNodes","node","spy","HOME_KEY","END_KEY","CLASS_DROPDOWN","SELECTOR_DROPDOWN_MENU","NOT_SELECTOR_DROPDOWN_TOGGLE","SELECTOR_TAB_PANEL","SELECTOR_OUTER","SELECTOR_INNER","SELECTOR_INNER_ELEM","SELECTOR_DATA_TOGGLE_ACTIVE","Tab","_setInitialAttributes","_getChildren","innerElem","_elemIsActive","active","_getActiveElem","_deactivate","_activate","relatedElem","_toggleDropDown","nextActiveElement","preventScroll","_setAttributeIfNotExists","_setInitialAttributesOnChild","_getInnerElement","isActive","outerElem","_getOuterElement","_setInitialAttributesOnTargetPanel","open","EVENT_MOUSEOVER","EVENT_MOUSEOUT","CLASS_NAME_HIDE","autohide","Toast","_hasMouseInteraction","_hasKeyboardInteraction","_clearTimeout","_maybeScheduleHide","isShown","_onInteraction","isInteracting"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAAA;EACA;EACA;EACA;EACA;EACA;;EAEA;EACA;EACA;;EAEA,MAAMA,UAAU,GAAG,IAAIC,GAAG,EAAE;AAE5B,eAAe;EACbC,EAAAA,GAAGA,CAACC,OAAO,EAAEC,GAAG,EAAEC,QAAQ,EAAE;EAC1B,IAAA,IAAI,CAACL,UAAU,CAACM,GAAG,CAACH,OAAO,CAAC,EAAE;QAC5BH,UAAU,CAACE,GAAG,CAACC,OAAO,EAAE,IAAIF,GAAG,EAAE,CAAC;EACpC,IAAA;EAEA,IAAA,MAAMM,WAAW,GAAGP,UAAU,CAACQ,GAAG,CAACL,OAAO,CAAC;;EAE3C;EACA;EACA,IAAA,IAAI,CAACI,WAAW,CAACD,GAAG,CAACF,GAAG,CAAC,IAAIG,WAAW,CAACE,IAAI,KAAK,CAAC,EAAE;EACnD;EACAC,MAAAA,OAAO,CAACC,KAAK,CAAC,+EAA+EC,KAAK,CAACC,IAAI,CAACN,WAAW,CAACO,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;EAClI,MAAA;EACF,IAAA;EAEAP,IAAAA,WAAW,CAACL,GAAG,CAACE,GAAG,EAAEC,QAAQ,CAAC;IAChC,CAAC;EAEDG,EAAAA,GAAGA,CAACL,OAAO,EAAEC,GAAG,EAAE;EAChB,IAAA,IAAIJ,UAAU,CAACM,GAAG,CAACH,OAAO,CAAC,EAAE;EAC3B,MAAA,OAAOH,UAAU,CAACQ,GAAG,CAACL,OAAO,CAAC,CAACK,GAAG,CAACJ,GAAG,CAAC,IAAI,IAAI;EACjD,IAAA;EAEA,IAAA,OAAO,IAAI;IACb,CAAC;EAEDW,EAAAA,MAAMA,CAACZ,OAAO,EAAEC,GAAG,EAAE;EACnB,IAAA,IAAI,CAACJ,UAAU,CAACM,GAAG,CAACH,OAAO,CAAC,EAAE;EAC5B,MAAA;EACF,IAAA;EAEA,IAAA,MAAMI,WAAW,GAAGP,UAAU,CAACQ,GAAG,CAACL,OAAO,CAAC;EAE3CI,IAAAA,WAAW,CAACS,MAAM,CAACZ,GAAG,CAAC;;EAEvB;EACA,IAAA,IAAIG,WAAW,CAACE,IAAI,KAAK,CAAC,EAAE;EAC1BT,MAAAA,UAAU,CAACgB,MAAM,CAACb,OAAO,CAAC;EAC5B,IAAA;EACF,EAAA;EACF,CAAC;;ECtDD;EACA;EACA;EACA;EACA;EACA;;EAEA,MAAMc,OAAO,GAAG,OAAS;EACzB,MAAMC,uBAAuB,GAAG,IAAI;EACpC,MAAMC,cAAc,GAAG,eAAe;;EAEtC;EACA;EACA;EACA;EACA;EACA,MAAMC,aAAa,GAAGC,QAAQ,IAAI;IAChC,IAAIA,QAAQ,IAAIC,MAAM,CAACC,GAAG,IAAID,MAAM,CAACC,GAAG,CAACC,MAAM,EAAE;EAC/C;MACAH,QAAQ,GAAGA,QAAQ,CAACI,OAAO,CAAC,eAAe,EAAE,CAACC,KAAK,EAAEC,EAAE,KAAK,CAAA,CAAA,EAAIJ,GAAG,CAACC,MAAM,CAACG,EAAE,CAAC,EAAE,CAAC;EACnF,EAAA;EAEA,EAAA,OAAON,QAAQ;EACjB,CAAC;;EAED;EACA,MAAMO,MAAM,GAAGC,MAAM,IAAI;EACvB,EAAA,IAAIA,MAAM,KAAK,IAAI,IAAIA,MAAM,KAAKC,SAAS,EAAE;MAC3C,OAAO,CAAA,EAAGD,MAAM,CAAA,CAAE;EACpB,EAAA;IAEA,OAAOE,MAAM,CAACC,SAAS,CAACC,QAAQ,CAACC,IAAI,CAACL,MAAM,CAAC,CAACH,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAACS,WAAW,EAAE;EACrF,CAAC;;EAED;EACA;EACA;;EAEA,MAAMC,MAAM,GAAGC,MAAM,IAAI;IACvB,GAAG;EACDA,IAAAA,MAAM,IAAIC,IAAI,CAACC,KAAK,CAACD,IAAI,CAACE,MAAM,EAAE,GAAGvB,OAAO,CAAC;EAC/C,EAAA,CAAC,QAAQwB,QAAQ,CAACC,cAAc,CAACL,MAAM,CAAC;EAExC,EAAA,OAAOA,MAAM;EACf,CAAC;EAED,MAAMM,gCAAgC,GAAGxC,OAAO,IAAI;IAClD,IAAI,CAACA,OAAO,EAAE;EACZ,IAAA,OAAO,CAAC;EACV,EAAA;;EAEA;IACA,IAAI;MAAEyC,kBAAkB;EAAEC,IAAAA;EAAgB,GAAC,GAAGvB,MAAM,CAACwB,gBAAgB,CAAC3C,OAAO,CAAC;EAE9E,EAAA,MAAM4C,uBAAuB,GAAGC,MAAM,CAACC,UAAU,CAACL,kBAAkB,CAAC;EACrE,EAAA,MAAMM,oBAAoB,GAAGF,MAAM,CAACC,UAAU,CAACJ,eAAe,CAAC;;EAE/D;EACA,EAAA,IAAI,CAACE,uBAAuB,IAAI,CAACG,oBAAoB,EAAE;EACrD,IAAA,OAAO,CAAC;EACV,EAAA;;EAEA;IACAN,kBAAkB,GAAGA,kBAAkB,CAACO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrDN,eAAe,GAAGA,eAAe,CAACM,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;EAE/C,EAAA,OAAO,CAACH,MAAM,CAACC,UAAU,CAACL,kBAAkB,CAAC,GAAGI,MAAM,CAACC,UAAU,CAACJ,eAAe,CAAC,IAAI3B,uBAAuB;EAC/G,CAAC;EAED,MAAMkC,oBAAoB,GAAGjD,OAAO,IAAI;IACtCA,OAAO,CAACkD,aAAa,CAAC,IAAIC,KAAK,CAACnC,cAAc,CAAC,CAAC;EAClD,CAAC;EAED,MAAMoC,SAAS,GAAG1B,MAAM,IAAI;EAC1B,EAAA,IAAI,CAACA,MAAM,IAAI,OAAOA,MAAM,KAAK,QAAQ,EAAE;EACzC,IAAA,OAAO,KAAK;EACd,EAAA;EAEA,EAAA,IAAI,OAAOA,MAAM,CAAC2B,MAAM,KAAK,WAAW,EAAE;EACxC3B,IAAAA,MAAM,GAAGA,MAAM,CAAC,CAAC,CAAC;EACpB,EAAA;EAEA,EAAA,OAAO,OAAOA,MAAM,CAAC4B,QAAQ,KAAK,WAAW;EAC/C,CAAC;EAED,MAAMC,UAAU,GAAG7B,MAAM,IAAI;EAC3B;EACA,EAAA,IAAI0B,SAAS,CAAC1B,MAAM,CAAC,EAAE;MACrB,OAAOA,MAAM,CAAC2B,MAAM,GAAG3B,MAAM,CAAC,CAAC,CAAC,GAAGA,MAAM;EAC3C,EAAA;IAEA,IAAI,OAAOA,MAAM,KAAK,QAAQ,IAAIA,MAAM,CAAC8B,MAAM,GAAG,CAAC,EAAE;MACnD,OAAOlB,QAAQ,CAACmB,aAAa,CAACxC,aAAa,CAACS,MAAM,CAAC,CAAC;EACtD,EAAA;EAEA,EAAA,OAAO,IAAI;EACb,CAAC;EAED,MAAMgC,SAAS,GAAG1D,OAAO,IAAI;EAC3B,EAAA,IAAI,CAACoD,SAAS,CAACpD,OAAO,CAAC,IAAIA,OAAO,CAAC2D,cAAc,EAAE,CAACH,MAAM,KAAK,CAAC,EAAE;EAChE,IAAA,OAAO,KAAK;EACd,EAAA;EAEA,EAAA,MAAMI,gBAAgB,GAAGjB,gBAAgB,CAAC3C,OAAO,CAAC,CAAC6D,gBAAgB,CAAC,YAAY,CAAC,KAAK,SAAS;EAC/F;EACA,EAAA,MAAMC,aAAa,GAAG9D,OAAO,CAAC+D,OAAO,CAAC,qBAAqB,CAAC;IAE5D,IAAI,CAACD,aAAa,EAAE;EAClB,IAAA,OAAOF,gBAAgB;EACzB,EAAA;IAEA,IAAIE,aAAa,KAAK9D,OAAO,EAAE;EAC7B,IAAA,MAAMgE,OAAO,GAAGhE,OAAO,CAAC+D,OAAO,CAAC,SAAS,CAAC;EAC1C,IAAA,IAAIC,OAAO,IAAIA,OAAO,CAACC,UAAU,KAAKH,aAAa,EAAE;EACnD,MAAA,OAAO,KAAK;EACd,IAAA;MAEA,IAAIE,OAAO,KAAK,IAAI,EAAE;EACpB,MAAA,OAAO,KAAK;EACd,IAAA;EACF,EAAA;EAEA,EAAA,OAAOJ,gBAAgB;EACzB,CAAC;EAED,MAAMM,UAAU,GAAGlE,OAAO,IAAI;IAC5B,IAAI,CAACA,OAAO,IAAIA,OAAO,CAACsD,QAAQ,KAAKa,IAAI,CAACC,YAAY,EAAE;EACtD,IAAA,OAAO,IAAI;EACb,EAAA;IAEA,IAAIpE,OAAO,CAACqE,SAAS,CAACC,QAAQ,CAAC,UAAU,CAAC,EAAE;EAC1C,IAAA,OAAO,IAAI;EACb,EAAA;EAEA,EAAA,IAAI,OAAOtE,OAAO,CAACuE,QAAQ,KAAK,WAAW,EAAE;MAC3C,OAAOvE,OAAO,CAACuE,QAAQ;EACzB,EAAA;EAEA,EAAA,OAAOvE,OAAO,CAACwE,YAAY,CAAC,UAAU,CAAC,IAAIxE,OAAO,CAACyE,YAAY,CAAC,UAAU,CAAC,KAAK,OAAO;EACzF,CAAC;EAED,MAAMC,cAAc,GAAG1E,OAAO,IAAI;EAChC,EAAA,IAAI,CAACsC,QAAQ,CAACqC,eAAe,CAACC,YAAY,EAAE;EAC1C,IAAA,OAAO,IAAI;EACb,EAAA;;EAEA;EACA,EAAA,IAAI,OAAO5E,OAAO,CAAC6E,WAAW,KAAK,UAAU,EAAE;EAC7C,IAAA,MAAMC,IAAI,GAAG9E,OAAO,CAAC6E,WAAW,EAAE;EAClC,IAAA,OAAOC,IAAI,YAAYC,UAAU,GAAGD,IAAI,GAAG,IAAI;EACjD,EAAA;IAEA,IAAI9E,OAAO,YAAY+E,UAAU,EAAE;EACjC,IAAA,OAAO/E,OAAO;EAChB,EAAA;;EAEA;EACA,EAAA,IAAI,CAACA,OAAO,CAACiE,UAAU,EAAE;EACvB,IAAA,OAAO,IAAI;EACb,EAAA;EAEA,EAAA,OAAOS,cAAc,CAAC1E,OAAO,CAACiE,UAAU,CAAC;EAC3C,CAAC;EAED,MAAMe,IAAI,GAAGA,MAAM,CAAC,CAAC;;EAErB;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAMC,MAAM,GAAGjF,OAAO,IAAI;IACxBA,OAAO,CAACkF,YAAY,CAAA;EACtB,CAAC;EAED,MAAMC,SAAS,GAAGA,MAAM;EACtB,EAAA,IAAIhE,MAAM,CAACiE,MAAM,IAAI,CAAC9C,QAAQ,CAAC+C,IAAI,CAACb,YAAY,CAAC,mBAAmB,CAAC,EAAE;MACrE,OAAOrD,MAAM,CAACiE,MAAM;EACtB,EAAA;EAEA,EAAA,OAAO,IAAI;EACb,CAAC;EAED,MAAME,yBAAyB,GAAG,EAAE;EAEpC,MAAMC,kBAAkB,GAAGC,QAAQ,IAAI;EACrC,EAAA,IAAIlD,QAAQ,CAACmD,UAAU,KAAK,SAAS,EAAE;EACrC;EACA,IAAA,IAAI,CAACH,yBAAyB,CAAC9B,MAAM,EAAE;EACrClB,MAAAA,QAAQ,CAACoD,gBAAgB,CAAC,kBAAkB,EAAE,MAAM;EAClD,QAAA,KAAK,MAAMF,QAAQ,IAAIF,yBAAyB,EAAE;EAChDE,UAAAA,QAAQ,EAAE;EACZ,QAAA;EACF,MAAA,CAAC,CAAC;EACJ,IAAA;EAEAF,IAAAA,yBAAyB,CAACK,IAAI,CAACH,QAAQ,CAAC;EAC1C,EAAA,CAAC,MAAM;EACLA,IAAAA,QAAQ,EAAE;EACZ,EAAA;EACF,CAAC;EAED,MAAMI,KAAK,GAAGA,MAAMtD,QAAQ,CAACqC,eAAe,CAACkB,GAAG,KAAK,KAAK;EAE1D,MAAMC,kBAAkB,GAAGC,MAAM,IAAI;EACnCR,EAAAA,kBAAkB,CAAC,MAAM;EACvB,IAAA,MAAMS,CAAC,GAAGb,SAAS,EAAE;EACrB;EACA,IAAA,IAAIa,CAAC,EAAE;EACL,MAAA,MAAMC,IAAI,GAAGF,MAAM,CAACG,IAAI;EACxB,MAAA,MAAMC,kBAAkB,GAAGH,CAAC,CAACI,EAAE,CAACH,IAAI,CAAC;QACrCD,CAAC,CAACI,EAAE,CAACH,IAAI,CAAC,GAAGF,MAAM,CAACM,eAAe;QACnCL,CAAC,CAACI,EAAE,CAACH,IAAI,CAAC,CAACK,WAAW,GAAGP,MAAM;QAC/BC,CAAC,CAACI,EAAE,CAACH,IAAI,CAAC,CAACM,UAAU,GAAG,MAAM;EAC5BP,QAAAA,CAAC,CAACI,EAAE,CAACH,IAAI,CAAC,GAAGE,kBAAkB;UAC/B,OAAOJ,MAAM,CAACM,eAAe;QAC/B,CAAC;EACH,IAAA;EACF,EAAA,CAAC,CAAC;EACJ,CAAC;EAED,MAAMG,OAAO,GAAGA,CAACC,gBAAgB,EAAEC,IAAI,GAAG,EAAE,EAAEC,YAAY,GAAGF,gBAAgB,KAAK;EAChF,EAAA,OAAO,OAAOA,gBAAgB,KAAK,UAAU,GAAGA,gBAAgB,CAAC1E,IAAI,CAAC,GAAG2E,IAAI,CAAC,GAAGC,YAAY;EAC/F,CAAC;EAED,MAAMC,sBAAsB,GAAGA,CAACpB,QAAQ,EAAEqB,iBAAiB,EAAEC,iBAAiB,GAAG,IAAI,KAAK;IACxF,IAAI,CAACA,iBAAiB,EAAE;MACtBN,OAAO,CAAChB,QAAQ,CAAC;EACjB,IAAA;EACF,EAAA;IAEA,MAAMuB,eAAe,GAAG,CAAC;EACzB,EAAA,MAAMC,gBAAgB,GAAGxE,gCAAgC,CAACqE,iBAAiB,CAAC,GAAGE,eAAe;IAE9F,IAAIE,MAAM,GAAG,KAAK;IAElB,MAAMC,OAAO,GAAGA,CAAC;EAAEC,IAAAA;EAAO,GAAC,KAAK;MAC9B,IAAIA,MAAM,KAAKN,iBAAiB,EAAE;EAChC,MAAA;EACF,IAAA;EAEAI,IAAAA,MAAM,GAAG,IAAI;EACbJ,IAAAA,iBAAiB,CAACO,mBAAmB,CAACpG,cAAc,EAAEkG,OAAO,CAAC;MAC9DV,OAAO,CAAChB,QAAQ,CAAC;IACnB,CAAC;EAEDqB,EAAAA,iBAAiB,CAACnB,gBAAgB,CAAC1E,cAAc,EAAEkG,OAAO,CAAC;EAC3DG,EAAAA,UAAU,CAAC,MAAM;MACf,IAAI,CAACJ,MAAM,EAAE;QACXhE,oBAAoB,CAAC4D,iBAAiB,CAAC;EACzC,IAAA;IACF,CAAC,EAAEG,gBAAgB,CAAC;EACtB,CAAC;;EAED;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA,MAAMM,oBAAoB,GAAGA,CAACC,IAAI,EAAEC,aAAa,EAAEC,aAAa,EAAEC,cAAc,KAAK;EACnF,EAAA,MAAMC,UAAU,GAAGJ,IAAI,CAAC/D,MAAM;EAC9B,EAAA,IAAIoE,KAAK,GAAGL,IAAI,CAACM,OAAO,CAACL,aAAa,CAAC;;EAEvC;EACA;EACA,EAAA,IAAII,KAAK,KAAK,EAAE,EAAE;EAChB,IAAA,OAAO,CAACH,aAAa,IAAIC,cAAc,GAAGH,IAAI,CAACI,UAAU,GAAG,CAAC,CAAC,GAAGJ,IAAI,CAAC,CAAC,CAAC;EAC1E,EAAA;EAEAK,EAAAA,KAAK,IAAIH,aAAa,GAAG,CAAC,GAAG,EAAE;EAE/B,EAAA,IAAIC,cAAc,EAAE;EAClBE,IAAAA,KAAK,GAAG,CAACA,KAAK,GAAGD,UAAU,IAAIA,UAAU;EAC3C,EAAA;EAEA,EAAA,OAAOJ,IAAI,CAACpF,IAAI,CAAC2F,GAAG,CAAC,CAAC,EAAE3F,IAAI,CAAC4F,GAAG,CAACH,KAAK,EAAED,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC;EAC3D,CAAC;;EC3RD;EACA;EACA;EACA;EACA;EACA;;;EAIA;EACA;EACA;;EAEA,MAAMK,cAAc,GAAG,oBAAoB;EAC3C,MAAMC,cAAc,GAAG,MAAM;EAC7B,MAAMC,aAAa,GAAG,QAAQ;EAC9B,MAAMC,aAAa,GAAG,EAAE,CAAA;EACxB,IAAIC,QAAQ,GAAG,CAAC;EAChB,MAAMC,YAAY,GAAG;EACnBC,EAAAA,UAAU,EAAE,WAAW;EACvBC,EAAAA,UAAU,EAAE;EACd,CAAC;EAED,MAAMC,YAAY,GAAG,IAAIC,GAAG,CAAC,CAC3B,OAAO,EACP,UAAU,EACV,SAAS,EACT,WAAW,EACX,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,WAAW,EACX,aAAa,EACb,WAAW,EACX,SAAS,EACT,UAAU,EACV,OAAO,EACP,mBAAmB,EACnB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,aAAa,EACb,aAAa,EACb,aAAa,EACb,WAAW,EACX,cAAc,EACd,eAAe,EACf,cAAc,EACd,eAAe,EACf,YAAY,EACZ,OAAO,EACP,MAAM,EACN,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,UAAU,EACV,MAAM,EACN,QAAQ,EACR,cAAc,EACd,QAAQ,EACR,MAAM,EACN,kBAAkB,EAClB,kBAAkB,EAClB,OAAO,EACP,OAAO,EACP,QAAQ,CACT,CAAC;;EAEF;EACA;EACA;;EAEA,SAASC,YAAYA,CAAC1I,OAAO,EAAE2I,GAAG,EAAE;EAClC,EAAA,OAAQA,GAAG,IAAI,CAAA,EAAGA,GAAG,KAAKP,QAAQ,EAAE,CAAA,CAAE,IAAKpI,OAAO,CAACoI,QAAQ,IAAIA,QAAQ,EAAE;EAC3E;EAEA,SAASQ,gBAAgBA,CAAC5I,OAAO,EAAE;EACjC,EAAA,MAAM2I,GAAG,GAAGD,YAAY,CAAC1I,OAAO,CAAC;IAEjCA,OAAO,CAACoI,QAAQ,GAAGO,GAAG;IACtBR,aAAa,CAACQ,GAAG,CAAC,GAAGR,aAAa,CAACQ,GAAG,CAAC,IAAI,EAAE;IAE7C,OAAOR,aAAa,CAACQ,GAAG,CAAC;EAC3B;EAEA,SAASE,gBAAgBA,CAAC7I,OAAO,EAAEoG,EAAE,EAAE;EACrC,EAAA,OAAO,SAASc,OAAOA,CAAC4B,KAAK,EAAE;MAC7BC,UAAU,CAACD,KAAK,EAAE;EAAEE,MAAAA,cAAc,EAAEhJ;EAAQ,KAAC,CAAC;MAE9C,IAAIkH,OAAO,CAAC+B,MAAM,EAAE;QAClBC,YAAY,CAACC,GAAG,CAACnJ,OAAO,EAAE8I,KAAK,CAACM,IAAI,EAAEhD,EAAE,CAAC;EAC3C,IAAA;MAEA,OAAOA,EAAE,CAACiD,KAAK,CAACrJ,OAAO,EAAE,CAAC8I,KAAK,CAAC,CAAC;IACnC,CAAC;EACH;EAEA,SAASQ,0BAA0BA,CAACtJ,OAAO,EAAEkB,QAAQ,EAAEkF,EAAE,EAAE;EACzD,EAAA,OAAO,SAASc,OAAOA,CAAC4B,KAAK,EAAE;EAC7B,IAAA,MAAMS,WAAW,GAAGvJ,OAAO,CAACwJ,gBAAgB,CAACtI,QAAQ,CAAC;EAEtD,IAAA,KAAK,IAAI;EAAEiG,MAAAA;EAAO,KAAC,GAAG2B,KAAK,EAAE3B,MAAM,IAAIA,MAAM,KAAK,IAAI,EAAEA,MAAM,GAAGA,MAAM,CAAClD,UAAU,EAAE;EAClF,MAAA,KAAK,MAAMwF,UAAU,IAAIF,WAAW,EAAE;UACpC,IAAIE,UAAU,KAAKtC,MAAM,EAAE;EACzB,UAAA;EACF,QAAA;UAEA4B,UAAU,CAACD,KAAK,EAAE;EAAEE,UAAAA,cAAc,EAAE7B;EAAO,SAAC,CAAC;UAE7C,IAAID,OAAO,CAAC+B,MAAM,EAAE;EAClBC,UAAAA,YAAY,CAACC,GAAG,CAACnJ,OAAO,EAAE8I,KAAK,CAACM,IAAI,EAAElI,QAAQ,EAAEkF,EAAE,CAAC;EACrD,QAAA;UAEA,OAAOA,EAAE,CAACiD,KAAK,CAAClC,MAAM,EAAE,CAAC2B,KAAK,CAAC,CAAC;EAClC,MAAA;EACF,IAAA;IACF,CAAC;EACH;EAEA,SAASY,WAAWA,CAACC,MAAM,EAAEC,QAAQ,EAAEC,kBAAkB,GAAG,IAAI,EAAE;IAChE,OAAOjI,MAAM,CAACkI,MAAM,CAACH,MAAM,CAAC,CACzBI,IAAI,CAACjB,KAAK,IAAIA,KAAK,CAACc,QAAQ,KAAKA,QAAQ,IAAId,KAAK,CAACe,kBAAkB,KAAKA,kBAAkB,CAAC;EAClG;EAEA,SAASG,mBAAmBA,CAACC,iBAAiB,EAAE/C,OAAO,EAAEgD,kBAAkB,EAAE;EAC3E,EAAA,MAAMC,WAAW,GAAG,OAAOjD,OAAO,KAAK,QAAQ;EAC/C;IACA,MAAM0C,QAAQ,GAAGO,WAAW,GAAGD,kBAAkB,GAAIhD,OAAO,IAAIgD,kBAAmB;EACnF,EAAA,IAAIE,SAAS,GAAGC,YAAY,CAACJ,iBAAiB,CAAC;EAE/C,EAAA,IAAI,CAACzB,YAAY,CAACrI,GAAG,CAACiK,SAAS,CAAC,EAAE;EAChCA,IAAAA,SAAS,GAAGH,iBAAiB;EAC/B,EAAA;EAEA,EAAA,OAAO,CAACE,WAAW,EAAEP,QAAQ,EAAEQ,SAAS,CAAC;EAC3C;EAEA,SAASE,UAAUA,CAACtK,OAAO,EAAEiK,iBAAiB,EAAE/C,OAAO,EAAEgD,kBAAkB,EAAEjB,MAAM,EAAE;EACnF,EAAA,IAAI,OAAOgB,iBAAiB,KAAK,QAAQ,IAAI,CAACjK,OAAO,EAAE;EACrD,IAAA;EACF,EAAA;EAEA,EAAA,IAAI,CAACmK,WAAW,EAAEP,QAAQ,EAAEQ,SAAS,CAAC,GAAGJ,mBAAmB,CAACC,iBAAiB,EAAE/C,OAAO,EAAEgD,kBAAkB,CAAC;;EAE5G;EACA;IACA,IAAID,iBAAiB,IAAI5B,YAAY,EAAE;MACrC,MAAMkC,YAAY,GAAGnE,EAAE,IAAI;QACzB,OAAO,UAAU0C,KAAK,EAAE;UACtB,IAAI,CAACA,KAAK,CAAC0B,aAAa,IAAK1B,KAAK,CAAC0B,aAAa,KAAK1B,KAAK,CAACE,cAAc,IAAI,CAACF,KAAK,CAACE,cAAc,CAAC1E,QAAQ,CAACwE,KAAK,CAAC0B,aAAa,CAAE,EAAE;EACjI,UAAA,OAAOpE,EAAE,CAACrE,IAAI,CAAC,IAAI,EAAE+G,KAAK,CAAC;EAC7B,QAAA;QACF,CAAC;MACH,CAAC;EAEDc,IAAAA,QAAQ,GAAGW,YAAY,CAACX,QAAQ,CAAC;EACnC,EAAA;EAEA,EAAA,MAAMD,MAAM,GAAGf,gBAAgB,CAAC5I,OAAO,CAAC;EACxC,EAAA,MAAMyK,QAAQ,GAAGd,MAAM,CAACS,SAAS,CAAC,KAAKT,MAAM,CAACS,SAAS,CAAC,GAAG,EAAE,CAAC;EAC9D,EAAA,MAAMM,gBAAgB,GAAGhB,WAAW,CAACe,QAAQ,EAAEb,QAAQ,EAAEO,WAAW,GAAGjD,OAAO,GAAG,IAAI,CAAC;EAEtF,EAAA,IAAIwD,gBAAgB,EAAE;EACpBA,IAAAA,gBAAgB,CAACzB,MAAM,GAAGyB,gBAAgB,CAACzB,MAAM,IAAIA,MAAM;EAE3D,IAAA;EACF,EAAA;EAEA,EAAA,MAAMN,GAAG,GAAGD,YAAY,CAACkB,QAAQ,EAAEK,iBAAiB,CAAC3I,OAAO,CAAC0G,cAAc,EAAE,EAAE,CAAC,CAAC;EACjF,EAAA,MAAM5B,EAAE,GAAG+D,WAAW,GACpBb,0BAA0B,CAACtJ,OAAO,EAAEkH,OAAO,EAAE0C,QAAQ,CAAC,GACtDf,gBAAgB,CAAC7I,OAAO,EAAE4J,QAAQ,CAAC;EAErCxD,EAAAA,EAAE,CAACyD,kBAAkB,GAAGM,WAAW,GAAGjD,OAAO,GAAG,IAAI;IACpDd,EAAE,CAACwD,QAAQ,GAAGA,QAAQ;IACtBxD,EAAE,CAAC6C,MAAM,GAAGA,MAAM;IAClB7C,EAAE,CAACgC,QAAQ,GAAGO,GAAG;EACjB8B,EAAAA,QAAQ,CAAC9B,GAAG,CAAC,GAAGvC,EAAE;IAElBpG,OAAO,CAAC0F,gBAAgB,CAAC0E,SAAS,EAAEhE,EAAE,EAAE+D,WAAW,CAAC;EACtD;EAEA,SAASQ,aAAaA,CAAC3K,OAAO,EAAE2J,MAAM,EAAES,SAAS,EAAElD,OAAO,EAAE2C,kBAAkB,EAAE;EAC9E,EAAA,MAAMzD,EAAE,GAAGsD,WAAW,CAACC,MAAM,CAACS,SAAS,CAAC,EAAElD,OAAO,EAAE2C,kBAAkB,CAAC;IAEtE,IAAI,CAACzD,EAAE,EAAE;EACP,IAAA;EACF,EAAA;IAEApG,OAAO,CAACoH,mBAAmB,CAACgD,SAAS,EAAEhE,EAAE,EAAEwE,OAAO,CAACf,kBAAkB,CAAC,CAAC;IACvE,OAAOF,MAAM,CAACS,SAAS,CAAC,CAAChE,EAAE,CAACgC,QAAQ,CAAC;EACvC;EAEA,SAASyC,wBAAwBA,CAAC7K,OAAO,EAAE2J,MAAM,EAAES,SAAS,EAAEU,SAAS,EAAE;IACvE,MAAMC,iBAAiB,GAAGpB,MAAM,CAACS,SAAS,CAAC,IAAI,EAAE;EAEjD,EAAA,KAAK,MAAM,CAACY,UAAU,EAAElC,KAAK,CAAC,IAAIlH,MAAM,CAACqJ,OAAO,CAACF,iBAAiB,CAAC,EAAE;EACnE,IAAA,IAAIC,UAAU,CAACE,QAAQ,CAACJ,SAAS,CAAC,EAAE;EAClCH,MAAAA,aAAa,CAAC3K,OAAO,EAAE2J,MAAM,EAAES,SAAS,EAAEtB,KAAK,CAACc,QAAQ,EAAEd,KAAK,CAACe,kBAAkB,CAAC;EACrF,IAAA;EACF,EAAA;EACF;EAEA,SAASQ,YAAYA,CAACvB,KAAK,EAAE;EAC3B;IACAA,KAAK,GAAGA,KAAK,CAACxH,OAAO,CAAC2G,cAAc,EAAE,EAAE,CAAC;EACzC,EAAA,OAAOI,YAAY,CAACS,KAAK,CAAC,IAAIA,KAAK;EACrC;EAEA,MAAMI,YAAY,GAAG;IACnBiC,EAAEA,CAACnL,OAAO,EAAE8I,KAAK,EAAE5B,OAAO,EAAEgD,kBAAkB,EAAE;MAC9CI,UAAU,CAACtK,OAAO,EAAE8I,KAAK,EAAE5B,OAAO,EAAEgD,kBAAkB,EAAE,KAAK,CAAC;IAChE,CAAC;IAEDkB,GAAGA,CAACpL,OAAO,EAAE8I,KAAK,EAAE5B,OAAO,EAAEgD,kBAAkB,EAAE;MAC/CI,UAAU,CAACtK,OAAO,EAAE8I,KAAK,EAAE5B,OAAO,EAAEgD,kBAAkB,EAAE,IAAI,CAAC;IAC/D,CAAC;IAEDf,GAAGA,CAACnJ,OAAO,EAAEiK,iBAAiB,EAAE/C,OAAO,EAAEgD,kBAAkB,EAAE;EAC3D,IAAA,IAAI,OAAOD,iBAAiB,KAAK,QAAQ,IAAI,CAACjK,OAAO,EAAE;EACrD,MAAA;EACF,IAAA;EAEA,IAAA,MAAM,CAACmK,WAAW,EAAEP,QAAQ,EAAEQ,SAAS,CAAC,GAAGJ,mBAAmB,CAACC,iBAAiB,EAAE/C,OAAO,EAAEgD,kBAAkB,CAAC;EAC9G,IAAA,MAAMmB,WAAW,GAAGjB,SAAS,KAAKH,iBAAiB;EACnD,IAAA,MAAMN,MAAM,GAAGf,gBAAgB,CAAC5I,OAAO,CAAC;MACxC,MAAM+K,iBAAiB,GAAGpB,MAAM,CAACS,SAAS,CAAC,IAAI,EAAE;EACjD,IAAA,MAAMkB,WAAW,GAAGrB,iBAAiB,CAACsB,UAAU,CAAC,GAAG,CAAC;EAErD,IAAA,IAAI,OAAO3B,QAAQ,KAAK,WAAW,EAAE;EACnC;QACA,IAAI,CAAChI,MAAM,CAACjB,IAAI,CAACoK,iBAAiB,CAAC,CAACvH,MAAM,EAAE;EAC1C,QAAA;EACF,MAAA;EAEAmH,MAAAA,aAAa,CAAC3K,OAAO,EAAE2J,MAAM,EAAES,SAAS,EAAER,QAAQ,EAAEO,WAAW,GAAGjD,OAAO,GAAG,IAAI,CAAC;EACjF,MAAA;EACF,IAAA;EAEA,IAAA,IAAIoE,WAAW,EAAE;QACf,KAAK,MAAME,YAAY,IAAI5J,MAAM,CAACjB,IAAI,CAACgJ,MAAM,CAAC,EAAE;EAC9CkB,QAAAA,wBAAwB,CAAC7K,OAAO,EAAE2J,MAAM,EAAE6B,YAAY,EAAEvB,iBAAiB,CAACwB,KAAK,CAAC,CAAC,CAAC,CAAC;EACrF,MAAA;EACF,IAAA;EAEA,IAAA,KAAK,MAAM,CAACC,WAAW,EAAE5C,KAAK,CAAC,IAAIlH,MAAM,CAACqJ,OAAO,CAACF,iBAAiB,CAAC,EAAE;QACpE,MAAMC,UAAU,GAAGU,WAAW,CAACpK,OAAO,CAAC4G,aAAa,EAAE,EAAE,CAAC;QAEzD,IAAI,CAACmD,WAAW,IAAIpB,iBAAiB,CAACiB,QAAQ,CAACF,UAAU,CAAC,EAAE;EAC1DL,QAAAA,aAAa,CAAC3K,OAAO,EAAE2J,MAAM,EAAES,SAAS,EAAEtB,KAAK,CAACc,QAAQ,EAAEd,KAAK,CAACe,kBAAkB,CAAC;EACrF,MAAA;EACF,IAAA;IACF,CAAC;EAED8B,EAAAA,OAAOA,CAAC3L,OAAO,EAAE8I,KAAK,EAAEpC,IAAI,EAAE;EAC5B,IAAA,IAAI,OAAOoC,KAAK,KAAK,QAAQ,IAAI,CAAC9I,OAAO,EAAE;EACzC,MAAA,OAAO,IAAI;EACb,IAAA;EAEA,IAAA,MAAMgG,CAAC,GAAGb,SAAS,EAAE;EACrB,IAAA,MAAMiF,SAAS,GAAGC,YAAY,CAACvB,KAAK,CAAC;EACrC,IAAA,MAAMuC,WAAW,GAAGvC,KAAK,KAAKsB,SAAS;MAEvC,IAAIwB,WAAW,GAAG,IAAI;MACtB,IAAIC,OAAO,GAAG,IAAI;MAClB,IAAIC,cAAc,GAAG,IAAI;MACzB,IAAIC,gBAAgB,GAAG,KAAK;MAE5B,IAAIV,WAAW,IAAIrF,CAAC,EAAE;QACpB4F,WAAW,GAAG5F,CAAC,CAAC7C,KAAK,CAAC2F,KAAK,EAAEpC,IAAI,CAAC;EAElCV,MAAAA,CAAC,CAAChG,OAAO,CAAC,CAAC2L,OAAO,CAACC,WAAW,CAAC;EAC/BC,MAAAA,OAAO,GAAG,CAACD,WAAW,CAACI,oBAAoB,EAAE;EAC7CF,MAAAA,cAAc,GAAG,CAACF,WAAW,CAACK,6BAA6B,EAAE;EAC7DF,MAAAA,gBAAgB,GAAGH,WAAW,CAACM,kBAAkB,EAAE;EACrD,IAAA;MAEA,MAAMC,GAAG,GAAGpD,UAAU,CAAC,IAAI5F,KAAK,CAAC2F,KAAK,EAAE;QAAE+C,OAAO;EAAEO,MAAAA,UAAU,EAAE;OAAM,CAAC,EAAE1F,IAAI,CAAC;EAE7E,IAAA,IAAIqF,gBAAgB,EAAE;QACpBI,GAAG,CAACE,cAAc,EAAE;EACtB,IAAA;EAEA,IAAA,IAAIP,cAAc,EAAE;EAClB9L,MAAAA,OAAO,CAACkD,aAAa,CAACiJ,GAAG,CAAC;EAC5B,IAAA;EAEA,IAAA,IAAIA,GAAG,CAACJ,gBAAgB,IAAIH,WAAW,EAAE;QACvCA,WAAW,CAACS,cAAc,EAAE;EAC9B,IAAA;EAEA,IAAA,OAAOF,GAAG;EACZ,EAAA;EACF,CAAC;EAED,SAASpD,UAAUA,CAACuD,GAAG,EAAEC,IAAI,GAAG,EAAE,EAAE;EAClC,EAAA,KAAK,MAAM,CAACtM,GAAG,EAAEuM,KAAK,CAAC,IAAI5K,MAAM,CAACqJ,OAAO,CAACsB,IAAI,CAAC,EAAE;MAC/C,IAAI;EACFD,MAAAA,GAAG,CAACrM,GAAG,CAAC,GAAGuM,KAAK;MAClB,CAAC,CAAC,OAAAC,OAAA,EAAM;EACN7K,MAAAA,MAAM,CAAC8K,cAAc,CAACJ,GAAG,EAAErM,GAAG,EAAE;EAC9B0M,QAAAA,YAAY,EAAE,IAAI;EAClBtM,QAAAA,GAAGA,GAAG;EACJ,UAAA,OAAOmM,KAAK;EACd,QAAA;EACF,OAAC,CAAC;EACJ,IAAA;EACF,EAAA;EAEA,EAAA,OAAOF,GAAG;EACZ;;EC1TA;EACA;EACA;EACA;EACA;EACA;;EAEA,SAASM,aAAaA,CAACJ,KAAK,EAAE;IAC5B,IAAIA,KAAK,KAAK,MAAM,EAAE;EACpB,IAAA,OAAO,IAAI;EACb,EAAA;IAEA,IAAIA,KAAK,KAAK,OAAO,EAAE;EACrB,IAAA,OAAO,KAAK;EACd,EAAA;IAEA,IAAIA,KAAK,KAAK3J,MAAM,CAAC2J,KAAK,CAAC,CAAC1K,QAAQ,EAAE,EAAE;MACtC,OAAOe,MAAM,CAAC2J,KAAK,CAAC;EACtB,EAAA;EAEA,EAAA,IAAIA,KAAK,KAAK,EAAE,IAAIA,KAAK,KAAK,MAAM,EAAE;EACpC,IAAA,OAAO,IAAI;EACb,EAAA;EAEA,EAAA,IAAI,OAAOA,KAAK,KAAK,QAAQ,EAAE;EAC7B,IAAA,OAAOA,KAAK;EACd,EAAA;IAEA,IAAI;MACF,OAAOK,IAAI,CAACC,KAAK,CAACC,kBAAkB,CAACP,KAAK,CAAC,CAAC;IAC9C,CAAC,CAAC,OAAAC,OAAA,EAAM;EACN,IAAA,OAAOD,KAAK;EACd,EAAA;EACF;EAEA,SAASQ,gBAAgBA,CAAC/M,GAAG,EAAE;EAC7B,EAAA,OAAOA,GAAG,CAACqB,OAAO,CAAC,QAAQ,EAAE2L,GAAG,IAAI,CAAA,CAAA,EAAIA,GAAG,CAACjL,WAAW,EAAE,EAAE,CAAC;EAC9D;EAEA,MAAMkL,WAAW,GAAG;EAClBC,EAAAA,gBAAgBA,CAACnN,OAAO,EAAEC,GAAG,EAAEuM,KAAK,EAAE;MACpCxM,OAAO,CAACoN,YAAY,CAAC,CAAA,QAAA,EAAWJ,gBAAgB,CAAC/M,GAAG,CAAC,CAAA,CAAE,EAAEuM,KAAK,CAAC;IACjE,CAAC;EAEDa,EAAAA,mBAAmBA,CAACrN,OAAO,EAAEC,GAAG,EAAE;MAChCD,OAAO,CAACsN,eAAe,CAAC,CAAA,QAAA,EAAWN,gBAAgB,CAAC/M,GAAG,CAAC,CAAA,CAAE,CAAC;IAC7D,CAAC;IAEDsN,iBAAiBA,CAACvN,OAAO,EAAE;MACzB,IAAI,CAACA,OAAO,EAAE;EACZ,MAAA,OAAO,EAAE;EACX,IAAA;MAEA,MAAMwN,UAAU,GAAG,EAAE;EACrB,IAAA,MAAMC,MAAM,GAAG7L,MAAM,CAACjB,IAAI,CAACX,OAAO,CAAC0N,OAAO,CAAC,CAACC,MAAM,CAAC1N,GAAG,IAAIA,GAAG,CAACsL,UAAU,CAAC,IAAI,CAAC,IAAI,CAACtL,GAAG,CAACsL,UAAU,CAAC,UAAU,CAAC,CAAC;EAE9G,IAAA,KAAK,MAAMtL,GAAG,IAAIwN,MAAM,EAAE;QACxB,IAAIG,OAAO,GAAG3N,GAAG,CAACqB,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;EACpCsM,MAAAA,OAAO,GAAGA,OAAO,CAACC,MAAM,CAAC,CAAC,CAAC,CAAC7L,WAAW,EAAE,GAAG4L,OAAO,CAACnC,KAAK,CAAC,CAAC,CAAC;EAC5D+B,MAAAA,UAAU,CAACI,OAAO,CAAC,GAAGhB,aAAa,CAAC5M,OAAO,CAAC0N,OAAO,CAACzN,GAAG,CAAC,CAAC;EAC3D,IAAA;EAEA,IAAA,OAAOuN,UAAU;IACnB,CAAC;EAEDM,EAAAA,gBAAgBA,CAAC9N,OAAO,EAAEC,GAAG,EAAE;EAC7B,IAAA,OAAO2M,aAAa,CAAC5M,OAAO,CAACyE,YAAY,CAAC,CAAA,QAAA,EAAWuI,gBAAgB,CAAC/M,GAAG,CAAC,CAAA,CAAE,CAAC,CAAC;EAChF,EAAA;EACF,CAAC;;ECpED;EACA;EACA;EACA;EACA;EACA;;;EAKA;EACA;EACA;;EAEA,MAAM8N,MAAM,CAAC;EACX;IACA,WAAWC,OAAOA,GAAG;EACnB,IAAA,OAAO,EAAE;EACX,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAO,EAAE;EACX,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,MAAM,IAAIgI,KAAK,CAAC,qEAAqE,CAAC;EACxF,EAAA;IAEAC,UAAUA,CAACC,MAAM,EAAE;EACjBA,IAAAA,MAAM,GAAG,IAAI,CAACC,eAAe,CAACD,MAAM,CAAC;EACrCA,IAAAA,MAAM,GAAG,IAAI,CAACE,iBAAiB,CAACF,MAAM,CAAC;EACvC,IAAA,IAAI,CAACG,gBAAgB,CAACH,MAAM,CAAC;EAC7B,IAAA,OAAOA,MAAM;EACf,EAAA;IAEAE,iBAAiBA,CAACF,MAAM,EAAE;EACxB,IAAA,OAAOA,MAAM;EACf,EAAA;EAEAC,EAAAA,eAAeA,CAACD,MAAM,EAAEpO,OAAO,EAAE;EAC/B,IAAA,MAAMwO,UAAU,GAAGpL,SAAS,CAACpD,OAAO,CAAC,GAAGkN,WAAW,CAACY,gBAAgB,CAAC9N,OAAO,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAA;;MAE5F,OAAO;EACL,MAAA,GAAG,IAAI,CAACyO,WAAW,CAACT,OAAO;QAC3B,IAAI,OAAOQ,UAAU,KAAK,QAAQ,GAAGA,UAAU,GAAG,EAAE,CAAC;EACrD,MAAA,IAAIpL,SAAS,CAACpD,OAAO,CAAC,GAAGkN,WAAW,CAACK,iBAAiB,CAACvN,OAAO,CAAC,GAAG,EAAE,CAAC;QACrE,IAAI,OAAOoO,MAAM,KAAK,QAAQ,GAAGA,MAAM,GAAG,EAAE;OAC7C;EACH,EAAA;IAEAG,gBAAgBA,CAACH,MAAM,EAAEM,WAAW,GAAG,IAAI,CAACD,WAAW,CAACR,WAAW,EAAE;EACnE,IAAA,KAAK,MAAM,CAACU,QAAQ,EAAEC,aAAa,CAAC,IAAIhN,MAAM,CAACqJ,OAAO,CAACyD,WAAW,CAAC,EAAE;EACnE,MAAA,MAAMlC,KAAK,GAAG4B,MAAM,CAACO,QAAQ,CAAC;EAC9B,MAAA,MAAME,SAAS,GAAGzL,SAAS,CAACoJ,KAAK,CAAC,GAAG,SAAS,GAAG/K,MAAM,CAAC+K,KAAK,CAAC;QAE9D,IAAI,CAAC,IAAIsC,MAAM,CAACF,aAAa,CAAC,CAACG,IAAI,CAACF,SAAS,CAAC,EAAE;UAC9C,MAAM,IAAIG,SAAS,CACjB,CAAA,EAAG,IAAI,CAACP,WAAW,CAACvI,IAAI,CAAC+I,WAAW,EAAE,aAAaN,QAAQ,CAAA,iBAAA,EAAoBE,SAAS,CAAA,qBAAA,EAAwBD,aAAa,IAC/H,CAAC;EACH,MAAA;EACF,IAAA;EACF,EAAA;EACF;;EC9DA;EACA;EACA;EACA;EACA;EACA;;;EAOA;EACA;EACA;;EAEA,MAAMM,OAAO,GAAG,OAAO;;EAEvB;EACA;EACA;;EAEA,MAAMC,aAAa,SAASpB,MAAM,CAAC;EACjCU,EAAAA,WAAWA,CAACzO,OAAO,EAAEoO,MAAM,EAAE;EAC3B,IAAA,KAAK,EAAE;EAEPpO,IAAAA,OAAO,GAAGuD,UAAU,CAACvD,OAAO,CAAC;MAC7B,IAAI,CAACA,OAAO,EAAE;EACZ,MAAA;EACF,IAAA;MAEA,IAAI,CAACoP,QAAQ,GAAGpP,OAAO;MACvB,IAAI,CAACqP,OAAO,GAAG,IAAI,CAAClB,UAAU,CAACC,MAAM,CAAC;EAEtCkB,IAAAA,IAAI,CAACvP,GAAG,CAAC,IAAI,CAACqP,QAAQ,EAAE,IAAI,CAACX,WAAW,CAACc,QAAQ,EAAE,IAAI,CAAC;EAC1D,EAAA;;EAEA;EACAC,EAAAA,OAAOA,GAAG;EACRF,IAAAA,IAAI,CAAC1O,MAAM,CAAC,IAAI,CAACwO,QAAQ,EAAE,IAAI,CAACX,WAAW,CAACc,QAAQ,CAAC;EACrDrG,IAAAA,YAAY,CAACC,GAAG,CAAC,IAAI,CAACiG,QAAQ,EAAE,IAAI,CAACX,WAAW,CAACgB,SAAS,CAAC;MAE3D,KAAK,MAAMC,YAAY,IAAI9N,MAAM,CAAC+N,mBAAmB,CAAC,IAAI,CAAC,EAAE;EAC3D,MAAA,IAAI,CAACD,YAAY,CAAC,GAAG,IAAI;EAC3B,IAAA;EACF,EAAA;;EAEA;IACAE,cAAcA,CAACpK,QAAQ,EAAExF,OAAO,EAAE6P,UAAU,GAAG,IAAI,EAAE;EACnDjJ,IAAAA,sBAAsB,CAACpB,QAAQ,EAAExF,OAAO,EAAE6P,UAAU,CAAC;EACvD,EAAA;IAEA1B,UAAUA,CAACC,MAAM,EAAE;MACjBA,MAAM,GAAG,IAAI,CAACC,eAAe,CAACD,MAAM,EAAE,IAAI,CAACgB,QAAQ,CAAC;EACpDhB,IAAAA,MAAM,GAAG,IAAI,CAACE,iBAAiB,CAACF,MAAM,CAAC;EACvC,IAAA,IAAI,CAACG,gBAAgB,CAACH,MAAM,CAAC;EAC7B,IAAA,OAAOA,MAAM;EACf,EAAA;;EAEA;IACA,OAAO0B,WAAWA,CAAC9P,OAAO,EAAE;EAC1B,IAAA,OAAOsP,IAAI,CAACjP,GAAG,CAACkD,UAAU,CAACvD,OAAO,CAAC,EAAE,IAAI,CAACuP,QAAQ,CAAC;EACrD,EAAA;IAEA,OAAOQ,mBAAmBA,CAAC/P,OAAO,EAAEoO,MAAM,GAAG,EAAE,EAAE;MAC/C,OAAO,IAAI,CAAC0B,WAAW,CAAC9P,OAAO,CAAC,IAAI,IAAI,IAAI,CAACA,OAAO,EAAE,OAAOoO,MAAM,KAAK,QAAQ,GAAGA,MAAM,GAAG,IAAI,CAAC;EACnG,EAAA;IAEA,WAAWc,OAAOA,GAAG;EACnB,IAAA,OAAOA,OAAO;EAChB,EAAA;IAEA,WAAWK,QAAQA,GAAG;EACpB,IAAA,OAAO,CAAA,GAAA,EAAM,IAAI,CAACrJ,IAAI,CAAA,CAAE;EAC1B,EAAA;IAEA,WAAWuJ,SAASA,GAAG;EACrB,IAAA,OAAO,CAAA,CAAA,EAAI,IAAI,CAACF,QAAQ,CAAA,CAAE;EAC5B,EAAA;IAEA,OAAOS,SAASA,CAAC/J,IAAI,EAAE;EACrB,IAAA,OAAO,GAAGA,IAAI,CAAA,EAAG,IAAI,CAACwJ,SAAS,CAAA,CAAE;EACnC,EAAA;EACF;;ECnFA;EACA;EACA;EACA;EACA;EACA;;EAIA,MAAMQ,WAAW,GAAGjQ,OAAO,IAAI;EAC7B,EAAA,IAAIkB,QAAQ,GAAGlB,OAAO,CAACyE,YAAY,CAAC,gBAAgB,CAAC;EAErD,EAAA,IAAI,CAACvD,QAAQ,IAAIA,QAAQ,KAAK,GAAG,EAAE;EACjC,IAAA,IAAIgP,aAAa,GAAGlQ,OAAO,CAACyE,YAAY,CAAC,MAAM,CAAC;;EAEhD;EACA;EACA;EACA;EACA,IAAA,IAAI,CAACyL,aAAa,IAAK,CAACA,aAAa,CAAChF,QAAQ,CAAC,GAAG,CAAC,IAAI,CAACgF,aAAa,CAAC3E,UAAU,CAAC,GAAG,CAAE,EAAE;EACtF,MAAA,OAAO,IAAI;EACb,IAAA;;EAEA;EACA,IAAA,IAAI2E,aAAa,CAAChF,QAAQ,CAAC,GAAG,CAAC,IAAI,CAACgF,aAAa,CAAC3E,UAAU,CAAC,GAAG,CAAC,EAAE;QACjE2E,aAAa,GAAG,CAAA,CAAA,EAAIA,aAAa,CAAClN,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA,CAAE;EACnD,IAAA;EAEA9B,IAAAA,QAAQ,GAAGgP,aAAa,IAAIA,aAAa,KAAK,GAAG,GAAGA,aAAa,CAACC,IAAI,EAAE,GAAG,IAAI;EACjF,EAAA;IAEA,OAAOjP,QAAQ,GAAGA,QAAQ,CAAC8B,KAAK,CAAC,GAAG,CAAC,CAACoN,GAAG,CAACC,GAAG,IAAIpP,aAAa,CAACoP,GAAG,CAAC,CAAC,CAACC,IAAI,CAAC,GAAG,CAAC,GAAG,IAAI;EACvF,CAAC;EAED,MAAMC,cAAc,GAAG;IACrBxG,IAAIA,CAAC7I,QAAQ,EAAElB,OAAO,GAAGsC,QAAQ,CAACqC,eAAe,EAAE;EACjD,IAAA,OAAO,EAAE,CAAC6L,MAAM,CAAC,GAAGC,OAAO,CAAC5O,SAAS,CAAC2H,gBAAgB,CAACzH,IAAI,CAAC/B,OAAO,EAAEkB,QAAQ,CAAC,CAAC;IACjF,CAAC;IAEDwP,OAAOA,CAACxP,QAAQ,EAAElB,OAAO,GAAGsC,QAAQ,CAACqC,eAAe,EAAE;MACpD,OAAO8L,OAAO,CAAC5O,SAAS,CAAC4B,aAAa,CAAC1B,IAAI,CAAC/B,OAAO,EAAEkB,QAAQ,CAAC;IAChE,CAAC;EAEDyP,EAAAA,QAAQA,CAAC3Q,OAAO,EAAEkB,QAAQ,EAAE;MAC1B,OAAO,EAAE,CAACsP,MAAM,CAAC,GAAGxQ,OAAO,CAAC2Q,QAAQ,CAAC,CAAChD,MAAM,CAACiD,KAAK,IAAIA,KAAK,CAACC,OAAO,CAAC3P,QAAQ,CAAC,CAAC;IAChF,CAAC;EAED4P,EAAAA,OAAOA,CAAC9Q,OAAO,EAAEkB,QAAQ,EAAE;MACzB,MAAM4P,OAAO,GAAG,EAAE;MAClB,IAAIC,QAAQ,GAAG/Q,OAAO,CAACiE,UAAU,CAACF,OAAO,CAAC7C,QAAQ,CAAC;EAEnD,IAAA,OAAO6P,QAAQ,EAAE;EACfD,MAAAA,OAAO,CAACnL,IAAI,CAACoL,QAAQ,CAAC;QACtBA,QAAQ,GAAGA,QAAQ,CAAC9M,UAAU,CAACF,OAAO,CAAC7C,QAAQ,CAAC;EAClD,IAAA;EAEA,IAAA,OAAO4P,OAAO;IAChB,CAAC;EAEDE,EAAAA,IAAIA,CAAChR,OAAO,EAAEkB,QAAQ,EAAE;EACtB,IAAA,IAAI+P,QAAQ,GAAGjR,OAAO,CAACkR,sBAAsB;EAE7C,IAAA,OAAOD,QAAQ,EAAE;EACf,MAAA,IAAIA,QAAQ,CAACJ,OAAO,CAAC3P,QAAQ,CAAC,EAAE;UAC9B,OAAO,CAAC+P,QAAQ,CAAC;EACnB,MAAA;QAEAA,QAAQ,GAAGA,QAAQ,CAACC,sBAAsB;EAC5C,IAAA;EAEA,IAAA,OAAO,EAAE;IACX,CAAC;EACD;EACAC,EAAAA,IAAIA,CAACnR,OAAO,EAAEkB,QAAQ,EAAE;EACtB,IAAA,IAAIiQ,IAAI,GAAGnR,OAAO,CAACoR,kBAAkB;EAErC,IAAA,OAAOD,IAAI,EAAE;EACX,MAAA,IAAIA,IAAI,CAACN,OAAO,CAAC3P,QAAQ,CAAC,EAAE;UAC1B,OAAO,CAACiQ,IAAI,CAAC;EACf,MAAA;QAEAA,IAAI,GAAGA,IAAI,CAACC,kBAAkB;EAChC,IAAA;EAEA,IAAA,OAAO,EAAE;IACX,CAAC;IAEDC,iBAAiBA,CAACrR,OAAO,EAAE;EACzB,IAAA,MAAMsR,UAAU,GAAG,CACjB,GAAG,EACH,QAAQ,EACR,OAAO,EACP,UAAU,EACV,QAAQ,EACR,SAAS,EACT,YAAY,EACZ,0BAA0B,CAC3B,CAAClB,GAAG,CAAClP,QAAQ,IAAI,CAAA,EAAGA,QAAQ,CAAA,qBAAA,CAAuB,CAAC,CAACoP,IAAI,CAAC,GAAG,CAAC;MAE/D,OAAO,IAAI,CAACvG,IAAI,CAACuH,UAAU,EAAEtR,OAAO,CAAC,CAAC2N,MAAM,CAAC4D,EAAE,IAAI,CAACrN,UAAU,CAACqN,EAAE,CAAC,IAAI7N,SAAS,CAAC6N,EAAE,CAAC,CAAC;IACtF,CAAC;IAEDC,sBAAsBA,CAACxR,OAAO,EAAE;EAC9B,IAAA,MAAMkB,QAAQ,GAAG+O,WAAW,CAACjQ,OAAO,CAAC;EAErC,IAAA,IAAIkB,QAAQ,EAAE;QACZ,OAAOqP,cAAc,CAACG,OAAO,CAACxP,QAAQ,CAAC,GAAGA,QAAQ,GAAG,IAAI;EAC3D,IAAA;EAEA,IAAA,OAAO,IAAI;IACb,CAAC;IAEDuQ,sBAAsBA,CAACzR,OAAO,EAAE;EAC9B,IAAA,MAAMkB,QAAQ,GAAG+O,WAAW,CAACjQ,OAAO,CAAC;MAErC,OAAOkB,QAAQ,GAAGqP,cAAc,CAACG,OAAO,CAACxP,QAAQ,CAAC,GAAG,IAAI;IAC3D,CAAC;IAEDwQ,+BAA+BA,CAAC1R,OAAO,EAAE;EACvC,IAAA,MAAMkB,QAAQ,GAAG+O,WAAW,CAACjQ,OAAO,CAAC;MAErC,OAAOkB,QAAQ,GAAGqP,cAAc,CAACxG,IAAI,CAAC7I,QAAQ,CAAC,GAAG,EAAE;EACtD,EAAA;EACF,CAAC;;EC3HD;EACA;EACA;EACA;EACA;EACA;;EAMA,MAAMyQ,oBAAoB,GAAGA,CAACC,SAAS,EAAEC,MAAM,GAAG,MAAM,KAAK;EAC3D,EAAA,MAAMC,UAAU,GAAG,CAAA,aAAA,EAAgBF,SAAS,CAACnC,SAAS,CAAA,CAAE;EACxD,EAAA,MAAMxJ,IAAI,GAAG2L,SAAS,CAAC1L,IAAI;EAE3BgD,EAAAA,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAEwP,UAAU,EAAE,CAAA,kBAAA,EAAqB7L,IAAI,CAAA,EAAA,CAAI,EAAE,UAAU6C,KAAK,EAAE;EACpF,IAAA,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAACoC,QAAQ,CAAC,IAAI,CAAC6G,OAAO,CAAC,EAAE;QACxCjJ,KAAK,CAACuD,cAAc,EAAE;EACxB,IAAA;EAEA,IAAA,IAAInI,UAAU,CAAC,IAAI,CAAC,EAAE;EACpB,MAAA;EACF,IAAA;EAEA,IAAA,MAAMiD,MAAM,GAAGoJ,cAAc,CAACkB,sBAAsB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC1N,OAAO,CAAC,CAAA,CAAA,EAAIkC,IAAI,EAAE,CAAC;EACtF,IAAA,MAAM/F,QAAQ,GAAG0R,SAAS,CAAC7B,mBAAmB,CAAC5I,MAAM,CAAC;;EAEtD;EACAjH,IAAAA,QAAQ,CAAC2R,MAAM,CAAC,EAAE;EACpB,EAAA,CAAC,CAAC;EACJ,CAAC;;EC9BD;EACA;EACA;EACA;EACA;EACA;;;EAOA;EACA;EACA;;EAEA,MAAM3L,MAAI,GAAG,OAAO;EACpB,MAAMqJ,UAAQ,GAAG,UAAU;EAC3B,MAAME,WAAS,GAAG,CAAA,CAAA,EAAIF,UAAQ,CAAA,CAAE;EAEhC,MAAMyC,WAAW,GAAG,CAAA,KAAA,EAAQvC,WAAS,CAAA,CAAE;EACvC,MAAMwC,YAAY,GAAG,CAAA,MAAA,EAASxC,WAAS,CAAA,CAAE;EACzC,MAAMyC,iBAAe,GAAG,MAAM;EAC9B,MAAMC,iBAAe,GAAG,MAAM;;EAE9B;EACA;EACA;;EAEA,MAAMC,KAAK,SAASjD,aAAa,CAAC;EAChC;IACA,WAAWjJ,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACAmM,EAAAA,KAAKA,GAAG;MACN,MAAMC,UAAU,GAAGpJ,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAE4C,WAAW,CAAC;MAEnE,IAAIM,UAAU,CAACvG,gBAAgB,EAAE;EAC/B,MAAA;EACF,IAAA;MAEA,IAAI,CAACqD,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAACuR,iBAAe,CAAC;MAE/C,MAAMtC,UAAU,GAAG,IAAI,CAACT,QAAQ,CAAC/K,SAAS,CAACC,QAAQ,CAAC4N,iBAAe,CAAC;EACpE,IAAA,IAAI,CAACtC,cAAc,CAAC,MAAM,IAAI,CAAC2C,eAAe,EAAE,EAAE,IAAI,CAACnD,QAAQ,EAAES,UAAU,CAAC;EAC9E,EAAA;;EAEA;EACA0C,EAAAA,eAAeA,GAAG;EAChB,IAAA,IAAI,CAACnD,QAAQ,CAACxO,MAAM,EAAE;MACtBsI,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAE6C,YAAY,CAAC;MACjD,IAAI,CAACzC,OAAO,EAAE;EAChB,EAAA;;EAEA;IACA,OAAOnJ,eAAeA,CAAC+H,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACoE,IAAI,CAAC,YAAY;EAC3B,MAAA,MAAMC,IAAI,GAAGL,KAAK,CAACrC,mBAAmB,CAAC,IAAI,CAAC;EAE5C,MAAA,IAAI,OAAO3B,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA;EACF,MAAA;EAEA,MAAA,IAAIqE,IAAI,CAACrE,MAAM,CAAC,KAAKzM,SAAS,IAAIyM,MAAM,CAAC7C,UAAU,CAAC,GAAG,CAAC,IAAI6C,MAAM,KAAK,aAAa,EAAE;EACpF,QAAA,MAAM,IAAIY,SAAS,CAAC,CAAA,iBAAA,EAAoBZ,MAAM,GAAG,CAAC;EACpD,MAAA;EAEAqE,MAAAA,IAAI,CAACrE,MAAM,CAAC,CAAC,IAAI,CAAC;EACpB,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAuD,oBAAoB,CAACS,KAAK,EAAE,OAAO,CAAC;;EAEpC;EACA;EACA;;EAEAtM,kBAAkB,CAACsM,KAAK,CAAC;;ECpFzB;EACA;EACA;EACA;EACA;EACA;;;EAMA;EACA;EACA;;EAEA,MAAMlM,MAAI,GAAG,QAAQ;EACrB,MAAMqJ,UAAQ,GAAG,WAAW;EAC5B,MAAME,WAAS,GAAG,CAAA,CAAA,EAAIF,UAAQ,CAAA,CAAE;EAChC,MAAMmD,cAAY,GAAG,WAAW;EAEhC,MAAMC,mBAAiB,GAAG,QAAQ;EAClC,MAAMC,sBAAoB,GAAG,2BAA2B;EACxD,MAAMC,sBAAoB,GAAG,CAAA,KAAA,EAAQpD,WAAS,CAAA,EAAGiD,cAAY,CAAA,CAAE;;EAE/D;EACA;EACA;;EAEA,MAAMI,MAAM,SAAS3D,aAAa,CAAC;EACjC;IACA,WAAWjJ,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACA6M,EAAAA,MAAMA,GAAG;EACP;EACA,IAAA,IAAI,CAAC3D,QAAQ,CAAChC,YAAY,CAAC,cAAc,EAAE,IAAI,CAACgC,QAAQ,CAAC/K,SAAS,CAAC0O,MAAM,CAACJ,mBAAiB,CAAC,CAAC;EAC/F,EAAA;;EAEA;IACA,OAAOtM,eAAeA,CAAC+H,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACoE,IAAI,CAAC,YAAY;EAC3B,MAAA,MAAMC,IAAI,GAAGK,MAAM,CAAC/C,mBAAmB,CAAC,IAAI,CAAC;QAE7C,IAAI3B,MAAM,KAAK,QAAQ,EAAE;EACvBqE,QAAAA,IAAI,CAACrE,MAAM,CAAC,EAAE;EAChB,MAAA;EACF,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAlF,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAEuQ,sBAAoB,EAAED,sBAAoB,EAAE9J,KAAK,IAAI;IAC7EA,KAAK,CAACuD,cAAc,EAAE;IAEtB,MAAM2G,MAAM,GAAGlK,KAAK,CAAC3B,MAAM,CAACpD,OAAO,CAAC6O,sBAAoB,CAAC;EACzD,EAAA,MAAMH,IAAI,GAAGK,MAAM,CAAC/C,mBAAmB,CAACiD,MAAM,CAAC;IAE/CP,IAAI,CAACM,MAAM,EAAE;EACf,CAAC,CAAC;;EAEF;EACA;EACA;;EAEAjN,kBAAkB,CAACgN,MAAM,CAAC;;ECrE1B;EACA;EACA;EACA;EACA;EACA;;;EAMA;EACA;EACA;;EAEA,MAAM5M,MAAI,GAAG,OAAO;EACpB,MAAMuJ,WAAS,GAAG,WAAW;EAC7B,MAAMwD,gBAAgB,GAAG,CAAA,UAAA,EAAaxD,WAAS,CAAA,CAAE;EACjD,MAAMyD,eAAe,GAAG,CAAA,SAAA,EAAYzD,WAAS,CAAA,CAAE;EAC/C,MAAM0D,cAAc,GAAG,CAAA,QAAA,EAAW1D,WAAS,CAAA,CAAE;EAC7C,MAAM2D,iBAAiB,GAAG,CAAA,WAAA,EAAc3D,WAAS,CAAA,CAAE;EACnD,MAAM4D,eAAe,GAAG,CAAA,SAAA,EAAY5D,WAAS,CAAA,CAAE;EAC/C,MAAM6D,kBAAkB,GAAG,OAAO;EAClC,MAAMC,gBAAgB,GAAG,KAAK;EAC9B,MAAMC,wBAAwB,GAAG,eAAe;EAChD,MAAMC,eAAe,GAAG,EAAE;EAE1B,MAAMzF,SAAO,GAAG;EACd0F,EAAAA,WAAW,EAAE,IAAI;EACjBC,EAAAA,YAAY,EAAE,IAAI;EAClBC,EAAAA,aAAa,EAAE;EACjB,CAAC;EAED,MAAM3F,aAAW,GAAG;EAClByF,EAAAA,WAAW,EAAE,iBAAiB;EAC9BC,EAAAA,YAAY,EAAE,iBAAiB;EAC/BC,EAAAA,aAAa,EAAE;EACjB,CAAC;;EAED;EACA;EACA;;EAEA,MAAMC,KAAK,SAAS9F,MAAM,CAAC;EACzBU,EAAAA,WAAWA,CAACzO,OAAO,EAAEoO,MAAM,EAAE;EAC3B,IAAA,KAAK,EAAE;MACP,IAAI,CAACgB,QAAQ,GAAGpP,OAAO;MAEvB,IAAI,CAACA,OAAO,IAAI,CAAC6T,KAAK,CAACC,WAAW,EAAE,EAAE;EACpC,MAAA;EACF,IAAA;MAEA,IAAI,CAACzE,OAAO,GAAG,IAAI,CAAClB,UAAU,CAACC,MAAM,CAAC;MACtC,IAAI,CAAC2F,OAAO,GAAG,CAAC;MAChB,IAAI,CAACC,qBAAqB,GAAGpJ,OAAO,CAACzJ,MAAM,CAAC8S,YAAY,CAAC;MACzD,IAAI,CAACC,WAAW,EAAE;EACpB,EAAA;;EAEA;IACA,WAAWlG,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACAsJ,EAAAA,OAAOA,GAAG;MACRtG,YAAY,CAACC,GAAG,CAAC,IAAI,CAACiG,QAAQ,EAAEK,WAAS,CAAC;EAC5C,EAAA;;EAEA;IACA0E,MAAMA,CAACrL,KAAK,EAAE;EACZ,IAAA,IAAI,CAAC,IAAI,CAACkL,qBAAqB,EAAE;QAC/B,IAAI,CAACD,OAAO,GAAGjL,KAAK,CAACsL,OAAO,CAAC,CAAC,CAAC,CAACC,OAAO;EAEvC,MAAA;EACF,IAAA;EAEA,IAAA,IAAI,IAAI,CAACC,uBAAuB,CAACxL,KAAK,CAAC,EAAE;EACvC,MAAA,IAAI,CAACiL,OAAO,GAAGjL,KAAK,CAACuL,OAAO;EAC9B,IAAA;EACF,EAAA;IAEAE,IAAIA,CAACzL,KAAK,EAAE;EACV,IAAA,IAAI,IAAI,CAACwL,uBAAuB,CAACxL,KAAK,CAAC,EAAE;QACvC,IAAI,CAACiL,OAAO,GAAGjL,KAAK,CAACuL,OAAO,GAAG,IAAI,CAACN,OAAO;EAC7C,IAAA;MAEA,IAAI,CAACS,YAAY,EAAE;EACnBhO,IAAAA,OAAO,CAAC,IAAI,CAAC6I,OAAO,CAACqE,WAAW,CAAC;EACnC,EAAA;IAEAe,KAAKA,CAAC3L,KAAK,EAAE;EACX,IAAA,IAAI,CAACiL,OAAO,GAAGjL,KAAK,CAACsL,OAAO,IAAItL,KAAK,CAACsL,OAAO,CAAC5Q,MAAM,GAAG,CAAC,GACtD,CAAC,GACDsF,KAAK,CAACsL,OAAO,CAAC,CAAC,CAAC,CAACC,OAAO,GAAG,IAAI,CAACN,OAAO;EAC3C,EAAA;EAEAS,EAAAA,YAAYA,GAAG;MACb,MAAME,SAAS,GAAGvS,IAAI,CAACwS,GAAG,CAAC,IAAI,CAACZ,OAAO,CAAC;MAExC,IAAIW,SAAS,IAAIjB,eAAe,EAAE;EAChC,MAAA;EACF,IAAA;EAEA,IAAA,MAAMmB,SAAS,GAAGF,SAAS,GAAG,IAAI,CAACX,OAAO;MAE1C,IAAI,CAACA,OAAO,GAAG,CAAC;MAEhB,IAAI,CAACa,SAAS,EAAE;EACd,MAAA;EACF,IAAA;EAEApO,IAAAA,OAAO,CAACoO,SAAS,GAAG,CAAC,GAAG,IAAI,CAACvF,OAAO,CAACuE,aAAa,GAAG,IAAI,CAACvE,OAAO,CAACsE,YAAY,CAAC;EACjF,EAAA;EAEAO,EAAAA,WAAWA,GAAG;MACZ,IAAI,IAAI,CAACF,qBAAqB,EAAE;EAC9B9K,MAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAEgE,iBAAiB,EAAEtK,KAAK,IAAI,IAAI,CAACqL,MAAM,CAACrL,KAAK,CAAC,CAAC;EAC9EI,MAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAEiE,eAAe,EAAEvK,KAAK,IAAI,IAAI,CAACyL,IAAI,CAACzL,KAAK,CAAC,CAAC;QAE1E,IAAI,CAACsG,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAACrB,wBAAwB,CAAC;EACvD,IAAA,CAAC,MAAM;EACLtK,MAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAE6D,gBAAgB,EAAEnK,KAAK,IAAI,IAAI,CAACqL,MAAM,CAACrL,KAAK,CAAC,CAAC;EAC7EI,MAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAE8D,eAAe,EAAEpK,KAAK,IAAI,IAAI,CAAC2L,KAAK,CAAC3L,KAAK,CAAC,CAAC;EAC3EI,MAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAE+D,cAAc,EAAErK,KAAK,IAAI,IAAI,CAACyL,IAAI,CAACzL,KAAK,CAAC,CAAC;EAC3E,IAAA;EACF,EAAA;IAEAwL,uBAAuBA,CAACxL,KAAK,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACkL,qBAAqB,KAAKlL,KAAK,CAACgM,WAAW,KAAKvB,gBAAgB,IAAIzK,KAAK,CAACgM,WAAW,KAAKxB,kBAAkB,CAAC;EAC3H,EAAA;;EAEA;IACA,OAAOQ,WAAWA,GAAG;MACnB,OAAO,cAAc,IAAIxR,QAAQ,CAACqC,eAAe,IAAIoQ,SAAS,CAACC,cAAc,GAAG,CAAC;EACnF,EAAA;EACF;;EC/IA;EACA;EACA;EACA;EACA;EACA;;;EAgBA;EACA;EACA;;EAEA,MAAM9O,MAAI,GAAG,UAAU;EACvB,MAAMqJ,UAAQ,GAAG,aAAa;EAC9B,MAAME,WAAS,GAAG,CAAA,CAAA,EAAIF,UAAQ,CAAA,CAAE;EAChC,MAAMmD,cAAY,GAAG,WAAW;EAEhC,MAAMuC,gBAAc,GAAG,WAAW;EAClC,MAAMC,iBAAe,GAAG,YAAY;EACpC,MAAMC,sBAAsB,GAAG,GAAG,CAAA;;EAElC,MAAMC,UAAU,GAAG,MAAM;EACzB,MAAMC,UAAU,GAAG,MAAM;EACzB,MAAMC,cAAc,GAAG,MAAM;EAC7B,MAAMC,eAAe,GAAG,OAAO;EAE/B,MAAMC,WAAW,GAAG,CAAA,KAAA,EAAQ/F,WAAS,CAAA,CAAE;EACvC,MAAMgG,UAAU,GAAG,CAAA,IAAA,EAAOhG,WAAS,CAAA,CAAE;EACrC,MAAMiG,eAAa,GAAG,CAAA,OAAA,EAAUjG,WAAS,CAAA,CAAE;EAC3C,MAAMkG,kBAAgB,GAAG,CAAA,UAAA,EAAalG,WAAS,CAAA,CAAE;EACjD,MAAMmG,kBAAgB,GAAG,CAAA,UAAA,EAAanG,WAAS,CAAA,CAAE;EACjD,MAAMoG,gBAAgB,GAAG,CAAA,SAAA,EAAYpG,WAAS,CAAA,CAAE;EAChD,MAAMqG,qBAAmB,GAAG,CAAA,IAAA,EAAOrG,WAAS,CAAA,EAAGiD,cAAY,CAAA,CAAE;EAC7D,MAAMG,sBAAoB,GAAG,CAAA,KAAA,EAAQpD,WAAS,CAAA,EAAGiD,cAAY,CAAA,CAAE;EAE/D,MAAMqD,mBAAmB,GAAG,UAAU;EACtC,MAAMpD,mBAAiB,GAAG,QAAQ;EAClC,MAAMqD,gBAAgB,GAAG,OAAO;EAChC,MAAMC,cAAc,GAAG,mBAAmB;EAC1C,MAAMC,gBAAgB,GAAG,qBAAqB;EAC9C,MAAMC,eAAe,GAAG,oBAAoB;EAC5C,MAAMC,eAAe,GAAG,oBAAoB;EAE5C,MAAMC,eAAe,GAAG,SAAS;EACjC,MAAMC,aAAa,GAAG,gBAAgB;EACtC,MAAMC,oBAAoB,GAAGF,eAAe,GAAGC,aAAa;EAC5D,MAAME,iBAAiB,GAAG,oBAAoB;EAC9C,MAAMC,mBAAmB,GAAG,sBAAsB;EAClD,MAAMC,mBAAmB,GAAG,qCAAqC;EACjE,MAAMC,kBAAkB,GAAG,2BAA2B;EAEtD,MAAMC,gBAAgB,GAAG;IACvB,CAAC3B,gBAAc,GAAGM,eAAe;EACjC,EAAA,CAACL,iBAAe,GAAGI;EACrB,CAAC;EAED,MAAMtH,SAAO,GAAG;EACd6I,EAAAA,QAAQ,EAAE,IAAI;EACdC,EAAAA,QAAQ,EAAE,IAAI;EACdC,EAAAA,KAAK,EAAE,OAAO;EACdC,EAAAA,IAAI,EAAE,KAAK;EACXC,EAAAA,KAAK,EAAE,IAAI;EACXC,EAAAA,IAAI,EAAE;EACR,CAAC;EAED,MAAMjJ,aAAW,GAAG;EAClB4I,EAAAA,QAAQ,EAAE,kBAAkB;EAAE;EAC9BC,EAAAA,QAAQ,EAAE,SAAS;EACnBC,EAAAA,KAAK,EAAE,kBAAkB;EACzBC,EAAAA,IAAI,EAAE,kBAAkB;EACxBC,EAAAA,KAAK,EAAE,SAAS;EAChBC,EAAAA,IAAI,EAAE;EACR,CAAC;;EAED;EACA;EACA;;EAEA,MAAMC,QAAQ,SAAShI,aAAa,CAAC;EACnCV,EAAAA,WAAWA,CAACzO,OAAO,EAAEoO,MAAM,EAAE;EAC3B,IAAA,KAAK,CAACpO,OAAO,EAAEoO,MAAM,CAAC;MAEtB,IAAI,CAACgJ,SAAS,GAAG,IAAI;MACrB,IAAI,CAACC,cAAc,GAAG,IAAI;MAC1B,IAAI,CAACC,UAAU,GAAG,KAAK;MACvB,IAAI,CAACC,YAAY,GAAG,IAAI;MACxB,IAAI,CAACC,YAAY,GAAG,IAAI;EAExB,IAAA,IAAI,CAACC,kBAAkB,GAAGlH,cAAc,CAACG,OAAO,CAAC+F,mBAAmB,EAAE,IAAI,CAACrH,QAAQ,CAAC;MACpF,IAAI,CAACsI,kBAAkB,EAAE;EAEzB,IAAA,IAAI,IAAI,CAACrI,OAAO,CAAC2H,IAAI,KAAKjB,mBAAmB,EAAE;QAC7C,IAAI,CAAC4B,KAAK,EAAE;EACd,IAAA;EACF,EAAA;;EAEA;IACA,WAAW3J,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACAiL,EAAAA,IAAIA,GAAG;EACL,IAAA,IAAI,CAACyG,MAAM,CAACxC,UAAU,CAAC;EACzB,EAAA;EAEAyC,EAAAA,eAAeA,GAAG;EAChB;EACA;EACA;MACA,IAAI,CAACvV,QAAQ,CAACwV,MAAM,IAAIpU,SAAS,CAAC,IAAI,CAAC0L,QAAQ,CAAC,EAAE;QAChD,IAAI,CAAC+B,IAAI,EAAE;EACb,IAAA;EACF,EAAA;EAEAH,EAAAA,IAAIA,GAAG;EACL,IAAA,IAAI,CAAC4G,MAAM,CAACvC,UAAU,CAAC;EACzB,EAAA;EAEA0B,EAAAA,KAAKA,GAAG;MACN,IAAI,IAAI,CAACO,UAAU,EAAE;EACnBrU,MAAAA,oBAAoB,CAAC,IAAI,CAACmM,QAAQ,CAAC;EACrC,IAAA;MAEA,IAAI,CAAC2I,cAAc,EAAE;EACvB,EAAA;EAEAJ,EAAAA,KAAKA,GAAG;MACN,IAAI,CAACI,cAAc,EAAE;MACrB,IAAI,CAACC,eAAe,EAAE;EAEtB,IAAA,IAAI,CAACZ,SAAS,GAAGa,WAAW,CAAC,MAAM,IAAI,CAACJ,eAAe,EAAE,EAAE,IAAI,CAACxI,OAAO,CAACwH,QAAQ,CAAC;EACnF,EAAA;EAEAqB,EAAAA,iBAAiBA,GAAG;EAClB,IAAA,IAAI,CAAC,IAAI,CAAC7I,OAAO,CAAC2H,IAAI,EAAE;EACtB,MAAA;EACF,IAAA;MAEA,IAAI,IAAI,CAACM,UAAU,EAAE;EACnBpO,MAAAA,YAAY,CAACkC,GAAG,CAAC,IAAI,CAACgE,QAAQ,EAAEqG,UAAU,EAAE,MAAM,IAAI,CAACkC,KAAK,EAAE,CAAC;EAC/D,MAAA;EACF,IAAA;MAEA,IAAI,CAACA,KAAK,EAAE;EACd,EAAA;IAEAQ,EAAEA,CAACvQ,KAAK,EAAE;EACR,IAAA,MAAMwQ,KAAK,GAAG,IAAI,CAACC,SAAS,EAAE;MAC9B,IAAIzQ,KAAK,GAAGwQ,KAAK,CAAC5U,MAAM,GAAG,CAAC,IAAIoE,KAAK,GAAG,CAAC,EAAE;EACzC,MAAA;EACF,IAAA;MAEA,IAAI,IAAI,CAAC0P,UAAU,EAAE;EACnBpO,MAAAA,YAAY,CAACkC,GAAG,CAAC,IAAI,CAACgE,QAAQ,EAAEqG,UAAU,EAAE,MAAM,IAAI,CAAC0C,EAAE,CAACvQ,KAAK,CAAC,CAAC;EACjE,MAAA;EACF,IAAA;MAEA,MAAM0Q,WAAW,GAAG,IAAI,CAACC,aAAa,CAAC,IAAI,CAACC,UAAU,EAAE,CAAC;MACzD,IAAIF,WAAW,KAAK1Q,KAAK,EAAE;EACzB,MAAA;EACF,IAAA;MAEA,MAAM6Q,KAAK,GAAG7Q,KAAK,GAAG0Q,WAAW,GAAGlD,UAAU,GAAGC,UAAU;MAE3D,IAAI,CAACuC,MAAM,CAACa,KAAK,EAAEL,KAAK,CAACxQ,KAAK,CAAC,CAAC;EAClC,EAAA;EAEA4H,EAAAA,OAAOA,GAAG;MACR,IAAI,IAAI,CAACgI,YAAY,EAAE;EACrB,MAAA,IAAI,CAACA,YAAY,CAAChI,OAAO,EAAE;EAC7B,IAAA;MAEA,KAAK,CAACA,OAAO,EAAE;EACjB,EAAA;;EAEA;IACAlB,iBAAiBA,CAACF,MAAM,EAAE;EACxBA,IAAAA,MAAM,CAACsK,eAAe,GAAGtK,MAAM,CAACyI,QAAQ;EACxC,IAAA,OAAOzI,MAAM;EACf,EAAA;EAEAsJ,EAAAA,kBAAkBA,GAAG;EACnB,IAAA,IAAI,IAAI,CAACrI,OAAO,CAACyH,QAAQ,EAAE;EACzB5N,MAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAEsG,eAAa,EAAE5M,KAAK,IAAI,IAAI,CAAC6P,QAAQ,CAAC7P,KAAK,CAAC,CAAC;EAC9E,IAAA;EAEA,IAAA,IAAI,IAAI,CAACuG,OAAO,CAAC0H,KAAK,KAAK,OAAO,EAAE;EAClC7N,MAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAEuG,kBAAgB,EAAE,MAAM,IAAI,CAACoB,KAAK,EAAE,CAAC;EACpE7N,MAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAEwG,kBAAgB,EAAE,MAAM,IAAI,CAACsC,iBAAiB,EAAE,CAAC;EAClF,IAAA;MAEA,IAAI,IAAI,CAAC7I,OAAO,CAAC4H,KAAK,IAAIpD,KAAK,CAACC,WAAW,EAAE,EAAE;QAC7C,IAAI,CAAC8E,uBAAuB,EAAE;EAChC,IAAA;EACF,EAAA;EAEAA,EAAAA,uBAAuBA,GAAG;EACxB,IAAA,KAAK,MAAMC,GAAG,IAAItI,cAAc,CAACxG,IAAI,CAACyM,iBAAiB,EAAE,IAAI,CAACpH,QAAQ,CAAC,EAAE;EACvElG,MAAAA,YAAY,CAACiC,EAAE,CAAC0N,GAAG,EAAEhD,gBAAgB,EAAE/M,KAAK,IAAIA,KAAK,CAACuD,cAAc,EAAE,CAAC;EACzE,IAAA;MAEA,MAAMyM,WAAW,GAAGA,MAAM;EACxB,MAAA,IAAI,IAAI,CAACzJ,OAAO,CAAC0H,KAAK,KAAK,OAAO,EAAE;EAClC,QAAA;EACF,MAAA;;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;;QAEA,IAAI,CAACA,KAAK,EAAE;QACZ,IAAI,IAAI,CAACQ,YAAY,EAAE;EACrBwB,QAAAA,YAAY,CAAC,IAAI,CAACxB,YAAY,CAAC;EACjC,MAAA;EAEA,MAAA,IAAI,CAACA,YAAY,GAAGlQ,UAAU,CAAC,MAAM,IAAI,CAAC6Q,iBAAiB,EAAE,EAAE/C,sBAAsB,GAAG,IAAI,CAAC9F,OAAO,CAACwH,QAAQ,CAAC;MAChH,CAAC;EAED,IAAA,MAAMmC,WAAW,GAAG;EAClBrF,MAAAA,YAAY,EAAEA,MAAM,IAAI,CAACiE,MAAM,CAAC,IAAI,CAACqB,iBAAiB,CAAC3D,cAAc,CAAC,CAAC;EACvE1B,MAAAA,aAAa,EAAEA,MAAM,IAAI,CAACgE,MAAM,CAAC,IAAI,CAACqB,iBAAiB,CAAC1D,eAAe,CAAC,CAAC;EACzE7B,MAAAA,WAAW,EAAEoF;OACd;MAED,IAAI,CAACtB,YAAY,GAAG,IAAI3D,KAAK,CAAC,IAAI,CAACzE,QAAQ,EAAE4J,WAAW,CAAC;EAC3D,EAAA;IAEAL,QAAQA,CAAC7P,KAAK,EAAE;MACd,IAAI,iBAAiB,CAACiG,IAAI,CAACjG,KAAK,CAAC3B,MAAM,CAAC4K,OAAO,CAAC,EAAE;EAChD,MAAA;EACF,IAAA;EAEA,IAAA,MAAM6C,SAAS,GAAGgC,gBAAgB,CAAC9N,KAAK,CAAC7I,GAAG,CAAC;EAC7C,IAAA,IAAI2U,SAAS,EAAE;QACb9L,KAAK,CAACuD,cAAc,EAAE;QACtB,IAAI,CAACuL,MAAM,CAAC,IAAI,CAACqB,iBAAiB,CAACrE,SAAS,CAAC,CAAC;EAChD,IAAA;EACF,EAAA;IAEA2D,aAAaA,CAACvY,OAAO,EAAE;MACrB,OAAO,IAAI,CAACqY,SAAS,EAAE,CAACxQ,OAAO,CAAC7H,OAAO,CAAC;EAC1C,EAAA;IAEAkZ,0BAA0BA,CAACtR,KAAK,EAAE;EAChC,IAAA,IAAI,CAAC,IAAI,CAAC6P,kBAAkB,EAAE;EAC5B,MAAA;EACF,IAAA;MAEA,MAAM0B,eAAe,GAAG5I,cAAc,CAACG,OAAO,CAAC2F,eAAe,EAAE,IAAI,CAACoB,kBAAkB,CAAC;EAExF0B,IAAAA,eAAe,CAAC9U,SAAS,CAACzD,MAAM,CAAC+R,mBAAiB,CAAC;EACnDwG,IAAAA,eAAe,CAAC7L,eAAe,CAAC,cAAc,CAAC;EAE/C,IAAA,MAAM8L,kBAAkB,GAAG7I,cAAc,CAACG,OAAO,CAAC,CAAA,mBAAA,EAAsB9I,KAAK,CAAA,EAAA,CAAI,EAAE,IAAI,CAAC6P,kBAAkB,CAAC;EAE3G,IAAA,IAAI2B,kBAAkB,EAAE;EACtBA,MAAAA,kBAAkB,CAAC/U,SAAS,CAACwQ,GAAG,CAAClC,mBAAiB,CAAC;EACnDyG,MAAAA,kBAAkB,CAAChM,YAAY,CAAC,cAAc,EAAE,MAAM,CAAC;EACzD,IAAA;EACF,EAAA;EAEA4K,EAAAA,eAAeA,GAAG;MAChB,MAAMhY,OAAO,GAAG,IAAI,CAACqX,cAAc,IAAI,IAAI,CAACmB,UAAU,EAAE;MAExD,IAAI,CAACxY,OAAO,EAAE;EACZ,MAAA;EACF,IAAA;EAEA,IAAA,MAAMqZ,eAAe,GAAGxW,MAAM,CAACyW,QAAQ,CAACtZ,OAAO,CAACyE,YAAY,CAAC,kBAAkB,CAAC,EAAE,EAAE,CAAC;MAErF,IAAI,CAAC4K,OAAO,CAACwH,QAAQ,GAAGwC,eAAe,IAAI,IAAI,CAAChK,OAAO,CAACqJ,eAAe;EACzE,EAAA;EAEAd,EAAAA,MAAMA,CAACa,KAAK,EAAEzY,OAAO,GAAG,IAAI,EAAE;MAC5B,IAAI,IAAI,CAACsX,UAAU,EAAE;EACnB,MAAA;EACF,IAAA;EAEA,IAAA,MAAM9P,aAAa,GAAG,IAAI,CAACgR,UAAU,EAAE;EACvC,IAAA,MAAMe,MAAM,GAAGd,KAAK,KAAKrD,UAAU;MACnC,MAAMoE,WAAW,GAAGxZ,OAAO,IAAIsH,oBAAoB,CAAC,IAAI,CAAC+Q,SAAS,EAAE,EAAE7Q,aAAa,EAAE+R,MAAM,EAAE,IAAI,CAAClK,OAAO,CAAC6H,IAAI,CAAC;MAE/G,IAAIsC,WAAW,KAAKhS,aAAa,EAAE;EACjC,MAAA;EACF,IAAA;EAEA,IAAA,MAAMiS,gBAAgB,GAAG,IAAI,CAAClB,aAAa,CAACiB,WAAW,CAAC;MAExD,MAAME,YAAY,GAAG1J,SAAS,IAAI;QAChC,OAAO9G,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEY,SAAS,EAAE;EACpDxF,QAAAA,aAAa,EAAEgP,WAAW;EAC1B5E,QAAAA,SAAS,EAAE,IAAI,CAAC+E,iBAAiB,CAAClB,KAAK,CAAC;EACxC/X,QAAAA,IAAI,EAAE,IAAI,CAAC6X,aAAa,CAAC/Q,aAAa,CAAC;EACvC2Q,QAAAA,EAAE,EAAEsB;EACN,OAAC,CAAC;MACJ,CAAC;EAED,IAAA,MAAMG,UAAU,GAAGF,YAAY,CAAClE,WAAW,CAAC;MAE5C,IAAIoE,UAAU,CAAC7N,gBAAgB,EAAE;EAC/B,MAAA;EACF,IAAA;EAEA,IAAA,IAAI,CAACvE,aAAa,IAAI,CAACgS,WAAW,EAAE;EAClC;EACA;EACA,MAAA;EACF,IAAA;EAEA,IAAA,MAAMK,SAAS,GAAGjP,OAAO,CAAC,IAAI,CAACwM,SAAS,CAAC;MACzC,IAAI,CAACL,KAAK,EAAE;MAEZ,IAAI,CAACO,UAAU,GAAG,IAAI;EAEtB,IAAA,IAAI,CAAC4B,0BAA0B,CAACO,gBAAgB,CAAC;MACjD,IAAI,CAACpC,cAAc,GAAGmC,WAAW;EAEjC,IAAA,MAAMM,oBAAoB,GAAGP,MAAM,GAAGrD,gBAAgB,GAAGD,cAAc;EACvE,IAAA,MAAM8D,cAAc,GAAGR,MAAM,GAAGpD,eAAe,GAAGC,eAAe;EAEjEoD,IAAAA,WAAW,CAACnV,SAAS,CAACwQ,GAAG,CAACkF,cAAc,CAAC;MAEzC9U,MAAM,CAACuU,WAAW,CAAC;EAEnBhS,IAAAA,aAAa,CAACnD,SAAS,CAACwQ,GAAG,CAACiF,oBAAoB,CAAC;EACjDN,IAAAA,WAAW,CAACnV,SAAS,CAACwQ,GAAG,CAACiF,oBAAoB,CAAC;MAE/C,MAAME,gBAAgB,GAAGA,MAAM;QAC7BR,WAAW,CAACnV,SAAS,CAACzD,MAAM,CAACkZ,oBAAoB,EAAEC,cAAc,CAAC;EAClEP,MAAAA,WAAW,CAACnV,SAAS,CAACwQ,GAAG,CAAClC,mBAAiB,CAAC;QAE5CnL,aAAa,CAACnD,SAAS,CAACzD,MAAM,CAAC+R,mBAAiB,EAAEoH,cAAc,EAAED,oBAAoB,CAAC;QAEvF,IAAI,CAACxC,UAAU,GAAG,KAAK;QAEvBoC,YAAY,CAACjE,UAAU,CAAC;MAC1B,CAAC;EAED,IAAA,IAAI,CAAC7F,cAAc,CAACoK,gBAAgB,EAAExS,aAAa,EAAE,IAAI,CAACyS,WAAW,EAAE,CAAC;EAExE,IAAA,IAAIJ,SAAS,EAAE;QACb,IAAI,CAAClC,KAAK,EAAE;EACd,IAAA;EACF,EAAA;EAEAsC,EAAAA,WAAWA,GAAG;MACZ,OAAO,IAAI,CAAC7K,QAAQ,CAAC/K,SAAS,CAACC,QAAQ,CAAC0R,gBAAgB,CAAC;EAC3D,EAAA;EAEAwC,EAAAA,UAAUA,GAAG;MACX,OAAOjI,cAAc,CAACG,OAAO,CAAC6F,oBAAoB,EAAE,IAAI,CAACnH,QAAQ,CAAC;EACpE,EAAA;EAEAiJ,EAAAA,SAASA,GAAG;MACV,OAAO9H,cAAc,CAACxG,IAAI,CAACuM,aAAa,EAAE,IAAI,CAAClH,QAAQ,CAAC;EAC1D,EAAA;EAEA2I,EAAAA,cAAcA,GAAG;MACf,IAAI,IAAI,CAACX,SAAS,EAAE;EAClB8C,MAAAA,aAAa,CAAC,IAAI,CAAC9C,SAAS,CAAC;QAC7B,IAAI,CAACA,SAAS,GAAG,IAAI;EACvB,IAAA;EACF,EAAA;IAEA6B,iBAAiBA,CAACrE,SAAS,EAAE;MAC3B,IAAIhP,KAAK,EAAE,EAAE;EACX,MAAA,OAAOgP,SAAS,KAAKU,cAAc,GAAGD,UAAU,GAAGD,UAAU;EAC/D,IAAA;EAEA,IAAA,OAAOR,SAAS,KAAKU,cAAc,GAAGF,UAAU,GAAGC,UAAU;EAC/D,EAAA;IAEAsE,iBAAiBA,CAAClB,KAAK,EAAE;MACvB,IAAI7S,KAAK,EAAE,EAAE;EACX,MAAA,OAAO6S,KAAK,KAAKpD,UAAU,GAAGC,cAAc,GAAGC,eAAe;EAChE,IAAA;EAEA,IAAA,OAAOkD,KAAK,KAAKpD,UAAU,GAAGE,eAAe,GAAGD,cAAc;EAChE,EAAA;;EAEA;IACA,OAAOjP,eAAeA,CAAC+H,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACoE,IAAI,CAAC,YAAY;QAC3B,MAAMC,IAAI,GAAG0E,QAAQ,CAACpH,mBAAmB,CAAC,IAAI,EAAE3B,MAAM,CAAC;EAEvD,MAAA,IAAI,OAAOA,MAAM,KAAK,QAAQ,EAAE;EAC9BqE,QAAAA,IAAI,CAAC0F,EAAE,CAAC/J,MAAM,CAAC;EACf,QAAA;EACF,MAAA;EAEA,MAAA,IAAI,OAAOA,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA,IAAIqE,IAAI,CAACrE,MAAM,CAAC,KAAKzM,SAAS,IAAIyM,MAAM,CAAC7C,UAAU,CAAC,GAAG,CAAC,IAAI6C,MAAM,KAAK,aAAa,EAAE;EACpF,UAAA,MAAM,IAAIY,SAAS,CAAC,CAAA,iBAAA,EAAoBZ,MAAM,GAAG,CAAC;EACpD,QAAA;EAEAqE,QAAAA,IAAI,CAACrE,MAAM,CAAC,EAAE;EAChB,MAAA;EACF,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAlF,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAEuQ,sBAAoB,EAAE6D,mBAAmB,EAAE,UAAU5N,KAAK,EAAE;EACpF,EAAA,MAAM3B,MAAM,GAAGoJ,cAAc,CAACkB,sBAAsB,CAAC,IAAI,CAAC;EAE1D,EAAA,IAAI,CAACtK,MAAM,IAAI,CAACA,MAAM,CAAC9C,SAAS,CAACC,QAAQ,CAACyR,mBAAmB,CAAC,EAAE;EAC9D,IAAA;EACF,EAAA;IAEAjN,KAAK,CAACuD,cAAc,EAAE;EAEtB,EAAA,MAAM8N,QAAQ,GAAGhD,QAAQ,CAACpH,mBAAmB,CAAC5I,MAAM,CAAC;EACrD,EAAA,MAAMiT,UAAU,GAAG,IAAI,CAAC3V,YAAY,CAAC,kBAAkB,CAAC;EAExD,EAAA,IAAI2V,UAAU,EAAE;EACdD,IAAAA,QAAQ,CAAChC,EAAE,CAACiC,UAAU,CAAC;MACvBD,QAAQ,CAACjC,iBAAiB,EAAE;EAC5B,IAAA;EACF,EAAA;IAEA,IAAIhL,WAAW,CAACY,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,KAAK,MAAM,EAAE;MAC1DqM,QAAQ,CAAChJ,IAAI,EAAE;MACfgJ,QAAQ,CAACjC,iBAAiB,EAAE;EAC5B,IAAA;EACF,EAAA;IAEAiC,QAAQ,CAACnJ,IAAI,EAAE;IACfmJ,QAAQ,CAACjC,iBAAiB,EAAE;EAC9B,CAAC,CAAC;EAEFhP,YAAY,CAACiC,EAAE,CAAChK,MAAM,EAAE2U,qBAAmB,EAAE,MAAM;EACjD,EAAA,MAAMuE,SAAS,GAAG9J,cAAc,CAACxG,IAAI,CAAC4M,kBAAkB,CAAC;EAEzD,EAAA,KAAK,MAAMwD,QAAQ,IAAIE,SAAS,EAAE;EAChClD,IAAAA,QAAQ,CAACpH,mBAAmB,CAACoK,QAAQ,CAAC;EACxC,EAAA;EACF,CAAC,CAAC;;EAEF;EACA;EACA;;EAEArU,kBAAkB,CAACqR,QAAQ,CAAC;;ECvd5B;EACA;EACA;EACA;EACA;EACA;;;EAWA;EACA;EACA;;EAEA,MAAMjR,MAAI,GAAG,UAAU;EACvB,MAAMqJ,UAAQ,GAAG,aAAa;EAC9B,MAAME,WAAS,GAAG,CAAA,CAAA,EAAIF,UAAQ,CAAA,CAAE;EAChC,MAAMmD,cAAY,GAAG,WAAW;EAEhC,MAAM4H,YAAU,GAAG,CAAA,IAAA,EAAO7K,WAAS,CAAA,CAAE;EACrC,MAAM8K,aAAW,GAAG,CAAA,KAAA,EAAQ9K,WAAS,CAAA,CAAE;EACvC,MAAM+K,YAAU,GAAG,CAAA,IAAA,EAAO/K,WAAS,CAAA,CAAE;EACrC,MAAMgL,cAAY,GAAG,CAAA,MAAA,EAAShL,WAAS,CAAA,CAAE;EACzC,MAAMoD,sBAAoB,GAAG,CAAA,KAAA,EAAQpD,WAAS,CAAA,EAAGiD,cAAY,CAAA,CAAE;EAE/D,MAAMP,iBAAe,GAAG,MAAM;EAC9B,MAAMuI,mBAAmB,GAAG,UAAU;EACtC,MAAMC,qBAAqB,GAAG,YAAY;EAC1C,MAAMC,oBAAoB,GAAG,WAAW;EACxC,MAAMC,0BAA0B,GAAG,CAAA,QAAA,EAAWH,mBAAmB,CAAA,EAAA,EAAKA,mBAAmB,CAAA,CAAE;EAC3F,MAAMI,qBAAqB,GAAG,qBAAqB;EAEnD,MAAMC,KAAK,GAAG,OAAO;EACrB,MAAMC,MAAM,GAAG,QAAQ;EAEvB,MAAMC,gBAAgB,GAAG,sCAAsC;EAC/D,MAAMrI,sBAAoB,GAAG,6BAA6B;EAE1D,MAAM5E,SAAO,GAAG;EACdkN,EAAAA,MAAM,EAAE,IAAI;EACZnI,EAAAA,MAAM,EAAE;EACV,CAAC;EAED,MAAM9E,aAAW,GAAG;EAClBiN,EAAAA,MAAM,EAAE,gBAAgB;EACxBnI,EAAAA,MAAM,EAAE;EACV,CAAC;;EAED;EACA;EACA;;EAEA,MAAMoI,QAAQ,SAAShM,aAAa,CAAC;EACnCV,EAAAA,WAAWA,CAACzO,OAAO,EAAEoO,MAAM,EAAE;EAC3B,IAAA,KAAK,CAACpO,OAAO,EAAEoO,MAAM,CAAC;MAEtB,IAAI,CAACgN,gBAAgB,GAAG,KAAK;MAC7B,IAAI,CAACC,aAAa,GAAG,EAAE;EAEvB,IAAA,MAAMC,UAAU,GAAG/K,cAAc,CAACxG,IAAI,CAAC6I,sBAAoB,CAAC;EAE5D,IAAA,KAAK,MAAM2I,IAAI,IAAID,UAAU,EAAE;EAC7B,MAAA,MAAMpa,QAAQ,GAAGqP,cAAc,CAACiB,sBAAsB,CAAC+J,IAAI,CAAC;EAC5D,MAAA,MAAMC,aAAa,GAAGjL,cAAc,CAACxG,IAAI,CAAC7I,QAAQ,CAAC,CAChDyM,MAAM,CAAC8N,YAAY,IAAIA,YAAY,KAAK,IAAI,CAACrM,QAAQ,CAAC;EAEzD,MAAA,IAAIlO,QAAQ,KAAK,IAAI,IAAIsa,aAAa,CAAChY,MAAM,EAAE;EAC7C,QAAA,IAAI,CAAC6X,aAAa,CAAC1V,IAAI,CAAC4V,IAAI,CAAC;EAC/B,MAAA;EACF,IAAA;MAEA,IAAI,CAACG,mBAAmB,EAAE;EAE1B,IAAA,IAAI,CAAC,IAAI,CAACrM,OAAO,CAAC6L,MAAM,EAAE;EACxB,MAAA,IAAI,CAACS,yBAAyB,CAAC,IAAI,CAACN,aAAa,EAAE,IAAI,CAACO,QAAQ,EAAE,CAAC;EACrE,IAAA;EAEA,IAAA,IAAI,IAAI,CAACvM,OAAO,CAAC0D,MAAM,EAAE;QACvB,IAAI,CAACA,MAAM,EAAE;EACf,IAAA;EACF,EAAA;;EAEA;IACA,WAAW/E,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACA6M,EAAAA,MAAMA,GAAG;EACP,IAAA,IAAI,IAAI,CAAC6I,QAAQ,EAAE,EAAE;QACnB,IAAI,CAACC,IAAI,EAAE;EACb,IAAA,CAAC,MAAM;QACL,IAAI,CAACC,IAAI,EAAE;EACb,IAAA;EACF,EAAA;EAEAA,EAAAA,IAAIA,GAAG;MACL,IAAI,IAAI,CAACV,gBAAgB,IAAI,IAAI,CAACQ,QAAQ,EAAE,EAAE;EAC5C,MAAA;EACF,IAAA;MAEA,IAAIG,cAAc,GAAG,EAAE;;EAEvB;EACA,IAAA,IAAI,IAAI,CAAC1M,OAAO,CAAC6L,MAAM,EAAE;EACvBa,MAAAA,cAAc,GAAG,IAAI,CAACC,sBAAsB,CAACf,gBAAgB,CAAC,CAC3DtN,MAAM,CAAC3N,OAAO,IAAIA,OAAO,KAAK,IAAI,CAACoP,QAAQ,CAAC,CAC5CgB,GAAG,CAACpQ,OAAO,IAAImb,QAAQ,CAACpL,mBAAmB,CAAC/P,OAAO,EAAE;EAAE+S,QAAAA,MAAM,EAAE;EAAM,OAAC,CAAC,CAAC;EAC7E,IAAA;MAEA,IAAIgJ,cAAc,CAACvY,MAAM,IAAIuY,cAAc,CAAC,CAAC,CAAC,CAACX,gBAAgB,EAAE;EAC/D,MAAA;EACF,IAAA;MAEA,MAAMa,UAAU,GAAG/S,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEkL,YAAU,CAAC;MAClE,IAAI2B,UAAU,CAAClQ,gBAAgB,EAAE;EAC/B,MAAA;EACF,IAAA;EAEA,IAAA,KAAK,MAAMmQ,cAAc,IAAIH,cAAc,EAAE;QAC3CG,cAAc,CAACL,IAAI,EAAE;EACvB,IAAA;EAEA,IAAA,MAAMM,SAAS,GAAG,IAAI,CAACC,aAAa,EAAE;MAEtC,IAAI,CAAChN,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAAC8Z,mBAAmB,CAAC;MACnD,IAAI,CAACtL,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAAC8F,qBAAqB,CAAC;MAElD,IAAI,CAACvL,QAAQ,CAACiN,KAAK,CAACF,SAAS,CAAC,GAAG,CAAC;MAElC,IAAI,CAACR,yBAAyB,CAAC,IAAI,CAACN,aAAa,EAAE,IAAI,CAAC;MACxD,IAAI,CAACD,gBAAgB,GAAG,IAAI;MAE5B,MAAMkB,QAAQ,GAAGA,MAAM;QACrB,IAAI,CAAClB,gBAAgB,GAAG,KAAK;QAE7B,IAAI,CAAChM,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAAC+Z,qBAAqB,CAAC;QACrD,IAAI,CAACvL,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAAC6F,mBAAmB,EAAEvI,iBAAe,CAAC;QAEjE,IAAI,CAAC/C,QAAQ,CAACiN,KAAK,CAACF,SAAS,CAAC,GAAG,EAAE;QAEnCjT,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEmL,aAAW,CAAC;MAClD,CAAC;EAED,IAAA,MAAMgC,oBAAoB,GAAGJ,SAAS,CAAC,CAAC,CAAC,CAAClN,WAAW,EAAE,GAAGkN,SAAS,CAAC1Q,KAAK,CAAC,CAAC,CAAC;EAC5E,IAAA,MAAM+Q,UAAU,GAAG,CAAA,MAAA,EAASD,oBAAoB,CAAA,CAAE;MAElD,IAAI,CAAC3M,cAAc,CAAC0M,QAAQ,EAAE,IAAI,CAAClN,QAAQ,EAAE,IAAI,CAAC;EAClD,IAAA,IAAI,CAACA,QAAQ,CAACiN,KAAK,CAACF,SAAS,CAAC,GAAG,CAAA,EAAG,IAAI,CAAC/M,QAAQ,CAACoN,UAAU,CAAC,CAAA,EAAA,CAAI;EACnE,EAAA;EAEAX,EAAAA,IAAIA,GAAG;MACL,IAAI,IAAI,CAACT,gBAAgB,IAAI,CAAC,IAAI,CAACQ,QAAQ,EAAE,EAAE;EAC7C,MAAA;EACF,IAAA;MAEA,MAAMK,UAAU,GAAG/S,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEoL,YAAU,CAAC;MAClE,IAAIyB,UAAU,CAAClQ,gBAAgB,EAAE;EAC/B,MAAA;EACF,IAAA;EAEA,IAAA,MAAMoQ,SAAS,GAAG,IAAI,CAACC,aAAa,EAAE;EAEtC,IAAA,IAAI,CAAChN,QAAQ,CAACiN,KAAK,CAACF,SAAS,CAAC,GAAG,CAAA,EAAG,IAAI,CAAC/M,QAAQ,CAACqN,qBAAqB,EAAE,CAACN,SAAS,CAAC,CAAA,EAAA,CAAI;EAExFlX,IAAAA,MAAM,CAAC,IAAI,CAACmK,QAAQ,CAAC;MAErB,IAAI,CAACA,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAAC8F,qBAAqB,CAAC;MAClD,IAAI,CAACvL,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAAC8Z,mBAAmB,EAAEvI,iBAAe,CAAC;EAEpE,IAAA,KAAK,MAAMxG,OAAO,IAAI,IAAI,CAAC0P,aAAa,EAAE;EACxC,MAAA,MAAMrb,OAAO,GAAGuQ,cAAc,CAACkB,sBAAsB,CAAC9F,OAAO,CAAC;QAE9D,IAAI3L,OAAO,IAAI,CAAC,IAAI,CAAC4b,QAAQ,CAAC5b,OAAO,CAAC,EAAE;UACtC,IAAI,CAAC2b,yBAAyB,CAAC,CAAChQ,OAAO,CAAC,EAAE,KAAK,CAAC;EAClD,MAAA;EACF,IAAA;MAEA,IAAI,CAACyP,gBAAgB,GAAG,IAAI;MAE5B,MAAMkB,QAAQ,GAAGA,MAAM;QACrB,IAAI,CAAClB,gBAAgB,GAAG,KAAK;QAC7B,IAAI,CAAChM,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAAC+Z,qBAAqB,CAAC;QACrD,IAAI,CAACvL,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAAC6F,mBAAmB,CAAC;QAChDxR,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEqL,cAAY,CAAC;MACnD,CAAC;MAED,IAAI,CAACrL,QAAQ,CAACiN,KAAK,CAACF,SAAS,CAAC,GAAG,EAAE;MAEnC,IAAI,CAACvM,cAAc,CAAC0M,QAAQ,EAAE,IAAI,CAAClN,QAAQ,EAAE,IAAI,CAAC;EACpD,EAAA;;EAEA;EACAwM,EAAAA,QAAQA,CAAC5b,OAAO,GAAG,IAAI,CAACoP,QAAQ,EAAE;EAChC,IAAA,OAAOpP,OAAO,CAACqE,SAAS,CAACC,QAAQ,CAAC6N,iBAAe,CAAC;EACpD,EAAA;IAEA7D,iBAAiBA,CAACF,MAAM,EAAE;MACxBA,MAAM,CAAC2E,MAAM,GAAGnI,OAAO,CAACwD,MAAM,CAAC2E,MAAM,CAAC,CAAA;MACtC3E,MAAM,CAAC8M,MAAM,GAAG3X,UAAU,CAAC6K,MAAM,CAAC8M,MAAM,CAAC;EACzC,IAAA,OAAO9M,MAAM;EACf,EAAA;EAEAgO,EAAAA,aAAaA,GAAG;EACd,IAAA,OAAO,IAAI,CAAChN,QAAQ,CAAC/K,SAAS,CAACC,QAAQ,CAACwW,qBAAqB,CAAC,GAAGC,KAAK,GAAGC,MAAM;EACjF,EAAA;EAEAU,EAAAA,mBAAmBA,GAAG;EACpB,IAAA,IAAI,CAAC,IAAI,CAACrM,OAAO,CAAC6L,MAAM,EAAE;EACxB,MAAA;EACF,IAAA;EAEA,IAAA,MAAMvK,QAAQ,GAAG,IAAI,CAACqL,sBAAsB,CAACpJ,sBAAoB,CAAC;EAElE,IAAA,KAAK,MAAM5S,OAAO,IAAI2Q,QAAQ,EAAE;EAC9B,MAAA,MAAM+L,QAAQ,GAAGnM,cAAc,CAACkB,sBAAsB,CAACzR,OAAO,CAAC;EAE/D,MAAA,IAAI0c,QAAQ,EAAE;EACZ,QAAA,IAAI,CAACf,yBAAyB,CAAC,CAAC3b,OAAO,CAAC,EAAE,IAAI,CAAC4b,QAAQ,CAACc,QAAQ,CAAC,CAAC;EACpE,MAAA;EACF,IAAA;EACF,EAAA;IAEAV,sBAAsBA,CAAC9a,QAAQ,EAAE;EAC/B,IAAA,MAAMyP,QAAQ,GAAGJ,cAAc,CAACxG,IAAI,CAAC8Q,0BAA0B,EAAE,IAAI,CAACxL,OAAO,CAAC6L,MAAM,CAAC;EACrF;MACA,OAAO3K,cAAc,CAACxG,IAAI,CAAC7I,QAAQ,EAAE,IAAI,CAACmO,OAAO,CAAC6L,MAAM,CAAC,CAACvN,MAAM,CAAC3N,OAAO,IAAI,CAAC2Q,QAAQ,CAACzF,QAAQ,CAAClL,OAAO,CAAC,CAAC;EAC1G,EAAA;EAEA2b,EAAAA,yBAAyBA,CAACgB,YAAY,EAAEC,MAAM,EAAE;EAC9C,IAAA,IAAI,CAACD,YAAY,CAACnZ,MAAM,EAAE;EACxB,MAAA;EACF,IAAA;EAEA,IAAA,KAAK,MAAMxD,OAAO,IAAI2c,YAAY,EAAE;QAClC3c,OAAO,CAACqE,SAAS,CAAC0O,MAAM,CAAC6H,oBAAoB,EAAE,CAACgC,MAAM,CAAC;EACvD5c,MAAAA,OAAO,CAACoN,YAAY,CAAC,eAAe,EAAEwP,MAAM,CAAC;EAC/C,IAAA;EACF,EAAA;;EAEA;IACA,OAAOvW,eAAeA,CAAC+H,MAAM,EAAE;MAC7B,MAAMiB,OAAO,GAAG,EAAE;MAClB,IAAI,OAAOjB,MAAM,KAAK,QAAQ,IAAI,WAAW,CAACW,IAAI,CAACX,MAAM,CAAC,EAAE;QAC1DiB,OAAO,CAAC0D,MAAM,GAAG,KAAK;EACxB,IAAA;EAEA,IAAA,OAAO,IAAI,CAACP,IAAI,CAAC,YAAY;QAC3B,MAAMC,IAAI,GAAG0I,QAAQ,CAACpL,mBAAmB,CAAC,IAAI,EAAEV,OAAO,CAAC;EAExD,MAAA,IAAI,OAAOjB,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA,IAAI,OAAOqE,IAAI,CAACrE,MAAM,CAAC,KAAK,WAAW,EAAE;EACvC,UAAA,MAAM,IAAIY,SAAS,CAAC,CAAA,iBAAA,EAAoBZ,MAAM,GAAG,CAAC;EACpD,QAAA;EAEAqE,QAAAA,IAAI,CAACrE,MAAM,CAAC,EAAE;EAChB,MAAA;EACF,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAlF,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAEuQ,sBAAoB,EAAED,sBAAoB,EAAE,UAAU9J,KAAK,EAAE;EACrF;EACA,EAAA,IAAIA,KAAK,CAAC3B,MAAM,CAAC4K,OAAO,KAAK,GAAG,IAAKjJ,KAAK,CAACE,cAAc,IAAIF,KAAK,CAACE,cAAc,CAAC+I,OAAO,KAAK,GAAI,EAAE;MAClGjJ,KAAK,CAACuD,cAAc,EAAE;EACxB,EAAA;IAEA,KAAK,MAAMrM,OAAO,IAAIuQ,cAAc,CAACmB,+BAA+B,CAAC,IAAI,CAAC,EAAE;EAC1EyJ,IAAAA,QAAQ,CAACpL,mBAAmB,CAAC/P,OAAO,EAAE;EAAE+S,MAAAA,MAAM,EAAE;EAAM,KAAC,CAAC,CAACA,MAAM,EAAE;EACnE,EAAA;EACF,CAAC,CAAC;;EAEF;EACA;EACA;;EAEAjN,kBAAkB,CAACqV,QAAQ,CAAC;;ECtS5B;EACA;EACA;EACA;EACA;EACA;;;EAmBA;EACA;EACA;;EAEA,MAAMjV,MAAI,GAAG,UAAU;EACvB,MAAMqJ,UAAQ,GAAG,aAAa;EAC9B,MAAME,WAAS,GAAG,CAAA,CAAA,EAAIF,UAAQ,CAAA,CAAE;EAChC,MAAMmD,cAAY,GAAG,WAAW;EAEhC,MAAMmK,YAAU,GAAG,QAAQ;EAC3B,MAAMC,SAAO,GAAG,KAAK;EACrB,MAAMC,cAAY,GAAG,SAAS;EAC9B,MAAMC,gBAAc,GAAG,WAAW;EAClC,MAAMC,kBAAkB,GAAG,CAAC,CAAA;;EAE5B,MAAMzC,YAAU,GAAG,CAAA,IAAA,EAAO/K,WAAS,CAAA,CAAE;EACrC,MAAMgL,cAAY,GAAG,CAAA,MAAA,EAAShL,WAAS,CAAA,CAAE;EACzC,MAAM6K,YAAU,GAAG,CAAA,IAAA,EAAO7K,WAAS,CAAA,CAAE;EACrC,MAAM8K,aAAW,GAAG,CAAA,KAAA,EAAQ9K,WAAS,CAAA,CAAE;EACvC,MAAMoD,sBAAoB,GAAG,CAAA,KAAA,EAAQpD,WAAS,CAAA,EAAGiD,cAAY,CAAA,CAAE;EAC/D,MAAMwK,sBAAsB,GAAG,CAAA,OAAA,EAAUzN,WAAS,CAAA,EAAGiD,cAAY,CAAA,CAAE;EACnE,MAAMyK,oBAAoB,GAAG,CAAA,KAAA,EAAQ1N,WAAS,CAAA,EAAGiD,cAAY,CAAA,CAAE;EAE/D,MAAMP,iBAAe,GAAG,MAAM;EAC9B,MAAMiL,iBAAiB,GAAG,QAAQ;EAClC,MAAMC,kBAAkB,GAAG,SAAS;EACpC,MAAMC,oBAAoB,GAAG,WAAW;EACxC,MAAMC,wBAAwB,GAAG,eAAe;EAChD,MAAMC,0BAA0B,GAAG,iBAAiB;EAEpD,MAAM5K,sBAAoB,GAAG,2DAA2D;EACxF,MAAM6K,0BAA0B,GAAG,CAAA,EAAG7K,sBAAoB,CAAA,CAAA,EAAIT,iBAAe,CAAA,CAAE;EAC/E,MAAMuL,aAAa,GAAG,gBAAgB;EACtC,MAAMC,eAAe,GAAG,SAAS;EACjC,MAAMC,mBAAmB,GAAG,aAAa;EACzC,MAAMC,sBAAsB,GAAG,6DAA6D;EAE5F,MAAMC,aAAa,GAAGlY,KAAK,EAAE,GAAG,SAAS,GAAG,WAAW;EACvD,MAAMmY,gBAAgB,GAAGnY,KAAK,EAAE,GAAG,WAAW,GAAG,SAAS;EAC1D,MAAMoY,gBAAgB,GAAGpY,KAAK,EAAE,GAAG,YAAY,GAAG,cAAc;EAChE,MAAMqY,mBAAmB,GAAGrY,KAAK,EAAE,GAAG,cAAc,GAAG,YAAY;EACnE,MAAMsY,eAAe,GAAGtY,KAAK,EAAE,GAAG,YAAY,GAAG,aAAa;EAC9D,MAAMuY,cAAc,GAAGvY,KAAK,EAAE,GAAG,aAAa,GAAG,YAAY;EAC7D,MAAMwY,mBAAmB,GAAG,KAAK;EACjC,MAAMC,sBAAsB,GAAG,QAAQ;EAEvC,MAAMrQ,SAAO,GAAG;EACdsQ,EAAAA,SAAS,EAAE,IAAI;EACfC,EAAAA,QAAQ,EAAE,iBAAiB;EAC3BC,EAAAA,OAAO,EAAE,SAAS;EAClBC,EAAAA,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;EACdC,EAAAA,YAAY,EAAE,IAAI;EAClBC,EAAAA,SAAS,EAAE;EACb,CAAC;EAED,MAAM1Q,aAAW,GAAG;EAClBqQ,EAAAA,SAAS,EAAE,kBAAkB;EAC7BC,EAAAA,QAAQ,EAAE,kBAAkB;EAC5BC,EAAAA,OAAO,EAAE,QAAQ;EACjBC,EAAAA,MAAM,EAAE,yBAAyB;EACjCC,EAAAA,YAAY,EAAE,wBAAwB;EACtCC,EAAAA,SAAS,EAAE;EACb,CAAC;;EAED;EACA;EACA;;EAEA,MAAMC,QAAQ,SAASzP,aAAa,CAAC;EACnCV,EAAAA,WAAWA,CAACzO,OAAO,EAAEoO,MAAM,EAAE;EAC3B,IAAA,KAAK,CAACpO,OAAO,EAAEoO,MAAM,CAAC;MAEtB,IAAI,CAACyQ,OAAO,GAAG,IAAI;MACnB,IAAI,CAACC,OAAO,GAAG,IAAI,CAAC1P,QAAQ,CAACnL,UAAU,CAAA;EACvC;EACA,IAAA,IAAI,CAAC8a,KAAK,GAAGxO,cAAc,CAACY,IAAI,CAAC,IAAI,CAAC/B,QAAQ,EAAEsO,aAAa,CAAC,CAAC,CAAC,CAAC,IAC/DnN,cAAc,CAACS,IAAI,CAAC,IAAI,CAAC5B,QAAQ,EAAEsO,aAAa,CAAC,CAAC,CAAC,CAAC,IACpDnN,cAAc,CAACG,OAAO,CAACgN,aAAa,EAAE,IAAI,CAACoB,OAAO,CAAC;EACrD,IAAA,IAAI,CAACE,SAAS,GAAG,IAAI,CAACC,aAAa,EAAE;EACvC,EAAA;;EAEA;IACA,WAAWjR,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACA6M,EAAAA,MAAMA,GAAG;EACP,IAAA,OAAO,IAAI,CAAC6I,QAAQ,EAAE,GAAG,IAAI,CAACC,IAAI,EAAE,GAAG,IAAI,CAACC,IAAI,EAAE;EACpD,EAAA;EAEAA,EAAAA,IAAIA,GAAG;EACL,IAAA,IAAI5X,UAAU,CAAC,IAAI,CAACkL,QAAQ,CAAC,IAAI,IAAI,CAACwM,QAAQ,EAAE,EAAE;EAChD,MAAA;EACF,IAAA;EAEA,IAAA,MAAMpR,aAAa,GAAG;QACpBA,aAAa,EAAE,IAAI,CAAC4E;OACrB;EAED,IAAA,MAAM8P,SAAS,GAAGhW,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEkL,YAAU,EAAE9P,aAAa,CAAC;MAEhF,IAAI0U,SAAS,CAACnT,gBAAgB,EAAE;EAC9B,MAAA;EACF,IAAA;MAEA,IAAI,CAACoT,aAAa,EAAE;;EAEpB;EACA;EACA;EACA;EACA,IAAA,IAAI,cAAc,IAAI7c,QAAQ,CAACqC,eAAe,IAAI,CAAC,IAAI,CAACma,OAAO,CAAC/a,OAAO,CAAC6Z,mBAAmB,CAAC,EAAE;EAC5F,MAAA,KAAK,MAAM5d,OAAO,IAAI,EAAE,CAACwQ,MAAM,CAAC,GAAGlO,QAAQ,CAAC+C,IAAI,CAACsL,QAAQ,CAAC,EAAE;UAC1DzH,YAAY,CAACiC,EAAE,CAACnL,OAAO,EAAE,WAAW,EAAEgF,IAAI,CAAC;EAC7C,MAAA;EACF,IAAA;EAEA,IAAA,IAAI,CAACoK,QAAQ,CAACgQ,KAAK,EAAE;MACrB,IAAI,CAAChQ,QAAQ,CAAChC,YAAY,CAAC,eAAe,EAAE,IAAI,CAAC;MAEjD,IAAI,CAAC2R,KAAK,CAAC1a,SAAS,CAACwQ,GAAG,CAAC1C,iBAAe,CAAC;MACzC,IAAI,CAAC/C,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAAC1C,iBAAe,CAAC;MAC5CjJ,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEmL,aAAW,EAAE/P,aAAa,CAAC;EACjE,EAAA;EAEAqR,EAAAA,IAAIA,GAAG;EACL,IAAA,IAAI3X,UAAU,CAAC,IAAI,CAACkL,QAAQ,CAAC,IAAI,CAAC,IAAI,CAACwM,QAAQ,EAAE,EAAE;EACjD,MAAA;EACF,IAAA;EAEA,IAAA,MAAMpR,aAAa,GAAG;QACpBA,aAAa,EAAE,IAAI,CAAC4E;OACrB;EAED,IAAA,IAAI,CAACiQ,aAAa,CAAC7U,aAAa,CAAC;EACnC,EAAA;EAEAgF,EAAAA,OAAOA,GAAG;MACR,IAAI,IAAI,CAACqP,OAAO,EAAE;EAChB,MAAA,IAAI,CAACA,OAAO,CAACS,OAAO,EAAE;EACxB,IAAA;MAEA,KAAK,CAAC9P,OAAO,EAAE;EACjB,EAAA;EAEA+P,EAAAA,MAAMA,GAAG;EACP,IAAA,IAAI,CAACP,SAAS,GAAG,IAAI,CAACC,aAAa,EAAE;MACrC,IAAI,IAAI,CAACJ,OAAO,EAAE;EAChB,MAAA,IAAI,CAACA,OAAO,CAACU,MAAM,EAAE;EACvB,IAAA;EACF,EAAA;;EAEA;IACAF,aAAaA,CAAC7U,aAAa,EAAE;EAC3B,IAAA,MAAMgV,SAAS,GAAGtW,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEoL,YAAU,EAAEhQ,aAAa,CAAC;MAChF,IAAIgV,SAAS,CAACzT,gBAAgB,EAAE;EAC9B,MAAA;EACF,IAAA;;EAEA;EACA;EACA,IAAA,IAAI,cAAc,IAAIzJ,QAAQ,CAACqC,eAAe,EAAE;EAC9C,MAAA,KAAK,MAAM3E,OAAO,IAAI,EAAE,CAACwQ,MAAM,CAAC,GAAGlO,QAAQ,CAAC+C,IAAI,CAACsL,QAAQ,CAAC,EAAE;UAC1DzH,YAAY,CAACC,GAAG,CAACnJ,OAAO,EAAE,WAAW,EAAEgF,IAAI,CAAC;EAC9C,MAAA;EACF,IAAA;MAEA,IAAI,IAAI,CAAC6Z,OAAO,EAAE;EAChB,MAAA,IAAI,CAACA,OAAO,CAACS,OAAO,EAAE;EACxB,IAAA;MAEA,IAAI,CAACP,KAAK,CAAC1a,SAAS,CAACzD,MAAM,CAACuR,iBAAe,CAAC;MAC5C,IAAI,CAAC/C,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAACuR,iBAAe,CAAC;MAC/C,IAAI,CAAC/C,QAAQ,CAAChC,YAAY,CAAC,eAAe,EAAE,OAAO,CAAC;MACpDF,WAAW,CAACG,mBAAmB,CAAC,IAAI,CAAC0R,KAAK,EAAE,QAAQ,CAAC;MACrD7V,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEqL,cAAY,EAAEjQ,aAAa,CAAC;EAClE,EAAA;IAEA2D,UAAUA,CAACC,MAAM,EAAE;EACjBA,IAAAA,MAAM,GAAG,KAAK,CAACD,UAAU,CAACC,MAAM,CAAC;MAEjC,IAAI,OAAOA,MAAM,CAACuQ,SAAS,KAAK,QAAQ,IAAI,CAACvb,SAAS,CAACgL,MAAM,CAACuQ,SAAS,CAAC,IACtE,OAAOvQ,MAAM,CAACuQ,SAAS,CAAClC,qBAAqB,KAAK,UAAU,EAC5D;EACA;QACA,MAAM,IAAIzN,SAAS,CAAC,CAAA,EAAG9I,MAAI,CAAC+I,WAAW,EAAE,CAAA,8FAAA,CAAgG,CAAC;EAC5I,IAAA;EAEA,IAAA,OAAOb,MAAM;EACf,EAAA;EAEA+Q,EAAAA,aAAaA,GAAG;EACd,IAAA,IAAI,OAAOM,iBAAM,KAAK,WAAW,EAAE;EACjC,MAAA,MAAM,IAAIzQ,SAAS,CAAC,wEAAwE,CAAC;EAC/F,IAAA;EAEA,IAAA,IAAI0Q,gBAAgB,GAAG,IAAI,CAACtQ,QAAQ;EAEpC,IAAA,IAAI,IAAI,CAACC,OAAO,CAACsP,SAAS,KAAK,QAAQ,EAAE;QACvCe,gBAAgB,GAAG,IAAI,CAACZ,OAAO;MACjC,CAAC,MAAM,IAAI1b,SAAS,CAAC,IAAI,CAACiM,OAAO,CAACsP,SAAS,CAAC,EAAE;QAC5Ce,gBAAgB,GAAGnc,UAAU,CAAC,IAAI,CAAC8L,OAAO,CAACsP,SAAS,CAAC;MACvD,CAAC,MAAM,IAAI,OAAO,IAAI,CAACtP,OAAO,CAACsP,SAAS,KAAK,QAAQ,EAAE;EACrDe,MAAAA,gBAAgB,GAAG,IAAI,CAACrQ,OAAO,CAACsP,SAAS;EAC3C,IAAA;EAEA,IAAA,MAAMD,YAAY,GAAG,IAAI,CAACiB,gBAAgB,EAAE;EAC5C,IAAA,IAAI,CAACd,OAAO,GAAGY,iBAAM,CAACG,YAAY,CAACF,gBAAgB,EAAE,IAAI,CAACX,KAAK,EAAEL,YAAY,CAAC;EAChF,EAAA;EAEA9C,EAAAA,QAAQA,GAAG;MACT,OAAO,IAAI,CAACmD,KAAK,CAAC1a,SAAS,CAACC,QAAQ,CAAC6N,iBAAe,CAAC;EACvD,EAAA;EAEA0N,EAAAA,aAAaA,GAAG;EACd,IAAA,MAAMC,cAAc,GAAG,IAAI,CAAChB,OAAO;MAEnC,IAAIgB,cAAc,CAACzb,SAAS,CAACC,QAAQ,CAAC+Y,kBAAkB,CAAC,EAAE;EACzD,MAAA,OAAOa,eAAe;EACxB,IAAA;MAEA,IAAI4B,cAAc,CAACzb,SAAS,CAACC,QAAQ,CAACgZ,oBAAoB,CAAC,EAAE;EAC3D,MAAA,OAAOa,cAAc;EACvB,IAAA;MAEA,IAAI2B,cAAc,CAACzb,SAAS,CAACC,QAAQ,CAACiZ,wBAAwB,CAAC,EAAE;EAC/D,MAAA,OAAOa,mBAAmB;EAC5B,IAAA;MAEA,IAAI0B,cAAc,CAACzb,SAAS,CAACC,QAAQ,CAACkZ,0BAA0B,CAAC,EAAE;EACjE,MAAA,OAAOa,sBAAsB;EAC/B,IAAA;;EAEA;EACA,IAAA,MAAM0B,KAAK,GAAGpd,gBAAgB,CAAC,IAAI,CAACoc,KAAK,CAAC,CAAClb,gBAAgB,CAAC,eAAe,CAAC,CAACsM,IAAI,EAAE,KAAK,KAAK;MAE7F,IAAI2P,cAAc,CAACzb,SAAS,CAACC,QAAQ,CAAC8Y,iBAAiB,CAAC,EAAE;EACxD,MAAA,OAAO2C,KAAK,GAAGhC,gBAAgB,GAAGD,aAAa;EACjD,IAAA;EAEA,IAAA,OAAOiC,KAAK,GAAG9B,mBAAmB,GAAGD,gBAAgB;EACvD,EAAA;EAEAiB,EAAAA,aAAaA,GAAG;MACd,OAAO,IAAI,CAAC7P,QAAQ,CAACrL,OAAO,CAAC4Z,eAAe,CAAC,KAAK,IAAI;EACxD,EAAA;EAEAqC,EAAAA,UAAUA,GAAG;MACX,MAAM;EAAEvB,MAAAA;OAAQ,GAAG,IAAI,CAACpP,OAAO;EAE/B,IAAA,IAAI,OAAOoP,MAAM,KAAK,QAAQ,EAAE;EAC9B,MAAA,OAAOA,MAAM,CAACzb,KAAK,CAAC,GAAG,CAAC,CAACoN,GAAG,CAAC5D,KAAK,IAAI3J,MAAM,CAACyW,QAAQ,CAAC9M,KAAK,EAAE,EAAE,CAAC,CAAC;EACnE,IAAA;EAEA,IAAA,IAAI,OAAOiS,MAAM,KAAK,UAAU,EAAE;QAChC,OAAOwB,UAAU,IAAIxB,MAAM,CAACwB,UAAU,EAAE,IAAI,CAAC7Q,QAAQ,CAAC;EACxD,IAAA;EAEA,IAAA,OAAOqP,MAAM;EACf,EAAA;EAEAkB,EAAAA,gBAAgBA,GAAG;EACjB,IAAA,MAAMO,qBAAqB,GAAG;EAC5BC,MAAAA,SAAS,EAAE,IAAI,CAACN,aAAa,EAAE;EAC/BO,MAAAA,SAAS,EAAE,CAAC;EACVna,QAAAA,IAAI,EAAE,iBAAiB;EACvBoa,QAAAA,OAAO,EAAE;EACP9B,UAAAA,QAAQ,EAAE,IAAI,CAAClP,OAAO,CAACkP;EACzB;EACF,OAAC,EACD;EACEtY,QAAAA,IAAI,EAAE,QAAQ;EACdoa,QAAAA,OAAO,EAAE;EACP5B,UAAAA,MAAM,EAAE,IAAI,CAACuB,UAAU;EACzB;SACD;OACF;;EAED;MACA,IAAI,IAAI,CAAChB,SAAS,IAAI,IAAI,CAAC3P,OAAO,CAACmP,OAAO,KAAK,QAAQ,EAAE;QACvDtR,WAAW,CAACC,gBAAgB,CAAC,IAAI,CAAC4R,KAAK,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;QAC5DmB,qBAAqB,CAACE,SAAS,GAAG,CAAC;EACjCna,QAAAA,IAAI,EAAE,aAAa;EACnBqa,QAAAA,OAAO,EAAE;EACX,OAAC,CAAC;EACJ,IAAA;MAEA,OAAO;EACL,MAAA,GAAGJ,qBAAqB;EACxB,MAAA,GAAG1Z,OAAO,CAAC,IAAI,CAAC6I,OAAO,CAACqP,YAAY,EAAE,CAAC/c,SAAS,EAAEue,qBAAqB,CAAC;OACzE;EACH,EAAA;EAEAK,EAAAA,eAAeA,CAAC;MAAEtgB,GAAG;EAAEkH,IAAAA;EAAO,GAAC,EAAE;MAC/B,MAAMiR,KAAK,GAAG7H,cAAc,CAACxG,IAAI,CAAC8T,sBAAsB,EAAE,IAAI,CAACkB,KAAK,CAAC,CAACpR,MAAM,CAAC3N,OAAO,IAAI0D,SAAS,CAAC1D,OAAO,CAAC,CAAC;EAE3G,IAAA,IAAI,CAACoY,KAAK,CAAC5U,MAAM,EAAE;EACjB,MAAA;EACF,IAAA;;EAEA;EACA;MACA8D,oBAAoB,CAAC8Q,KAAK,EAAEjR,MAAM,EAAElH,GAAG,KAAK+c,gBAAc,EAAE,CAAC5E,KAAK,CAAClN,QAAQ,CAAC/D,MAAM,CAAC,CAAC,CAACiY,KAAK,EAAE;EAC9F,EAAA;;EAEA;IACA,OAAO/Y,eAAeA,CAAC+H,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACoE,IAAI,CAAC,YAAY;QAC3B,MAAMC,IAAI,GAAGmM,QAAQ,CAAC7O,mBAAmB,CAAC,IAAI,EAAE3B,MAAM,CAAC;EAEvD,MAAA,IAAI,OAAOA,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA;EACF,MAAA;EAEA,MAAA,IAAI,OAAOqE,IAAI,CAACrE,MAAM,CAAC,KAAK,WAAW,EAAE;EACvC,QAAA,MAAM,IAAIY,SAAS,CAAC,CAAA,iBAAA,EAAoBZ,MAAM,GAAG,CAAC;EACpD,MAAA;EAEAqE,MAAAA,IAAI,CAACrE,MAAM,CAAC,EAAE;EAChB,IAAA,CAAC,CAAC;EACJ,EAAA;IAEA,OAAOoS,UAAUA,CAAC1X,KAAK,EAAE;EACvB,IAAA,IAAIA,KAAK,CAACkK,MAAM,KAAKiK,kBAAkB,IAAKnU,KAAK,CAACM,IAAI,KAAK,OAAO,IAAIN,KAAK,CAAC7I,GAAG,KAAK6c,SAAQ,EAAE;EAC5F,MAAA;EACF,IAAA;EAEA,IAAA,MAAM2D,WAAW,GAAGlQ,cAAc,CAACxG,IAAI,CAAC0T,0BAA0B,CAAC;EAEnE,IAAA,KAAK,MAAM1K,MAAM,IAAI0N,WAAW,EAAE;EAChC,MAAA,MAAMC,OAAO,GAAG9B,QAAQ,CAAC9O,WAAW,CAACiD,MAAM,CAAC;QAC5C,IAAI,CAAC2N,OAAO,IAAIA,OAAO,CAACrR,OAAO,CAACiP,SAAS,KAAK,KAAK,EAAE;EACnD,QAAA;EACF,MAAA;EAEA,MAAA,MAAMqC,YAAY,GAAG7X,KAAK,CAAC6X,YAAY,EAAE;QACzC,MAAMC,YAAY,GAAGD,YAAY,CAACzV,QAAQ,CAACwV,OAAO,CAAC3B,KAAK,CAAC;EACzD,MAAA,IACE4B,YAAY,CAACzV,QAAQ,CAACwV,OAAO,CAACtR,QAAQ,CAAC,IACtCsR,OAAO,CAACrR,OAAO,CAACiP,SAAS,KAAK,QAAQ,IAAI,CAACsC,YAAa,IACxDF,OAAO,CAACrR,OAAO,CAACiP,SAAS,KAAK,SAAS,IAAIsC,YAAa,EACzD;EACA,QAAA;EACF,MAAA;;EAEA;EACA,MAAA,IAAIF,OAAO,CAAC3B,KAAK,CAACza,QAAQ,CAACwE,KAAK,CAAC3B,MAAM,CAAC,KAAM2B,KAAK,CAACM,IAAI,KAAK,OAAO,IAAIN,KAAK,CAAC7I,GAAG,KAAK6c,SAAO,IAAK,oCAAoC,CAAC/N,IAAI,CAACjG,KAAK,CAAC3B,MAAM,CAAC4K,OAAO,CAAC,CAAC,EAAE;EAClK,QAAA;EACF,MAAA;EAEA,MAAA,MAAMvH,aAAa,GAAG;UAAEA,aAAa,EAAEkW,OAAO,CAACtR;SAAU;EAEzD,MAAA,IAAItG,KAAK,CAACM,IAAI,KAAK,OAAO,EAAE;UAC1BoB,aAAa,CAACsH,UAAU,GAAGhJ,KAAK;EAClC,MAAA;EAEA4X,MAAAA,OAAO,CAACrB,aAAa,CAAC7U,aAAa,CAAC;EACtC,IAAA;EACF,EAAA;IAEA,OAAOqW,qBAAqBA,CAAC/X,KAAK,EAAE;EAClC;EACA;;MAEA,MAAMgY,OAAO,GAAG,iBAAiB,CAAC/R,IAAI,CAACjG,KAAK,CAAC3B,MAAM,CAAC4K,OAAO,CAAC;EAC5D,IAAA,MAAMgP,aAAa,GAAGjY,KAAK,CAAC7I,GAAG,KAAK4c,YAAU;EAC9C,IAAA,MAAMmE,eAAe,GAAG,CAACjE,cAAY,EAAEC,gBAAc,CAAC,CAAC9R,QAAQ,CAACpC,KAAK,CAAC7I,GAAG,CAAC;EAE1E,IAAA,IAAI,CAAC+gB,eAAe,IAAI,CAACD,aAAa,EAAE;EACtC,MAAA;EACF,IAAA;EAEA,IAAA,IAAID,OAAO,IAAI,CAACC,aAAa,EAAE;EAC7B,MAAA;EACF,IAAA;MAEAjY,KAAK,CAACuD,cAAc,EAAE;;EAEtB;MACA,MAAM4U,eAAe,GAAG,IAAI,CAACpQ,OAAO,CAAC+B,sBAAoB,CAAC,GACxD,IAAI,GACHrC,cAAc,CAACS,IAAI,CAAC,IAAI,EAAE4B,sBAAoB,CAAC,CAAC,CAAC,CAAC,IACjDrC,cAAc,CAACY,IAAI,CAAC,IAAI,EAAEyB,sBAAoB,CAAC,CAAC,CAAC,CAAC,IAClDrC,cAAc,CAACG,OAAO,CAACkC,sBAAoB,EAAE9J,KAAK,CAACE,cAAc,CAAC/E,UAAU,CAAE;EAElF,IAAA,MAAM/D,QAAQ,GAAG0e,QAAQ,CAAC7O,mBAAmB,CAACkR,eAAe,CAAC;EAE9D,IAAA,IAAID,eAAe,EAAE;QACnBlY,KAAK,CAACoY,eAAe,EAAE;QACvBhhB,QAAQ,CAAC4b,IAAI,EAAE;EACf5b,MAAAA,QAAQ,CAACqgB,eAAe,CAACzX,KAAK,CAAC;EAC/B,MAAA;EACF,IAAA;EAEA,IAAA,IAAI5I,QAAQ,CAAC0b,QAAQ,EAAE,EAAE;EAAE;QACzB9S,KAAK,CAACoY,eAAe,EAAE;QACvBhhB,QAAQ,CAAC2b,IAAI,EAAE;QACfoF,eAAe,CAAC7B,KAAK,EAAE;EACzB,IAAA;EACF,EAAA;EACF;;EAEA;EACA;EACA;;EAEAlW,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAE4a,sBAAsB,EAAEtK,sBAAoB,EAAEgM,QAAQ,CAACiC,qBAAqB,CAAC;EACvG3X,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAE4a,sBAAsB,EAAEQ,aAAa,EAAEkB,QAAQ,CAACiC,qBAAqB,CAAC;EAChG3X,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAEuQ,sBAAoB,EAAE+L,QAAQ,CAAC4B,UAAU,CAAC;EACpEtX,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAE6a,oBAAoB,EAAEyB,QAAQ,CAAC4B,UAAU,CAAC;EACpEtX,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAEuQ,sBAAoB,EAAED,sBAAoB,EAAE,UAAU9J,KAAK,EAAE;IACrFA,KAAK,CAACuD,cAAc,EAAE;IACtBuS,QAAQ,CAAC7O,mBAAmB,CAAC,IAAI,CAAC,CAACgD,MAAM,EAAE;EAC7C,CAAC,CAAC;;EAEF;EACA;EACA;;EAEAjN,kBAAkB,CAAC8Y,QAAQ,CAAC;;ECpc5B;EACA;EACA;EACA;EACA;EACA;;;EAQA;EACA;EACA;;EAEA,MAAM1Y,MAAI,GAAG,UAAU;EACvB,MAAMgM,iBAAe,GAAG,MAAM;EAC9B,MAAMC,iBAAe,GAAG,MAAM;EAC9B,MAAMgP,eAAe,GAAG,CAAA,aAAA,EAAgBjb,MAAI,CAAA,CAAE;EAE9C,MAAM8H,SAAO,GAAG;EACdoT,EAAAA,SAAS,EAAE,gBAAgB;EAC3BC,EAAAA,aAAa,EAAE,IAAI;EACnBxR,EAAAA,UAAU,EAAE,KAAK;EACjBnM,EAAAA,SAAS,EAAE,IAAI;EAAE;IACjB4d,WAAW,EAAE,MAAM;EACrB,CAAC;EAED,MAAMrT,aAAW,GAAG;EAClBmT,EAAAA,SAAS,EAAE,QAAQ;EACnBC,EAAAA,aAAa,EAAE,iBAAiB;EAChCxR,EAAAA,UAAU,EAAE,SAAS;EACrBnM,EAAAA,SAAS,EAAE,SAAS;EACpB4d,EAAAA,WAAW,EAAE;EACf,CAAC;;EAED;EACA;EACA;;EAEA,MAAMC,QAAQ,SAASxT,MAAM,CAAC;IAC5BU,WAAWA,CAACL,MAAM,EAAE;EAClB,IAAA,KAAK,EAAE;MACP,IAAI,CAACiB,OAAO,GAAG,IAAI,CAAClB,UAAU,CAACC,MAAM,CAAC;MACtC,IAAI,CAACoT,WAAW,GAAG,KAAK;MACxB,IAAI,CAACpS,QAAQ,GAAG,IAAI;EACtB,EAAA;;EAEA;IACA,WAAWpB,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;IACA4V,IAAIA,CAACtW,QAAQ,EAAE;EACb,IAAA,IAAI,CAAC,IAAI,CAAC6J,OAAO,CAAC3L,SAAS,EAAE;QAC3B8C,OAAO,CAAChB,QAAQ,CAAC;EACjB,MAAA;EACF,IAAA;MAEA,IAAI,CAACic,OAAO,EAAE;EAEd,IAAA,MAAMzhB,OAAO,GAAG,IAAI,CAAC0hB,WAAW,EAAE;EAClC,IAAA,IAAI,IAAI,CAACrS,OAAO,CAACQ,UAAU,EAAE;QAC3B5K,MAAM,CAACjF,OAAO,CAAC;EACjB,IAAA;EAEAA,IAAAA,OAAO,CAACqE,SAAS,CAACwQ,GAAG,CAAC1C,iBAAe,CAAC;MAEtC,IAAI,CAACwP,iBAAiB,CAAC,MAAM;QAC3Bnb,OAAO,CAAChB,QAAQ,CAAC;EACnB,IAAA,CAAC,CAAC;EACJ,EAAA;IAEAqW,IAAIA,CAACrW,QAAQ,EAAE;EACb,IAAA,IAAI,CAAC,IAAI,CAAC6J,OAAO,CAAC3L,SAAS,EAAE;QAC3B8C,OAAO,CAAChB,QAAQ,CAAC;EACjB,MAAA;EACF,IAAA;MAEA,IAAI,CAACkc,WAAW,EAAE,CAACrd,SAAS,CAACzD,MAAM,CAACuR,iBAAe,CAAC;MAEpD,IAAI,CAACwP,iBAAiB,CAAC,MAAM;QAC3B,IAAI,CAACnS,OAAO,EAAE;QACdhJ,OAAO,CAAChB,QAAQ,CAAC;EACnB,IAAA,CAAC,CAAC;EACJ,EAAA;EAEAgK,EAAAA,OAAOA,GAAG;EACR,IAAA,IAAI,CAAC,IAAI,CAACgS,WAAW,EAAE;EACrB,MAAA;EACF,IAAA;MAEAtY,YAAY,CAACC,GAAG,CAAC,IAAI,CAACiG,QAAQ,EAAE+R,eAAe,CAAC;EAEhD,IAAA,IAAI,CAAC/R,QAAQ,CAACxO,MAAM,EAAE;MACtB,IAAI,CAAC4gB,WAAW,GAAG,KAAK;EAC1B,EAAA;;EAEA;EACAE,EAAAA,WAAWA,GAAG;EACZ,IAAA,IAAI,CAAC,IAAI,CAACtS,QAAQ,EAAE;EAClB,MAAA,MAAMwS,QAAQ,GAAGtf,QAAQ,CAACuf,aAAa,CAAC,KAAK,CAAC;EAC9CD,MAAAA,QAAQ,CAACR,SAAS,GAAG,IAAI,CAAC/R,OAAO,CAAC+R,SAAS;EAC3C,MAAA,IAAI,IAAI,CAAC/R,OAAO,CAACQ,UAAU,EAAE;EAC3B+R,QAAAA,QAAQ,CAACvd,SAAS,CAACwQ,GAAG,CAAC3C,iBAAe,CAAC;EACzC,MAAA;QAEA,IAAI,CAAC9C,QAAQ,GAAGwS,QAAQ;EAC1B,IAAA;MAEA,OAAO,IAAI,CAACxS,QAAQ;EACtB,EAAA;IAEAd,iBAAiBA,CAACF,MAAM,EAAE;EACxB;MACAA,MAAM,CAACkT,WAAW,GAAG/d,UAAU,CAAC6K,MAAM,CAACkT,WAAW,CAAC;EACnD,IAAA,OAAOlT,MAAM;EACf,EAAA;EAEAqT,EAAAA,OAAOA,GAAG;MACR,IAAI,IAAI,CAACD,WAAW,EAAE;EACpB,MAAA;EACF,IAAA;EAEA,IAAA,MAAMxhB,OAAO,GAAG,IAAI,CAAC0hB,WAAW,EAAE;MAClC,IAAI,CAACrS,OAAO,CAACiS,WAAW,CAACQ,MAAM,CAAC9hB,OAAO,CAAC;EAExCkJ,IAAAA,YAAY,CAACiC,EAAE,CAACnL,OAAO,EAAEmhB,eAAe,EAAE,MAAM;EAC9C3a,MAAAA,OAAO,CAAC,IAAI,CAAC6I,OAAO,CAACgS,aAAa,CAAC;EACrC,IAAA,CAAC,CAAC;MAEF,IAAI,CAACG,WAAW,GAAG,IAAI;EACzB,EAAA;IAEAG,iBAAiBA,CAACnc,QAAQ,EAAE;EAC1BoB,IAAAA,sBAAsB,CAACpB,QAAQ,EAAE,IAAI,CAACkc,WAAW,EAAE,EAAE,IAAI,CAACrS,OAAO,CAACQ,UAAU,CAAC;EAC/E,EAAA;EACF;;ECpJA;EACA;EACA;EACA;EACA;EACA;;;EAMA;EACA;EACA;;EAEA,MAAM3J,MAAI,GAAG,WAAW;EACxB,MAAMqJ,UAAQ,GAAG,cAAc;EAC/B,MAAME,WAAS,GAAG,CAAA,CAAA,EAAIF,UAAQ,CAAA,CAAE;EAChC,MAAMwS,eAAa,GAAG,CAAA,OAAA,EAAUtS,WAAS,CAAA,CAAE;EAC3C,MAAMuS,iBAAiB,GAAG,CAAA,WAAA,EAAcvS,WAAS,CAAA,CAAE;EAEnD,MAAMqN,OAAO,GAAG,KAAK;EACrB,MAAMmF,eAAe,GAAG,SAAS;EACjC,MAAMC,gBAAgB,GAAG,UAAU;EAEnC,MAAMlU,SAAO,GAAG;EACdmU,EAAAA,SAAS,EAAE,IAAI;IACfC,WAAW,EAAE,IAAI;EACnB,CAAC;EAED,MAAMnU,aAAW,GAAG;EAClBkU,EAAAA,SAAS,EAAE,SAAS;EACpBC,EAAAA,WAAW,EAAE;EACf,CAAC;;EAED;EACA;EACA;;EAEA,MAAMC,SAAS,SAAStU,MAAM,CAAC;IAC7BU,WAAWA,CAACL,MAAM,EAAE;EAClB,IAAA,KAAK,EAAE;MACP,IAAI,CAACiB,OAAO,GAAG,IAAI,CAAClB,UAAU,CAACC,MAAM,CAAC;MACtC,IAAI,CAACkU,SAAS,GAAG,KAAK;MACtB,IAAI,CAACC,oBAAoB,GAAG,IAAI;EAClC,EAAA;;EAEA;IACA,WAAWvU,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACAsc,EAAAA,QAAQA,GAAG;MACT,IAAI,IAAI,CAACF,SAAS,EAAE;EAClB,MAAA;EACF,IAAA;EAEA,IAAA,IAAI,IAAI,CAACjT,OAAO,CAAC8S,SAAS,EAAE;EAC1B,MAAA,IAAI,CAAC9S,OAAO,CAAC+S,WAAW,CAAChD,KAAK,EAAE;EAClC,IAAA;EAEAlW,IAAAA,YAAY,CAACC,GAAG,CAAC7G,QAAQ,EAAEmN,WAAS,CAAC,CAAA;EACrCvG,IAAAA,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAEyf,eAAa,EAAEjZ,KAAK,IAAI,IAAI,CAAC2Z,cAAc,CAAC3Z,KAAK,CAAC,CAAC;EAC7EI,IAAAA,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAE0f,iBAAiB,EAAElZ,KAAK,IAAI,IAAI,CAAC4Z,cAAc,CAAC5Z,KAAK,CAAC,CAAC;MAEjF,IAAI,CAACwZ,SAAS,GAAG,IAAI;EACvB,EAAA;EAEAK,EAAAA,UAAUA,GAAG;EACX,IAAA,IAAI,CAAC,IAAI,CAACL,SAAS,EAAE;EACnB,MAAA;EACF,IAAA;MAEA,IAAI,CAACA,SAAS,GAAG,KAAK;EACtBpZ,IAAAA,YAAY,CAACC,GAAG,CAAC7G,QAAQ,EAAEmN,WAAS,CAAC;EACvC,EAAA;;EAEA;IACAgT,cAAcA,CAAC3Z,KAAK,EAAE;MACpB,MAAM;EAAEsZ,MAAAA;OAAa,GAAG,IAAI,CAAC/S,OAAO;MAEpC,IAAIvG,KAAK,CAAC3B,MAAM,KAAK7E,QAAQ,IAAIwG,KAAK,CAAC3B,MAAM,KAAKib,WAAW,IAAIA,WAAW,CAAC9d,QAAQ,CAACwE,KAAK,CAAC3B,MAAM,CAAC,EAAE;EACnG,MAAA;EACF,IAAA;EAEA,IAAA,MAAMyb,QAAQ,GAAGrS,cAAc,CAACc,iBAAiB,CAAC+Q,WAAW,CAAC;EAE9D,IAAA,IAAIQ,QAAQ,CAACpf,MAAM,KAAK,CAAC,EAAE;QACzB4e,WAAW,CAAChD,KAAK,EAAE;EACrB,IAAA,CAAC,MAAM,IAAI,IAAI,CAACmD,oBAAoB,KAAKL,gBAAgB,EAAE;QACzDU,QAAQ,CAACA,QAAQ,CAACpf,MAAM,GAAG,CAAC,CAAC,CAAC4b,KAAK,EAAE;EACvC,IAAA,CAAC,MAAM;EACLwD,MAAAA,QAAQ,CAAC,CAAC,CAAC,CAACxD,KAAK,EAAE;EACrB,IAAA;EACF,EAAA;IAEAsD,cAAcA,CAAC5Z,KAAK,EAAE;EACpB,IAAA,IAAIA,KAAK,CAAC7I,GAAG,KAAK6c,OAAO,EAAE;EACzB,MAAA;EACF,IAAA;MAEA,IAAI,CAACyF,oBAAoB,GAAGzZ,KAAK,CAAC+Z,QAAQ,GAAGX,gBAAgB,GAAGD,eAAe;EACjF,EAAA;EACF;;EChHA;EACA;EACA;EACA;EACA;EACA;;;EAMA;EACA;EACA;;EAEA,MAAMa,sBAAsB,GAAG,mDAAmD;EAClF,MAAMC,uBAAuB,GAAG,aAAa;EAC7C,MAAMC,gBAAgB,GAAG,eAAe;EACxC,MAAMC,eAAe,GAAG,cAAc;;EAEtC;EACA;EACA;;EAEA,MAAMC,eAAe,CAAC;EACpBzU,EAAAA,WAAWA,GAAG;EACZ,IAAA,IAAI,CAACW,QAAQ,GAAG9M,QAAQ,CAAC+C,IAAI;EAC/B,EAAA;;EAEA;EACA8d,EAAAA,QAAQA,GAAG;EACT;EACA,IAAA,MAAMC,aAAa,GAAG9gB,QAAQ,CAACqC,eAAe,CAAC0e,WAAW;MAC1D,OAAOlhB,IAAI,CAACwS,GAAG,CAACxT,MAAM,CAACmiB,UAAU,GAAGF,aAAa,CAAC;EACpD,EAAA;EAEAvH,EAAAA,IAAIA,GAAG;EACL,IAAA,MAAM0H,KAAK,GAAG,IAAI,CAACJ,QAAQ,EAAE;MAC7B,IAAI,CAACK,gBAAgB,EAAE;EACvB;EACA,IAAA,IAAI,CAACC,qBAAqB,CAAC,IAAI,CAACrU,QAAQ,EAAE4T,gBAAgB,EAAEU,eAAe,IAAIA,eAAe,GAAGH,KAAK,CAAC;EACvG;EACA,IAAA,IAAI,CAACE,qBAAqB,CAACX,sBAAsB,EAAEE,gBAAgB,EAAEU,eAAe,IAAIA,eAAe,GAAGH,KAAK,CAAC;EAChH,IAAA,IAAI,CAACE,qBAAqB,CAACV,uBAAuB,EAAEE,eAAe,EAAES,eAAe,IAAIA,eAAe,GAAGH,KAAK,CAAC;EAClH,EAAA;EAEAI,EAAAA,KAAKA,GAAG;MACN,IAAI,CAACC,uBAAuB,CAAC,IAAI,CAACxU,QAAQ,EAAE,UAAU,CAAC;MACvD,IAAI,CAACwU,uBAAuB,CAAC,IAAI,CAACxU,QAAQ,EAAE4T,gBAAgB,CAAC;EAC7D,IAAA,IAAI,CAACY,uBAAuB,CAACd,sBAAsB,EAAEE,gBAAgB,CAAC;EACtE,IAAA,IAAI,CAACY,uBAAuB,CAACb,uBAAuB,EAAEE,eAAe,CAAC;EACxE,EAAA;EAEAY,EAAAA,aAAaA,GAAG;EACd,IAAA,OAAO,IAAI,CAACV,QAAQ,EAAE,GAAG,CAAC;EAC5B,EAAA;;EAEA;EACAK,EAAAA,gBAAgBA,GAAG;MACjB,IAAI,CAACM,qBAAqB,CAAC,IAAI,CAAC1U,QAAQ,EAAE,UAAU,CAAC;EACrD,IAAA,IAAI,CAACA,QAAQ,CAACiN,KAAK,CAAC0H,QAAQ,GAAG,QAAQ;EACzC,EAAA;EAEAN,EAAAA,qBAAqBA,CAACviB,QAAQ,EAAE8iB,aAAa,EAAExe,QAAQ,EAAE;EACvD,IAAA,MAAMye,cAAc,GAAG,IAAI,CAACd,QAAQ,EAAE;MACtC,MAAMe,oBAAoB,GAAGlkB,OAAO,IAAI;EACtC,MAAA,IAAIA,OAAO,KAAK,IAAI,CAACoP,QAAQ,IAAIjO,MAAM,CAACmiB,UAAU,GAAGtjB,OAAO,CAACqjB,WAAW,GAAGY,cAAc,EAAE;EACzF,QAAA;EACF,MAAA;EAEA,MAAA,IAAI,CAACH,qBAAqB,CAAC9jB,OAAO,EAAEgkB,aAAa,CAAC;EAClD,MAAA,MAAMN,eAAe,GAAGviB,MAAM,CAACwB,gBAAgB,CAAC3C,OAAO,CAAC,CAAC6D,gBAAgB,CAACmgB,aAAa,CAAC;EACxFhkB,MAAAA,OAAO,CAACqc,KAAK,CAAC8H,WAAW,CAACH,aAAa,EAAE,CAAA,EAAGxe,QAAQ,CAAC3C,MAAM,CAACC,UAAU,CAAC4gB,eAAe,CAAC,CAAC,IAAI,CAAC;MAC/F,CAAC;EAED,IAAA,IAAI,CAACU,0BAA0B,CAACljB,QAAQ,EAAEgjB,oBAAoB,CAAC;EACjE,EAAA;EAEAJ,EAAAA,qBAAqBA,CAAC9jB,OAAO,EAAEgkB,aAAa,EAAE;MAC5C,MAAMK,WAAW,GAAGrkB,OAAO,CAACqc,KAAK,CAACxY,gBAAgB,CAACmgB,aAAa,CAAC;EACjE,IAAA,IAAIK,WAAW,EAAE;QACfnX,WAAW,CAACC,gBAAgB,CAACnN,OAAO,EAAEgkB,aAAa,EAAEK,WAAW,CAAC;EACnE,IAAA;EACF,EAAA;EAEAT,EAAAA,uBAAuBA,CAAC1iB,QAAQ,EAAE8iB,aAAa,EAAE;MAC/C,MAAME,oBAAoB,GAAGlkB,OAAO,IAAI;QACtC,MAAMwM,KAAK,GAAGU,WAAW,CAACY,gBAAgB,CAAC9N,OAAO,EAAEgkB,aAAa,CAAC;EAClE;QACA,IAAIxX,KAAK,KAAK,IAAI,EAAE;EAClBxM,QAAAA,OAAO,CAACqc,KAAK,CAACiI,cAAc,CAACN,aAAa,CAAC;EAC3C,QAAA;EACF,MAAA;EAEA9W,MAAAA,WAAW,CAACG,mBAAmB,CAACrN,OAAO,EAAEgkB,aAAa,CAAC;QACvDhkB,OAAO,CAACqc,KAAK,CAAC8H,WAAW,CAACH,aAAa,EAAExX,KAAK,CAAC;MACjD,CAAC;EAED,IAAA,IAAI,CAAC4X,0BAA0B,CAACljB,QAAQ,EAAEgjB,oBAAoB,CAAC;EACjE,EAAA;EAEAE,EAAAA,0BAA0BA,CAACljB,QAAQ,EAAEqjB,QAAQ,EAAE;EAC7C,IAAA,IAAInhB,SAAS,CAAClC,QAAQ,CAAC,EAAE;QACvBqjB,QAAQ,CAACrjB,QAAQ,CAAC;EAClB,MAAA;EACF,IAAA;EAEA,IAAA,KAAK,MAAMmP,GAAG,IAAIE,cAAc,CAACxG,IAAI,CAAC7I,QAAQ,EAAE,IAAI,CAACkO,QAAQ,CAAC,EAAE;QAC9DmV,QAAQ,CAAClU,GAAG,CAAC;EACf,IAAA;EACF,EAAA;EACF;;EC/GA;EACA;EACA;EACA;EACA;EACA;;;EAaA;EACA;EACA;;EAEA,MAAMnK,MAAI,GAAG,OAAO;EACpB,MAAMqJ,UAAQ,GAAG,UAAU;EAC3B,MAAME,WAAS,GAAG,CAAA,CAAA,EAAIF,UAAQ,CAAA,CAAE;EAChC,MAAMmD,cAAY,GAAG,WAAW;EAChC,MAAMmK,YAAU,GAAG,QAAQ;EAE3B,MAAMrC,YAAU,GAAG,CAAA,IAAA,EAAO/K,WAAS,CAAA,CAAE;EACrC,MAAM+U,sBAAoB,GAAG,CAAA,aAAA,EAAgB/U,WAAS,CAAA,CAAE;EACxD,MAAMgL,cAAY,GAAG,CAAA,MAAA,EAAShL,WAAS,CAAA,CAAE;EACzC,MAAM6K,YAAU,GAAG,CAAA,IAAA,EAAO7K,WAAS,CAAA,CAAE;EACrC,MAAM8K,aAAW,GAAG,CAAA,KAAA,EAAQ9K,WAAS,CAAA,CAAE;EACvC,MAAMgV,cAAY,GAAG,CAAA,MAAA,EAAShV,WAAS,CAAA,CAAE;EACzC,MAAMiV,mBAAmB,GAAG,CAAA,aAAA,EAAgBjV,WAAS,CAAA,CAAE;EACvD,MAAMkV,uBAAuB,GAAG,CAAA,iBAAA,EAAoBlV,WAAS,CAAA,CAAE;EAC/D,MAAMmV,uBAAqB,GAAG,CAAA,eAAA,EAAkBnV,WAAS,CAAA,CAAE;EAC3D,MAAMoD,sBAAoB,GAAG,CAAA,KAAA,EAAQpD,WAAS,CAAA,EAAGiD,cAAY,CAAA,CAAE;EAE/D,MAAMmS,eAAe,GAAG,YAAY;EACpC,MAAM3S,iBAAe,GAAG,MAAM;EAC9B,MAAMC,iBAAe,GAAG,MAAM;EAC9B,MAAM2S,iBAAiB,GAAG,cAAc;EAExC,MAAMC,eAAa,GAAG,aAAa;EACnC,MAAMC,eAAe,GAAG,eAAe;EACvC,MAAMC,mBAAmB,GAAG,aAAa;EACzC,MAAMrS,sBAAoB,GAAG,0BAA0B;EAEvD,MAAM5E,SAAO,GAAG;EACd4T,EAAAA,QAAQ,EAAE,IAAI;EACdxC,EAAAA,KAAK,EAAE,IAAI;EACXtI,EAAAA,QAAQ,EAAE;EACZ,CAAC;EAED,MAAM7I,aAAW,GAAG;EAClB2T,EAAAA,QAAQ,EAAE,kBAAkB;EAC5BxC,EAAAA,KAAK,EAAE,SAAS;EAChBtI,EAAAA,QAAQ,EAAE;EACZ,CAAC;;EAED;EACA;EACA;;EAEA,MAAMoO,KAAK,SAAS/V,aAAa,CAAC;EAChCV,EAAAA,WAAWA,CAACzO,OAAO,EAAEoO,MAAM,EAAE;EAC3B,IAAA,KAAK,CAACpO,OAAO,EAAEoO,MAAM,CAAC;EAEtB,IAAA,IAAI,CAAC+W,OAAO,GAAG5U,cAAc,CAACG,OAAO,CAACsU,eAAe,EAAE,IAAI,CAAC5V,QAAQ,CAAC;EACrE,IAAA,IAAI,CAACgW,SAAS,GAAG,IAAI,CAACC,mBAAmB,EAAE;EAC3C,IAAA,IAAI,CAACC,UAAU,GAAG,IAAI,CAACC,oBAAoB,EAAE;MAC7C,IAAI,CAAC3J,QAAQ,GAAG,KAAK;MACrB,IAAI,CAACR,gBAAgB,GAAG,KAAK;EAC7B,IAAA,IAAI,CAACoK,UAAU,GAAG,IAAItC,eAAe,EAAE;MAEvC,IAAI,CAACxL,kBAAkB,EAAE;EAC3B,EAAA;;EAEA;IACA,WAAW1J,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;IACA6M,MAAMA,CAACvI,aAAa,EAAE;EACpB,IAAA,OAAO,IAAI,CAACoR,QAAQ,GAAG,IAAI,CAACC,IAAI,EAAE,GAAG,IAAI,CAACC,IAAI,CAACtR,aAAa,CAAC;EAC/D,EAAA;IAEAsR,IAAIA,CAACtR,aAAa,EAAE;EAClB,IAAA,IAAI,IAAI,CAACoR,QAAQ,IAAI,IAAI,CAACR,gBAAgB,EAAE;EAC1C,MAAA;EACF,IAAA;MAEA,MAAM8D,SAAS,GAAGhW,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEkL,YAAU,EAAE;EAChE9P,MAAAA;EACF,KAAC,CAAC;MAEF,IAAI0U,SAAS,CAACnT,gBAAgB,EAAE;EAC9B,MAAA;EACF,IAAA;MAEA,IAAI,CAAC6P,QAAQ,GAAG,IAAI;MACpB,IAAI,CAACR,gBAAgB,GAAG,IAAI;EAE5B,IAAA,IAAI,CAACoK,UAAU,CAAC3J,IAAI,EAAE;MAEtBvZ,QAAQ,CAAC+C,IAAI,CAAChB,SAAS,CAACwQ,GAAG,CAACgQ,eAAe,CAAC;MAE5C,IAAI,CAACY,aAAa,EAAE;EAEpB,IAAA,IAAI,CAACL,SAAS,CAACtJ,IAAI,CAAC,MAAM,IAAI,CAAC4J,YAAY,CAAClb,aAAa,CAAC,CAAC;EAC7D,EAAA;EAEAqR,EAAAA,IAAIA,GAAG;MACL,IAAI,CAAC,IAAI,CAACD,QAAQ,IAAI,IAAI,CAACR,gBAAgB,EAAE;EAC3C,MAAA;EACF,IAAA;MAEA,MAAMoE,SAAS,GAAGtW,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEoL,YAAU,CAAC;MAEjE,IAAIgF,SAAS,CAACzT,gBAAgB,EAAE;EAC9B,MAAA;EACF,IAAA;MAEA,IAAI,CAAC6P,QAAQ,GAAG,KAAK;MACrB,IAAI,CAACR,gBAAgB,GAAG,IAAI;EAC5B,IAAA,IAAI,CAACkK,UAAU,CAAC3C,UAAU,EAAE;MAE5B,IAAI,CAACvT,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAACuR,iBAAe,CAAC;EAE/C,IAAA,IAAI,CAACvC,cAAc,CAAC,MAAM,IAAI,CAAC+V,UAAU,EAAE,EAAE,IAAI,CAACvW,QAAQ,EAAE,IAAI,CAAC6K,WAAW,EAAE,CAAC;EACjF,EAAA;EAEAzK,EAAAA,OAAOA,GAAG;EACRtG,IAAAA,YAAY,CAACC,GAAG,CAAChI,MAAM,EAAEsO,WAAS,CAAC;MACnCvG,YAAY,CAACC,GAAG,CAAC,IAAI,CAACgc,OAAO,EAAE1V,WAAS,CAAC;EAEzC,IAAA,IAAI,CAAC2V,SAAS,CAAC5V,OAAO,EAAE;EACxB,IAAA,IAAI,CAAC8V,UAAU,CAAC3C,UAAU,EAAE;MAE5B,KAAK,CAACnT,OAAO,EAAE;EACjB,EAAA;EAEAoW,EAAAA,YAAYA,GAAG;MACb,IAAI,CAACH,aAAa,EAAE;EACtB,EAAA;;EAEA;EACAJ,EAAAA,mBAAmBA,GAAG;MACpB,OAAO,IAAI9D,QAAQ,CAAC;QAClB7d,SAAS,EAAEkH,OAAO,CAAC,IAAI,CAACyE,OAAO,CAACuS,QAAQ,CAAC;EAAE;EAC3C/R,MAAAA,UAAU,EAAE,IAAI,CAACoK,WAAW;EAC9B,KAAC,CAAC;EACJ,EAAA;EAEAsL,EAAAA,oBAAoBA,GAAG;MACrB,OAAO,IAAIlD,SAAS,CAAC;QACnBD,WAAW,EAAE,IAAI,CAAChT;EACpB,KAAC,CAAC;EACJ,EAAA;IAEAsW,YAAYA,CAAClb,aAAa,EAAE;EAC1B;MACA,IAAI,CAAClI,QAAQ,CAAC+C,IAAI,CAACf,QAAQ,CAAC,IAAI,CAAC8K,QAAQ,CAAC,EAAE;QAC1C9M,QAAQ,CAAC+C,IAAI,CAACyc,MAAM,CAAC,IAAI,CAAC1S,QAAQ,CAAC;EACrC,IAAA;EAEA,IAAA,IAAI,CAACA,QAAQ,CAACiN,KAAK,CAACmC,OAAO,GAAG,OAAO;EACrC,IAAA,IAAI,CAACpP,QAAQ,CAAC9B,eAAe,CAAC,aAAa,CAAC;MAC5C,IAAI,CAAC8B,QAAQ,CAAChC,YAAY,CAAC,YAAY,EAAE,IAAI,CAAC;MAC9C,IAAI,CAACgC,QAAQ,CAAChC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC;EAC5C,IAAA,IAAI,CAACgC,QAAQ,CAACyW,SAAS,GAAG,CAAC;MAE3B,MAAMC,SAAS,GAAGvV,cAAc,CAACG,OAAO,CAACuU,mBAAmB,EAAE,IAAI,CAACE,OAAO,CAAC;EAC3E,IAAA,IAAIW,SAAS,EAAE;QACbA,SAAS,CAACD,SAAS,GAAG,CAAC;EACzB,IAAA;EAEA5gB,IAAAA,MAAM,CAAC,IAAI,CAACmK,QAAQ,CAAC;MAErB,IAAI,CAACA,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAAC1C,iBAAe,CAAC;MAE5C,MAAM4T,kBAAkB,GAAGA,MAAM;EAC/B,MAAA,IAAI,IAAI,CAAC1W,OAAO,CAAC+P,KAAK,EAAE;EACtB,QAAA,IAAI,CAACkG,UAAU,CAAC9C,QAAQ,EAAE;EAC5B,MAAA;QAEA,IAAI,CAACpH,gBAAgB,GAAG,KAAK;QAC7BlS,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEmL,aAAW,EAAE;EAC/C/P,QAAAA;EACF,OAAC,CAAC;MACJ,CAAC;EAED,IAAA,IAAI,CAACoF,cAAc,CAACmW,kBAAkB,EAAE,IAAI,CAACZ,OAAO,EAAE,IAAI,CAAClL,WAAW,EAAE,CAAC;EAC3E,EAAA;EAEAvC,EAAAA,kBAAkBA,GAAG;MACnBxO,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAEwV,uBAAqB,EAAE9b,KAAK,IAAI;EAC7D,MAAA,IAAIA,KAAK,CAAC7I,GAAG,KAAK4c,YAAU,EAAE;EAC5B,QAAA;EACF,MAAA;EAEA,MAAA,IAAI,IAAI,CAACxN,OAAO,CAACyH,QAAQ,EAAE;UACzB,IAAI,CAAC+E,IAAI,EAAE;EACX,QAAA;EACF,MAAA;QAEA,IAAI,CAACmK,0BAA0B,EAAE;EACnC,IAAA,CAAC,CAAC;EAEF9c,IAAAA,YAAY,CAACiC,EAAE,CAAChK,MAAM,EAAEsjB,cAAY,EAAE,MAAM;QAC1C,IAAI,IAAI,CAAC7I,QAAQ,IAAI,CAAC,IAAI,CAACR,gBAAgB,EAAE;UAC3C,IAAI,CAACqK,aAAa,EAAE;EACtB,MAAA;EACF,IAAA,CAAC,CAAC;MAEFvc,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAEuV,uBAAuB,EAAE7b,KAAK,IAAI;EAC/D;QACAI,YAAY,CAACkC,GAAG,CAAC,IAAI,CAACgE,QAAQ,EAAEsV,mBAAmB,EAAEuB,MAAM,IAAI;EAC7D,QAAA,IAAI,IAAI,CAAC7W,QAAQ,KAAKtG,KAAK,CAAC3B,MAAM,IAAI,IAAI,CAACiI,QAAQ,KAAK6W,MAAM,CAAC9e,MAAM,EAAE;EACrE,UAAA;EACF,QAAA;EAEA,QAAA,IAAI,IAAI,CAACkI,OAAO,CAACuS,QAAQ,KAAK,QAAQ,EAAE;YACtC,IAAI,CAACoE,0BAA0B,EAAE;EACjC,UAAA;EACF,QAAA;EAEA,QAAA,IAAI,IAAI,CAAC3W,OAAO,CAACuS,QAAQ,EAAE;YACzB,IAAI,CAAC/F,IAAI,EAAE;EACb,QAAA;EACF,MAAA,CAAC,CAAC;EACJ,IAAA,CAAC,CAAC;EACJ,EAAA;EAEA8J,EAAAA,UAAUA,GAAG;EACX,IAAA,IAAI,CAACvW,QAAQ,CAACiN,KAAK,CAACmC,OAAO,GAAG,MAAM;MACpC,IAAI,CAACpP,QAAQ,CAAChC,YAAY,CAAC,aAAa,EAAE,IAAI,CAAC;EAC/C,IAAA,IAAI,CAACgC,QAAQ,CAAC9B,eAAe,CAAC,YAAY,CAAC;EAC3C,IAAA,IAAI,CAAC8B,QAAQ,CAAC9B,eAAe,CAAC,MAAM,CAAC;MACrC,IAAI,CAAC8N,gBAAgB,GAAG,KAAK;EAE7B,IAAA,IAAI,CAACgK,SAAS,CAACvJ,IAAI,CAAC,MAAM;QACxBvZ,QAAQ,CAAC+C,IAAI,CAAChB,SAAS,CAACzD,MAAM,CAACikB,eAAe,CAAC;QAC/C,IAAI,CAACqB,iBAAiB,EAAE;EACxB,MAAA,IAAI,CAACV,UAAU,CAAC7B,KAAK,EAAE;QACvBza,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEqL,cAAY,CAAC;EACnD,IAAA,CAAC,CAAC;EACJ,EAAA;EAEAR,EAAAA,WAAWA,GAAG;MACZ,OAAO,IAAI,CAAC7K,QAAQ,CAAC/K,SAAS,CAACC,QAAQ,CAAC4N,iBAAe,CAAC;EAC1D,EAAA;EAEA8T,EAAAA,0BAA0BA,GAAG;MAC3B,MAAMxG,SAAS,GAAGtW,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEoV,sBAAoB,CAAC;MAC3E,IAAIhF,SAAS,CAACzT,gBAAgB,EAAE;EAC9B,MAAA;EACF,IAAA;EAEA,IAAA,MAAMoa,kBAAkB,GAAG,IAAI,CAAC/W,QAAQ,CAACgX,YAAY,GAAG9jB,QAAQ,CAACqC,eAAe,CAAC0hB,YAAY;MAC7F,MAAMC,gBAAgB,GAAG,IAAI,CAAClX,QAAQ,CAACiN,KAAK,CAACkK,SAAS;EACtD;EACA,IAAA,IAAID,gBAAgB,KAAK,QAAQ,IAAI,IAAI,CAAClX,QAAQ,CAAC/K,SAAS,CAACC,QAAQ,CAACwgB,iBAAiB,CAAC,EAAE;EACxF,MAAA;EACF,IAAA;MAEA,IAAI,CAACqB,kBAAkB,EAAE;EACvB,MAAA,IAAI,CAAC/W,QAAQ,CAACiN,KAAK,CAACkK,SAAS,GAAG,QAAQ;EAC1C,IAAA;MAEA,IAAI,CAACnX,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAACiQ,iBAAiB,CAAC;MAC9C,IAAI,CAAClV,cAAc,CAAC,MAAM;QACxB,IAAI,CAACR,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAACkkB,iBAAiB,CAAC;QACjD,IAAI,CAAClV,cAAc,CAAC,MAAM;EACxB,QAAA,IAAI,CAACR,QAAQ,CAACiN,KAAK,CAACkK,SAAS,GAAGD,gBAAgB;EAClD,MAAA,CAAC,EAAE,IAAI,CAACnB,OAAO,CAAC;EAClB,IAAA,CAAC,EAAE,IAAI,CAACA,OAAO,CAAC;EAEhB,IAAA,IAAI,CAAC/V,QAAQ,CAACgQ,KAAK,EAAE;EACvB,EAAA;;EAEA;EACF;EACA;;EAEEqG,EAAAA,aAAaA,GAAG;EACd,IAAA,MAAMU,kBAAkB,GAAG,IAAI,CAAC/W,QAAQ,CAACgX,YAAY,GAAG9jB,QAAQ,CAACqC,eAAe,CAAC0hB,YAAY;MAC7F,MAAMpC,cAAc,GAAG,IAAI,CAACuB,UAAU,CAACrC,QAAQ,EAAE;EACjD,IAAA,MAAMqD,iBAAiB,GAAGvC,cAAc,GAAG,CAAC;EAE5C,IAAA,IAAIuC,iBAAiB,IAAI,CAACL,kBAAkB,EAAE;QAC5C,MAAMxX,QAAQ,GAAG/I,KAAK,EAAE,GAAG,aAAa,GAAG,cAAc;QACzD,IAAI,CAACwJ,QAAQ,CAACiN,KAAK,CAAC1N,QAAQ,CAAC,GAAG,CAAA,EAAGsV,cAAc,CAAA,EAAA,CAAI;EACvD,IAAA;EAEA,IAAA,IAAI,CAACuC,iBAAiB,IAAIL,kBAAkB,EAAE;QAC5C,MAAMxX,QAAQ,GAAG/I,KAAK,EAAE,GAAG,cAAc,GAAG,aAAa;QACzD,IAAI,CAACwJ,QAAQ,CAACiN,KAAK,CAAC1N,QAAQ,CAAC,GAAG,CAAA,EAAGsV,cAAc,CAAA,EAAA,CAAI;EACvD,IAAA;EACF,EAAA;EAEAiC,EAAAA,iBAAiBA,GAAG;EAClB,IAAA,IAAI,CAAC9W,QAAQ,CAACiN,KAAK,CAACoK,WAAW,GAAG,EAAE;EACpC,IAAA,IAAI,CAACrX,QAAQ,CAACiN,KAAK,CAACqK,YAAY,GAAG,EAAE;EACvC,EAAA;;EAEA;EACA,EAAA,OAAOrgB,eAAeA,CAAC+H,MAAM,EAAE5D,aAAa,EAAE;EAC5C,IAAA,OAAO,IAAI,CAACgI,IAAI,CAAC,YAAY;QAC3B,MAAMC,IAAI,GAAGyS,KAAK,CAACnV,mBAAmB,CAAC,IAAI,EAAE3B,MAAM,CAAC;EAEpD,MAAA,IAAI,OAAOA,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA;EACF,MAAA;EAEA,MAAA,IAAI,OAAOqE,IAAI,CAACrE,MAAM,CAAC,KAAK,WAAW,EAAE;EACvC,QAAA,MAAM,IAAIY,SAAS,CAAC,CAAA,iBAAA,EAAoBZ,MAAM,GAAG,CAAC;EACpD,MAAA;EAEAqE,MAAAA,IAAI,CAACrE,MAAM,CAAC,CAAC5D,aAAa,CAAC;EAC7B,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAtB,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAEuQ,sBAAoB,EAAED,sBAAoB,EAAE,UAAU9J,KAAK,EAAE;EACrF,EAAA,MAAM3B,MAAM,GAAGoJ,cAAc,CAACkB,sBAAsB,CAAC,IAAI,CAAC;EAE1D,EAAA,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAACvG,QAAQ,CAAC,IAAI,CAAC6G,OAAO,CAAC,EAAE;MACxCjJ,KAAK,CAACuD,cAAc,EAAE;EACxB,EAAA;IAEAnD,YAAY,CAACkC,GAAG,CAACjE,MAAM,EAAEmT,YAAU,EAAE4E,SAAS,IAAI;MAChD,IAAIA,SAAS,CAACnT,gBAAgB,EAAE;EAC9B;EACA,MAAA;EACF,IAAA;EAEA7C,IAAAA,YAAY,CAACkC,GAAG,CAACjE,MAAM,EAAEsT,cAAY,EAAE,MAAM;EAC3C,MAAA,IAAI/W,SAAS,CAAC,IAAI,CAAC,EAAE;UACnB,IAAI,CAAC0b,KAAK,EAAE;EACd,MAAA;EACF,IAAA,CAAC,CAAC;EACJ,EAAA,CAAC,CAAC;;EAEF;EACA,EAAA,MAAMuH,WAAW,GAAGpW,cAAc,CAACG,OAAO,CAACqU,eAAa,CAAC;EACzD,EAAA,IAAI4B,WAAW,EAAE;MACfzB,KAAK,CAACpV,WAAW,CAAC6W,WAAW,CAAC,CAAC9K,IAAI,EAAE;EACvC,EAAA;EAEA,EAAA,MAAMpJ,IAAI,GAAGyS,KAAK,CAACnV,mBAAmB,CAAC5I,MAAM,CAAC;EAE9CsL,EAAAA,IAAI,CAACM,MAAM,CAAC,IAAI,CAAC;EACnB,CAAC,CAAC;EAEFpB,oBAAoB,CAACuT,KAAK,CAAC;;EAE3B;EACA;EACA;;EAEApf,kBAAkB,CAACof,KAAK,CAAC;;ECvXzB;EACA;EACA;EACA;EACA;EACA;;;EAeA;EACA;EACA;;EAEA,MAAMhf,MAAI,GAAG,WAAW;EACxB,MAAMqJ,UAAQ,GAAG,cAAc;EAC/B,MAAME,WAAS,GAAG,CAAA,CAAA,EAAIF,UAAQ,CAAA,CAAE;EAChC,MAAMmD,cAAY,GAAG,WAAW;EAChC,MAAMoD,qBAAmB,GAAG,CAAA,IAAA,EAAOrG,WAAS,CAAA,EAAGiD,cAAY,CAAA,CAAE;EAC7D,MAAMmK,UAAU,GAAG,QAAQ;EAE3B,MAAM1K,iBAAe,GAAG,MAAM;EAC9B,MAAMyU,oBAAkB,GAAG,SAAS;EACpC,MAAMC,iBAAiB,GAAG,QAAQ;EAClC,MAAMC,mBAAmB,GAAG,oBAAoB;EAChD,MAAM/B,aAAa,GAAG,iBAAiB;EAEvC,MAAMzK,YAAU,GAAG,CAAA,IAAA,EAAO7K,WAAS,CAAA,CAAE;EACrC,MAAM8K,aAAW,GAAG,CAAA,KAAA,EAAQ9K,WAAS,CAAA,CAAE;EACvC,MAAM+K,YAAU,GAAG,CAAA,IAAA,EAAO/K,WAAS,CAAA,CAAE;EACrC,MAAM+U,oBAAoB,GAAG,CAAA,aAAA,EAAgB/U,WAAS,CAAA,CAAE;EACxD,MAAMgL,cAAY,GAAG,CAAA,MAAA,EAAShL,WAAS,CAAA,CAAE;EACzC,MAAMgV,YAAY,GAAG,CAAA,MAAA,EAAShV,WAAS,CAAA,CAAE;EACzC,MAAMoD,sBAAoB,GAAG,CAAA,KAAA,EAAQpD,WAAS,CAAA,EAAGiD,cAAY,CAAA,CAAE;EAC/D,MAAMkS,qBAAqB,GAAG,CAAA,eAAA,EAAkBnV,WAAS,CAAA,CAAE;EAE3D,MAAMmD,sBAAoB,GAAG,8BAA8B;EAE3D,MAAM5E,SAAO,GAAG;EACd4T,EAAAA,QAAQ,EAAE,IAAI;EACd9K,EAAAA,QAAQ,EAAE,IAAI;EACdiQ,EAAAA,MAAM,EAAE;EACV,CAAC;EAED,MAAM9Y,aAAW,GAAG;EAClB2T,EAAAA,QAAQ,EAAE,kBAAkB;EAC5B9K,EAAAA,QAAQ,EAAE,SAAS;EACnBiQ,EAAAA,MAAM,EAAE;EACV,CAAC;;EAED;EACA;EACA;;EAEA,MAAMC,SAAS,SAAS7X,aAAa,CAAC;EACpCV,EAAAA,WAAWA,CAACzO,OAAO,EAAEoO,MAAM,EAAE;EAC3B,IAAA,KAAK,CAACpO,OAAO,EAAEoO,MAAM,CAAC;MAEtB,IAAI,CAACwN,QAAQ,GAAG,KAAK;EACrB,IAAA,IAAI,CAACwJ,SAAS,GAAG,IAAI,CAACC,mBAAmB,EAAE;EAC3C,IAAA,IAAI,CAACC,UAAU,GAAG,IAAI,CAACC,oBAAoB,EAAE;MAC7C,IAAI,CAAC7N,kBAAkB,EAAE;EAC3B,EAAA;;EAEA;IACA,WAAW1J,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;IACA6M,MAAMA,CAACvI,aAAa,EAAE;EACpB,IAAA,OAAO,IAAI,CAACoR,QAAQ,GAAG,IAAI,CAACC,IAAI,EAAE,GAAG,IAAI,CAACC,IAAI,CAACtR,aAAa,CAAC;EAC/D,EAAA;IAEAsR,IAAIA,CAACtR,aAAa,EAAE;MAClB,IAAI,IAAI,CAACoR,QAAQ,EAAE;EACjB,MAAA;EACF,IAAA;MAEA,MAAMsD,SAAS,GAAGhW,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEkL,YAAU,EAAE;EAAE9P,MAAAA;EAAc,KAAC,CAAC;MAEpF,IAAI0U,SAAS,CAACnT,gBAAgB,EAAE;EAC9B,MAAA;EACF,IAAA;MAEA,IAAI,CAAC6P,QAAQ,GAAG,IAAI;EACpB,IAAA,IAAI,CAACwJ,SAAS,CAACtJ,IAAI,EAAE;EAErB,IAAA,IAAI,CAAC,IAAI,CAACzM,OAAO,CAAC0X,MAAM,EAAE;EACxB,MAAA,IAAI7D,eAAe,EAAE,CAACrH,IAAI,EAAE;EAC9B,IAAA;MAEA,IAAI,CAACzM,QAAQ,CAAChC,YAAY,CAAC,YAAY,EAAE,IAAI,CAAC;MAC9C,IAAI,CAACgC,QAAQ,CAAChC,YAAY,CAAC,MAAM,EAAE,QAAQ,CAAC;MAC5C,IAAI,CAACgC,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAAC+R,oBAAkB,CAAC;MAE/C,MAAM5M,gBAAgB,GAAGA,MAAM;EAC7B,MAAA,IAAI,CAAC,IAAI,CAAC3K,OAAO,CAAC0X,MAAM,IAAI,IAAI,CAAC1X,OAAO,CAACuS,QAAQ,EAAE;EACjD,QAAA,IAAI,CAAC0D,UAAU,CAAC9C,QAAQ,EAAE;EAC5B,MAAA;QAEA,IAAI,CAACpT,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAAC1C,iBAAe,CAAC;QAC5C,IAAI,CAAC/C,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAACgmB,oBAAkB,CAAC;QAClD1d,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEmL,aAAW,EAAE;EAAE/P,QAAAA;EAAc,OAAC,CAAC;MACrE,CAAC;MAED,IAAI,CAACoF,cAAc,CAACoK,gBAAgB,EAAE,IAAI,CAAC5K,QAAQ,EAAE,IAAI,CAAC;EAC5D,EAAA;EAEAyM,EAAAA,IAAIA,GAAG;EACL,IAAA,IAAI,CAAC,IAAI,CAACD,QAAQ,EAAE;EAClB,MAAA;EACF,IAAA;MAEA,MAAM4D,SAAS,GAAGtW,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEoL,YAAU,CAAC;MAEjE,IAAIgF,SAAS,CAACzT,gBAAgB,EAAE;EAC9B,MAAA;EACF,IAAA;EAEA,IAAA,IAAI,CAACuZ,UAAU,CAAC3C,UAAU,EAAE;EAC5B,IAAA,IAAI,CAACvT,QAAQ,CAAC6X,IAAI,EAAE;MACpB,IAAI,CAACrL,QAAQ,GAAG,KAAK;MACrB,IAAI,CAACxM,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAACgS,iBAAiB,CAAC;EAC9C,IAAA,IAAI,CAACzB,SAAS,CAACvJ,IAAI,EAAE;MAErB,MAAMqL,gBAAgB,GAAGA,MAAM;QAC7B,IAAI,CAAC9X,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAACuR,iBAAe,EAAE0U,iBAAiB,CAAC;EAClE,MAAA,IAAI,CAACzX,QAAQ,CAAC9B,eAAe,CAAC,YAAY,CAAC;EAC3C,MAAA,IAAI,CAAC8B,QAAQ,CAAC9B,eAAe,CAAC,MAAM,CAAC;EAErC,MAAA,IAAI,CAAC,IAAI,CAAC+B,OAAO,CAAC0X,MAAM,EAAE;EACxB,QAAA,IAAI7D,eAAe,EAAE,CAACS,KAAK,EAAE;EAC/B,MAAA;QAEAza,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEqL,cAAY,CAAC;MACnD,CAAC;MAED,IAAI,CAAC7K,cAAc,CAACsX,gBAAgB,EAAE,IAAI,CAAC9X,QAAQ,EAAE,IAAI,CAAC;EAC5D,EAAA;EAEAI,EAAAA,OAAOA,GAAG;EACR,IAAA,IAAI,CAAC4V,SAAS,CAAC5V,OAAO,EAAE;EACxB,IAAA,IAAI,CAAC8V,UAAU,CAAC3C,UAAU,EAAE;MAC5B,KAAK,CAACnT,OAAO,EAAE;EACjB,EAAA;;EAEA;EACA6V,EAAAA,mBAAmBA,GAAG;MACpB,MAAMhE,aAAa,GAAGA,MAAM;EAC1B,MAAA,IAAI,IAAI,CAAChS,OAAO,CAACuS,QAAQ,KAAK,QAAQ,EAAE;UACtC1Y,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEoV,oBAAoB,CAAC;EACzD,QAAA;EACF,MAAA;QAEA,IAAI,CAAC3I,IAAI,EAAE;MACb,CAAC;;EAED;MACA,MAAMnY,SAAS,GAAGkH,OAAO,CAAC,IAAI,CAACyE,OAAO,CAACuS,QAAQ,CAAC;MAEhD,OAAO,IAAIL,QAAQ,CAAC;EAClBH,MAAAA,SAAS,EAAE0F,mBAAmB;QAC9BpjB,SAAS;EACTmM,MAAAA,UAAU,EAAE,IAAI;EAChByR,MAAAA,WAAW,EAAE,IAAI,CAAClS,QAAQ,CAACnL,UAAU;EACrCod,MAAAA,aAAa,EAAE3d,SAAS,GAAG2d,aAAa,GAAG;EAC7C,KAAC,CAAC;EACJ,EAAA;EAEAkE,EAAAA,oBAAoBA,GAAG;MACrB,OAAO,IAAIlD,SAAS,CAAC;QACnBD,WAAW,EAAE,IAAI,CAAChT;EACpB,KAAC,CAAC;EACJ,EAAA;EAEAsI,EAAAA,kBAAkBA,GAAG;MACnBxO,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAEwV,qBAAqB,EAAE9b,KAAK,IAAI;EAC7D,MAAA,IAAIA,KAAK,CAAC7I,GAAG,KAAK4c,UAAU,EAAE;EAC5B,QAAA;EACF,MAAA;EAEA,MAAA,IAAI,IAAI,CAACxN,OAAO,CAACyH,QAAQ,EAAE;UACzB,IAAI,CAAC+E,IAAI,EAAE;EACX,QAAA;EACF,MAAA;QAEA3S,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEoV,oBAAoB,CAAC;EAC3D,IAAA,CAAC,CAAC;EACJ,EAAA;;EAEA;IACA,OAAOne,eAAeA,CAAC+H,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACoE,IAAI,CAAC,YAAY;QAC3B,MAAMC,IAAI,GAAGuU,SAAS,CAACjX,mBAAmB,CAAC,IAAI,EAAE3B,MAAM,CAAC;EAExD,MAAA,IAAI,OAAOA,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA;EACF,MAAA;EAEA,MAAA,IAAIqE,IAAI,CAACrE,MAAM,CAAC,KAAKzM,SAAS,IAAIyM,MAAM,CAAC7C,UAAU,CAAC,GAAG,CAAC,IAAI6C,MAAM,KAAK,aAAa,EAAE;EACpF,QAAA,MAAM,IAAIY,SAAS,CAAC,CAAA,iBAAA,EAAoBZ,MAAM,GAAG,CAAC;EACpD,MAAA;EAEAqE,MAAAA,IAAI,CAACrE,MAAM,CAAC,CAAC,IAAI,CAAC;EACpB,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAlF,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAEuQ,sBAAoB,EAAED,sBAAoB,EAAE,UAAU9J,KAAK,EAAE;EACrF,EAAA,MAAM3B,MAAM,GAAGoJ,cAAc,CAACkB,sBAAsB,CAAC,IAAI,CAAC;EAE1D,EAAA,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAACvG,QAAQ,CAAC,IAAI,CAAC6G,OAAO,CAAC,EAAE;MACxCjJ,KAAK,CAACuD,cAAc,EAAE;EACxB,EAAA;EAEA,EAAA,IAAInI,UAAU,CAAC,IAAI,CAAC,EAAE;EACpB,IAAA;EACF,EAAA;EAEAgF,EAAAA,YAAY,CAACkC,GAAG,CAACjE,MAAM,EAAEsT,cAAY,EAAE,MAAM;EAC3C;EACA,IAAA,IAAI/W,SAAS,CAAC,IAAI,CAAC,EAAE;QACnB,IAAI,CAAC0b,KAAK,EAAE;EACd,IAAA;EACF,EAAA,CAAC,CAAC;;EAEF;EACA,EAAA,MAAMuH,WAAW,GAAGpW,cAAc,CAACG,OAAO,CAACqU,aAAa,CAAC;EACzD,EAAA,IAAI4B,WAAW,IAAIA,WAAW,KAAKxf,MAAM,EAAE;MACzC6f,SAAS,CAAClX,WAAW,CAAC6W,WAAW,CAAC,CAAC9K,IAAI,EAAE;EAC3C,EAAA;EAEA,EAAA,MAAMpJ,IAAI,GAAGuU,SAAS,CAACjX,mBAAmB,CAAC5I,MAAM,CAAC;EAClDsL,EAAAA,IAAI,CAACM,MAAM,CAAC,IAAI,CAAC;EACnB,CAAC,CAAC;EAEF7J,YAAY,CAACiC,EAAE,CAAChK,MAAM,EAAE2U,qBAAmB,EAAE,MAAM;IACjD,KAAK,MAAM5U,QAAQ,IAAIqP,cAAc,CAACxG,IAAI,CAACgb,aAAa,CAAC,EAAE;MACzDiC,SAAS,CAACjX,mBAAmB,CAAC7O,QAAQ,CAAC,CAAC4a,IAAI,EAAE;EAChD,EAAA;EACF,CAAC,CAAC;EAEF5S,YAAY,CAACiC,EAAE,CAAChK,MAAM,EAAEsjB,YAAY,EAAE,MAAM;IAC1C,KAAK,MAAMzkB,OAAO,IAAIuQ,cAAc,CAACxG,IAAI,CAAC,8CAA8C,CAAC,EAAE;MACzF,IAAIpH,gBAAgB,CAAC3C,OAAO,CAAC,CAACmnB,QAAQ,KAAK,OAAO,EAAE;QAClDH,SAAS,CAACjX,mBAAmB,CAAC/P,OAAO,CAAC,CAAC6b,IAAI,EAAE;EAC/C,IAAA;EACF,EAAA;EACF,CAAC,CAAC;EAEFlK,oBAAoB,CAACqV,SAAS,CAAC;;EAE/B;EACA;EACA;;EAEAlhB,kBAAkB,CAACkhB,SAAS,CAAC;;ECvR7B;EACA;EACA;EACA;EACA;EACA;;EAEA;EACA,MAAMI,sBAAsB,GAAG,gBAAgB;EAExC,MAAMC,gBAAgB,GAAG;EAC9B;EACA,EAAA,GAAG,EAAE,CAAC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAED,sBAAsB,CAAC;IACnEE,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC;EACrCC,EAAAA,IAAI,EAAE,EAAE;EACRC,EAAAA,CAAC,EAAE,EAAE;EACLC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,GAAG,EAAE,EAAE;EACPC,EAAAA,IAAI,EAAE,EAAE;EACRC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,GAAG,EAAE,EAAE;EACPC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,CAAC,EAAE,EAAE;EACL3P,EAAAA,GAAG,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,CAAC;EACzD4P,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,EAAE,EAAE,EAAE;EACNC,EAAAA,CAAC,EAAE,EAAE;EACLC,EAAAA,GAAG,EAAE,EAAE;EACPC,EAAAA,CAAC,EAAE,EAAE;EACLC,EAAAA,KAAK,EAAE,EAAE;EACTC,EAAAA,IAAI,EAAE,EAAE;EACRC,EAAAA,GAAG,EAAE,EAAE;EACPC,EAAAA,GAAG,EAAE,EAAE;EACPC,EAAAA,MAAM,EAAE,EAAE;EACVC,EAAAA,CAAC,EAAE,EAAE;EACLC,EAAAA,EAAE,EAAE;EACN,CAAC;EACD;;EAEA,MAAMC,aAAa,GAAG,IAAI5gB,GAAG,CAAC,CAC5B,YAAY,EACZ,MAAM,EACN,MAAM,EACN,UAAU,EACV,UAAU,EACV,QAAQ,EACR,KAAK,EACL,YAAY,CACb,CAAC;;EAEF;EACA;EACA;EACA;EACA;EACA;EACA,MAAM6gB,gBAAgB,GAAG,yDAAyD;EAElF,MAAMC,gBAAgB,GAAGA,CAACC,SAAS,EAAEC,oBAAoB,KAAK;IAC5D,MAAMC,aAAa,GAAGF,SAAS,CAACG,QAAQ,CAAC3nB,WAAW,EAAE;EAEtD,EAAA,IAAIynB,oBAAoB,CAACve,QAAQ,CAACwe,aAAa,CAAC,EAAE;EAChD,IAAA,IAAIL,aAAa,CAAClpB,GAAG,CAACupB,aAAa,CAAC,EAAE;QACpC,OAAO9e,OAAO,CAAC0e,gBAAgB,CAACva,IAAI,CAACya,SAAS,CAACI,SAAS,CAAC,CAAC;EAC5D,IAAA;EAEA,IAAA,OAAO,IAAI;EACb,EAAA;;EAEA;IACA,OAAOH,oBAAoB,CAAC9b,MAAM,CAACkc,cAAc,IAAIA,cAAc,YAAY/a,MAAM,CAAC,CACnFgb,IAAI,CAACC,KAAK,IAAIA,KAAK,CAAChb,IAAI,CAAC2a,aAAa,CAAC,CAAC;EAC7C,CAAC;EAEM,SAASM,YAAYA,CAACC,UAAU,EAAEC,SAAS,EAAEC,gBAAgB,EAAE;EACpE,EAAA,IAAI,CAACF,UAAU,CAACzmB,MAAM,EAAE;EACtB,IAAA,OAAOymB,UAAU;EACnB,EAAA;EAEA,EAAA,IAAIE,gBAAgB,IAAI,OAAOA,gBAAgB,KAAK,UAAU,EAAE;MAC9D,OAAOA,gBAAgB,CAACF,UAAU,CAAC;EACrC,EAAA;EAEA,EAAA,MAAMG,SAAS,GAAG,IAAIjpB,MAAM,CAACkpB,SAAS,EAAE;IACxC,MAAMC,eAAe,GAAGF,SAAS,CAACG,eAAe,CAACN,UAAU,EAAE,WAAW,CAAC;EAC1E,EAAA,MAAMrH,QAAQ,GAAG,EAAE,CAACpS,MAAM,CAAC,GAAG8Z,eAAe,CAACjlB,IAAI,CAACmE,gBAAgB,CAAC,GAAG,CAAC,CAAC;EAEzE,EAAA,KAAK,MAAMxJ,OAAO,IAAI4iB,QAAQ,EAAE;MAC9B,MAAM4H,WAAW,GAAGxqB,OAAO,CAAC2pB,QAAQ,CAAC3nB,WAAW,EAAE;EAElD,IAAA,IAAI,CAACJ,MAAM,CAACjB,IAAI,CAACupB,SAAS,CAAC,CAAChf,QAAQ,CAACsf,WAAW,CAAC,EAAE;QACjDxqB,OAAO,CAACY,MAAM,EAAE;EAChB,MAAA;EACF,IAAA;MAEA,MAAM6pB,aAAa,GAAG,EAAE,CAACja,MAAM,CAAC,GAAGxQ,OAAO,CAACwN,UAAU,CAAC;EACtD,IAAA,MAAMkd,iBAAiB,GAAG,EAAE,CAACla,MAAM,CAAC0Z,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAEA,SAAS,CAACM,WAAW,CAAC,IAAI,EAAE,CAAC;EAEvF,IAAA,KAAK,MAAMhB,SAAS,IAAIiB,aAAa,EAAE;EACrC,MAAA,IAAI,CAAClB,gBAAgB,CAACC,SAAS,EAAEkB,iBAAiB,CAAC,EAAE;EACnD1qB,QAAAA,OAAO,CAACsN,eAAe,CAACkc,SAAS,CAACG,QAAQ,CAAC;EAC7C,MAAA;EACF,IAAA;EACF,EAAA;EAEA,EAAA,OAAOW,eAAe,CAACjlB,IAAI,CAACslB,SAAS;EACvC;;ECnHA;EACA;EACA;EACA;EACA;EACA;;;EAOA;EACA;EACA;;EAEA,MAAMzkB,MAAI,GAAG,iBAAiB;EAE9B,MAAM8H,SAAO,GAAG;EACdkc,EAAAA,SAAS,EAAE7C,gBAAgB;IAC3BuD,OAAO,EAAE,EAAE;EAAE;EACbC,EAAAA,UAAU,EAAE,EAAE;EACdC,EAAAA,IAAI,EAAE,KAAK;EACXC,EAAAA,QAAQ,EAAE,IAAI;EACdC,EAAAA,UAAU,EAAE,IAAI;EAChBC,EAAAA,QAAQ,EAAE;EACZ,CAAC;EAED,MAAMhd,aAAW,GAAG;EAClBic,EAAAA,SAAS,EAAE,QAAQ;EACnBU,EAAAA,OAAO,EAAE,QAAQ;EACjBC,EAAAA,UAAU,EAAE,mBAAmB;EAC/BC,EAAAA,IAAI,EAAE,SAAS;EACfC,EAAAA,QAAQ,EAAE,SAAS;EACnBC,EAAAA,UAAU,EAAE,iBAAiB;EAC7BC,EAAAA,QAAQ,EAAE;EACZ,CAAC;EAED,MAAMC,kBAAkB,GAAG;EACzBC,EAAAA,KAAK,EAAE,gCAAgC;EACvCjqB,EAAAA,QAAQ,EAAE;EACZ,CAAC;;EAED;EACA;EACA;;EAEA,MAAMkqB,eAAe,SAASrd,MAAM,CAAC;IACnCU,WAAWA,CAACL,MAAM,EAAE;EAClB,IAAA,KAAK,EAAE;MACP,IAAI,CAACiB,OAAO,GAAG,IAAI,CAAClB,UAAU,CAACC,MAAM,CAAC;EACxC,EAAA;;EAEA;IACA,WAAWJ,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACAmlB,EAAAA,UAAUA,GAAG;MACX,OAAOzpB,MAAM,CAACkI,MAAM,CAAC,IAAI,CAACuF,OAAO,CAACub,OAAO,CAAC,CACvCxa,GAAG,CAAChC,MAAM,IAAI,IAAI,CAACkd,wBAAwB,CAACld,MAAM,CAAC,CAAC,CACpDT,MAAM,CAAC/C,OAAO,CAAC;EACpB,EAAA;EAEA2gB,EAAAA,UAAUA,GAAG;MACX,OAAO,IAAI,CAACF,UAAU,EAAE,CAAC7nB,MAAM,GAAG,CAAC;EACrC,EAAA;IAEAgoB,aAAaA,CAACZ,OAAO,EAAE;EACrB,IAAA,IAAI,CAACa,aAAa,CAACb,OAAO,CAAC;EAC3B,IAAA,IAAI,CAACvb,OAAO,CAACub,OAAO,GAAG;EAAE,MAAA,GAAG,IAAI,CAACvb,OAAO,CAACub,OAAO;QAAE,GAAGA;OAAS;EAC9D,IAAA,OAAO,IAAI;EACb,EAAA;EAEAc,EAAAA,MAAMA,GAAG;EACP,IAAA,MAAMC,eAAe,GAAGrpB,QAAQ,CAACuf,aAAa,CAAC,KAAK,CAAC;EACrD8J,IAAAA,eAAe,CAAChB,SAAS,GAAG,IAAI,CAACiB,cAAc,CAAC,IAAI,CAACvc,OAAO,CAAC4b,QAAQ,CAAC;EAEtE,IAAA,KAAK,MAAM,CAAC/pB,QAAQ,EAAE2qB,IAAI,CAAC,IAAIjqB,MAAM,CAACqJ,OAAO,CAAC,IAAI,CAACoE,OAAO,CAACub,OAAO,CAAC,EAAE;QACnE,IAAI,CAACkB,WAAW,CAACH,eAAe,EAAEE,IAAI,EAAE3qB,QAAQ,CAAC;EACnD,IAAA;EAEA,IAAA,MAAM+pB,QAAQ,GAAGU,eAAe,CAAChb,QAAQ,CAAC,CAAC,CAAC;MAC5C,MAAMka,UAAU,GAAG,IAAI,CAACS,wBAAwB,CAAC,IAAI,CAACjc,OAAO,CAACwb,UAAU,CAAC;EAEzE,IAAA,IAAIA,UAAU,EAAE;EACdI,MAAAA,QAAQ,CAAC5mB,SAAS,CAACwQ,GAAG,CAAC,GAAGgW,UAAU,CAAC7nB,KAAK,CAAC,GAAG,CAAC,CAAC;EAClD,IAAA;EAEA,IAAA,OAAOioB,QAAQ;EACjB,EAAA;;EAEA;IACA1c,gBAAgBA,CAACH,MAAM,EAAE;EACvB,IAAA,KAAK,CAACG,gBAAgB,CAACH,MAAM,CAAC;EAC9B,IAAA,IAAI,CAACqd,aAAa,CAACrd,MAAM,CAACwc,OAAO,CAAC;EACpC,EAAA;IAEAa,aAAaA,CAACM,GAAG,EAAE;EACjB,IAAA,KAAK,MAAM,CAAC7qB,QAAQ,EAAE0pB,OAAO,CAAC,IAAIhpB,MAAM,CAACqJ,OAAO,CAAC8gB,GAAG,CAAC,EAAE;QACrD,KAAK,CAACxd,gBAAgB,CAAC;UAAErN,QAAQ;EAAEiqB,QAAAA,KAAK,EAAEP;SAAS,EAAEM,kBAAkB,CAAC;EAC1E,IAAA;EACF,EAAA;EAEAY,EAAAA,WAAWA,CAACb,QAAQ,EAAEL,OAAO,EAAE1pB,QAAQ,EAAE;MACvC,MAAM8qB,eAAe,GAAGzb,cAAc,CAACG,OAAO,CAACxP,QAAQ,EAAE+pB,QAAQ,CAAC;MAElE,IAAI,CAACe,eAAe,EAAE;EACpB,MAAA;EACF,IAAA;EAEApB,IAAAA,OAAO,GAAG,IAAI,CAACU,wBAAwB,CAACV,OAAO,CAAC;MAEhD,IAAI,CAACA,OAAO,EAAE;QACZoB,eAAe,CAACprB,MAAM,EAAE;EACxB,MAAA;EACF,IAAA;EAEA,IAAA,IAAIwC,SAAS,CAACwnB,OAAO,CAAC,EAAE;QACtB,IAAI,CAACqB,qBAAqB,CAAC1oB,UAAU,CAACqnB,OAAO,CAAC,EAAEoB,eAAe,CAAC;EAChE,MAAA;EACF,IAAA;EAEA,IAAA,IAAI,IAAI,CAAC3c,OAAO,CAACyb,IAAI,EAAE;QACrBkB,eAAe,CAACrB,SAAS,GAAG,IAAI,CAACiB,cAAc,CAAChB,OAAO,CAAC;EACxD,MAAA;EACF,IAAA;MAEAoB,eAAe,CAACE,WAAW,GAAGtB,OAAO;EACvC,EAAA;IAEAgB,cAAcA,CAACG,GAAG,EAAE;MAClB,OAAO,IAAI,CAAC1c,OAAO,CAAC0b,QAAQ,GAAGf,YAAY,CAAC+B,GAAG,EAAE,IAAI,CAAC1c,OAAO,CAAC6a,SAAS,EAAE,IAAI,CAAC7a,OAAO,CAAC2b,UAAU,CAAC,GAAGe,GAAG;EACzG,EAAA;IAEAT,wBAAwBA,CAACS,GAAG,EAAE;MAC5B,OAAOvlB,OAAO,CAACulB,GAAG,EAAE,CAACpqB,SAAS,EAAE,IAAI,CAAC,CAAC;EACxC,EAAA;EAEAsqB,EAAAA,qBAAqBA,CAACjsB,OAAO,EAAEgsB,eAAe,EAAE;EAC9C,IAAA,IAAI,IAAI,CAAC3c,OAAO,CAACyb,IAAI,EAAE;QACrBkB,eAAe,CAACrB,SAAS,GAAG,EAAE;EAC9BqB,MAAAA,eAAe,CAAClK,MAAM,CAAC9hB,OAAO,CAAC;EAC/B,MAAA;EACF,IAAA;EAEAgsB,IAAAA,eAAe,CAACE,WAAW,GAAGlsB,OAAO,CAACksB,WAAW;EACnD,EAAA;EACF;;EC7JA;EACA;EACA;EACA;EACA;EACA;;;EAYA;EACA;EACA;;EAEA,MAAMhmB,MAAI,GAAG,SAAS;EACtB,MAAMimB,qBAAqB,GAAG,IAAI1jB,GAAG,CAAC,CAAC,UAAU,EAAE,WAAW,EAAE,YAAY,CAAC,CAAC;EAE9E,MAAMyJ,iBAAe,GAAG,MAAM;EAC9B,MAAMka,gBAAgB,GAAG,OAAO;EAChC,MAAMja,iBAAe,GAAG,MAAM;EAE9B,MAAMka,sBAAsB,GAAG,gBAAgB;EAC/C,MAAMC,cAAc,GAAG,CAAA,CAAA,EAAIF,gBAAgB,CAAA,CAAE;EAE7C,MAAMG,gBAAgB,GAAG,eAAe;EAExC,MAAMC,aAAa,GAAG,OAAO;EAC7B,MAAMC,aAAa,GAAG,OAAO;EAC7B,MAAMC,aAAa,GAAG,OAAO;EAC7B,MAAMC,cAAc,GAAG,QAAQ;EAE/B,MAAMnS,YAAU,GAAG,MAAM;EACzB,MAAMC,cAAY,GAAG,QAAQ;EAC7B,MAAMH,YAAU,GAAG,MAAM;EACzB,MAAMC,aAAW,GAAG,OAAO;EAC3B,MAAMqS,cAAc,GAAG,UAAU;EACjC,MAAMC,aAAW,GAAG,OAAO;EAC3B,MAAM9K,eAAa,GAAG,SAAS;EAC/B,MAAM+K,gBAAc,GAAG,UAAU;EACjC,MAAMnX,gBAAgB,GAAG,YAAY;EACrC,MAAMC,gBAAgB,GAAG,YAAY;EAErC,MAAMmX,aAAa,GAAG;EACpBC,EAAAA,IAAI,EAAE,MAAM;EACZC,EAAAA,GAAG,EAAE,KAAK;EACVC,EAAAA,KAAK,EAAEtnB,KAAK,EAAE,GAAG,MAAM,GAAG,OAAO;EACjCunB,EAAAA,MAAM,EAAE,QAAQ;EAChBC,EAAAA,IAAI,EAAExnB,KAAK,EAAE,GAAG,OAAO,GAAG;EAC5B,CAAC;EAED,MAAMoI,SAAO,GAAG;EACdkc,EAAAA,SAAS,EAAE7C,gBAAgB;EAC3BgG,EAAAA,SAAS,EAAE,IAAI;EACf9O,EAAAA,QAAQ,EAAE,iBAAiB;EAC3B+O,EAAAA,SAAS,EAAE,KAAK;EAChBC,EAAAA,WAAW,EAAE,EAAE;EACfC,EAAAA,KAAK,EAAE,CAAC;IACRC,kBAAkB,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,CAAC;EACtD3C,EAAAA,IAAI,EAAE,KAAK;EACXrM,EAAAA,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;EACd0B,EAAAA,SAAS,EAAE,KAAK;EAChBzB,EAAAA,YAAY,EAAE,IAAI;EAClBqM,EAAAA,QAAQ,EAAE,IAAI;EACdC,EAAAA,UAAU,EAAE,IAAI;EAChB9pB,EAAAA,QAAQ,EAAE,KAAK;EACf+pB,EAAAA,QAAQ,EAAE,sCAAsC,GACtC,mCAAmC,GACnC,mCAAmC,GACnC,QAAQ;EAClByC,EAAAA,KAAK,EAAE,EAAE;EACT/hB,EAAAA,OAAO,EAAE;EACX,CAAC;EAED,MAAMsC,aAAW,GAAG;EAClBic,EAAAA,SAAS,EAAE,QAAQ;EACnBmD,EAAAA,SAAS,EAAE,SAAS;EACpB9O,EAAAA,QAAQ,EAAE,kBAAkB;EAC5B+O,EAAAA,SAAS,EAAE,0BAA0B;EACrCC,EAAAA,WAAW,EAAE,mBAAmB;EAChCC,EAAAA,KAAK,EAAE,iBAAiB;EACxBC,EAAAA,kBAAkB,EAAE,OAAO;EAC3B3C,EAAAA,IAAI,EAAE,SAAS;EACfrM,EAAAA,MAAM,EAAE,yBAAyB;EACjC0B,EAAAA,SAAS,EAAE,mBAAmB;EAC9BzB,EAAAA,YAAY,EAAE,wBAAwB;EACtCqM,EAAAA,QAAQ,EAAE,SAAS;EACnBC,EAAAA,UAAU,EAAE,iBAAiB;EAC7B9pB,EAAAA,QAAQ,EAAE,kBAAkB;EAC5B+pB,EAAAA,QAAQ,EAAE,QAAQ;EAClByC,EAAAA,KAAK,EAAE,2BAA2B;EAClC/hB,EAAAA,OAAO,EAAE;EACX,CAAC;;EAED;EACA;EACA;;EAEA,MAAMgiB,OAAO,SAASxe,aAAa,CAAC;EAClCV,EAAAA,WAAWA,CAACzO,OAAO,EAAEoO,MAAM,EAAE;EAC3B,IAAA,IAAI,OAAOqR,iBAAM,KAAK,WAAW,EAAE;EACjC,MAAA,MAAM,IAAIzQ,SAAS,CAAC,uEAAuE,CAAC;EAC9F,IAAA;EAEA,IAAA,KAAK,CAAChP,OAAO,EAAEoO,MAAM,CAAC;;EAEtB;MACA,IAAI,CAACwf,UAAU,GAAG,IAAI;MACtB,IAAI,CAACC,QAAQ,GAAG,CAAC;MACjB,IAAI,CAACC,UAAU,GAAG,IAAI;EACtB,IAAA,IAAI,CAACC,cAAc,GAAG,EAAE;MACxB,IAAI,CAAClP,OAAO,GAAG,IAAI;MACnB,IAAI,CAACmP,gBAAgB,GAAG,IAAI;MAC5B,IAAI,CAACC,WAAW,GAAG,IAAI;;EAEvB;MACA,IAAI,CAACC,GAAG,GAAG,IAAI;MAEf,IAAI,CAACC,aAAa,EAAE;EAEpB,IAAA,IAAI,CAAC,IAAI,CAAC9e,OAAO,CAACnO,QAAQ,EAAE;QAC1B,IAAI,CAACktB,SAAS,EAAE;EAClB,IAAA;EACF,EAAA;;EAEA;IACA,WAAWpgB,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACAmoB,EAAAA,MAAMA,GAAG;MACP,IAAI,CAACT,UAAU,GAAG,IAAI;EACxB,EAAA;EAEAU,EAAAA,OAAOA,GAAG;MACR,IAAI,CAACV,UAAU,GAAG,KAAK;EACzB,EAAA;EAEAW,EAAAA,aAAaA,GAAG;EACd,IAAA,IAAI,CAACX,UAAU,GAAG,CAAC,IAAI,CAACA,UAAU;EACpC,EAAA;EAEA7a,EAAAA,MAAMA,GAAG;EACP,IAAA,IAAI,CAAC,IAAI,CAAC6a,UAAU,EAAE;EACpB,MAAA;EACF,IAAA;EAEA,IAAA,IAAI,IAAI,CAAChS,QAAQ,EAAE,EAAE;QACnB,IAAI,CAAC4S,MAAM,EAAE;EACb,MAAA;EACF,IAAA;MAEA,IAAI,CAACC,MAAM,EAAE;EACf,EAAA;EAEAjf,EAAAA,OAAOA,GAAG;EACRuJ,IAAAA,YAAY,CAAC,IAAI,CAAC8U,QAAQ,CAAC;EAE3B3kB,IAAAA,YAAY,CAACC,GAAG,CAAC,IAAI,CAACiG,QAAQ,CAACrL,OAAO,CAACuoB,cAAc,CAAC,EAAEC,gBAAgB,EAAE,IAAI,CAACmC,iBAAiB,CAAC;MAEjG,IAAI,IAAI,CAACtf,QAAQ,CAAC3K,YAAY,CAAC,wBAAwB,CAAC,EAAE;EACxD,MAAA,IAAI,CAAC2K,QAAQ,CAAChC,YAAY,CAAC,OAAO,EAAE,IAAI,CAACgC,QAAQ,CAAC3K,YAAY,CAAC,wBAAwB,CAAC,CAAC;EAC3F,IAAA;MAEA,IAAI,CAACkqB,cAAc,EAAE;MACrB,KAAK,CAACnf,OAAO,EAAE;EACjB,EAAA;EAEAsM,EAAAA,IAAIA,GAAG;MACL,IAAI,IAAI,CAAC1M,QAAQ,CAACiN,KAAK,CAACmC,OAAO,KAAK,MAAM,EAAE;EAC1C,MAAA,MAAM,IAAItQ,KAAK,CAAC,qCAAqC,CAAC;EACxD,IAAA;MAEA,IAAI,EAAE,IAAI,CAAC0gB,cAAc,EAAE,IAAI,IAAI,CAAChB,UAAU,CAAC,EAAE;EAC/C,MAAA;EACF,IAAA;EAEA,IAAA,MAAM1O,SAAS,GAAGhW,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAE,IAAI,CAACX,WAAW,CAACuB,SAAS,CAACsK,YAAU,CAAC,CAAC;EAC7F,IAAA,MAAMuU,UAAU,GAAGnqB,cAAc,CAAC,IAAI,CAAC0K,QAAQ,CAAC;EAChD,IAAA,MAAM0f,UAAU,GAAG,CAACD,UAAU,IAAI,IAAI,CAACzf,QAAQ,CAAC2f,aAAa,CAACpqB,eAAe,EAAEL,QAAQ,CAAC,IAAI,CAAC8K,QAAQ,CAAC;EAEtG,IAAA,IAAI8P,SAAS,CAACnT,gBAAgB,IAAI,CAAC+iB,UAAU,EAAE;EAC7C,MAAA;EACF,IAAA;;EAEA;MACA,IAAI,CAACH,cAAc,EAAE;EAErB,IAAA,MAAMT,GAAG,GAAG,IAAI,CAACc,cAAc,EAAE;EAEjC,IAAA,IAAI,CAAC5f,QAAQ,CAAChC,YAAY,CAAC,kBAAkB,EAAE8gB,GAAG,CAACzpB,YAAY,CAAC,IAAI,CAAC,CAAC;MAEtE,MAAM;EAAE6oB,MAAAA;OAAW,GAAG,IAAI,CAACje,OAAO;EAElC,IAAA,IAAI,CAAC,IAAI,CAACD,QAAQ,CAAC2f,aAAa,CAACpqB,eAAe,CAACL,QAAQ,CAAC,IAAI,CAAC4pB,GAAG,CAAC,EAAE;EACnEZ,MAAAA,SAAS,CAACxL,MAAM,CAACoM,GAAG,CAAC;EACrBhlB,MAAAA,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAE,IAAI,CAACX,WAAW,CAACuB,SAAS,CAAC4c,cAAc,CAAC,CAAC;EACjF,IAAA;MAEA,IAAI,CAAC/N,OAAO,GAAG,IAAI,CAACM,aAAa,CAAC+O,GAAG,CAAC;EAEtCA,IAAAA,GAAG,CAAC7pB,SAAS,CAACwQ,GAAG,CAAC1C,iBAAe,CAAC;;EAElC;EACA;EACA;EACA;EACA,IAAA,IAAI,cAAc,IAAI7P,QAAQ,CAACqC,eAAe,EAAE;EAC9C,MAAA,KAAK,MAAM3E,OAAO,IAAI,EAAE,CAACwQ,MAAM,CAAC,GAAGlO,QAAQ,CAAC+C,IAAI,CAACsL,QAAQ,CAAC,EAAE;UAC1DzH,YAAY,CAACiC,EAAE,CAACnL,OAAO,EAAE,WAAW,EAAEgF,IAAI,CAAC;EAC7C,MAAA;EACF,IAAA;MAEA,MAAMsX,QAAQ,GAAGA,MAAM;EACrBpT,MAAAA,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAE,IAAI,CAACX,WAAW,CAACuB,SAAS,CAACuK,aAAW,CAAC,CAAC;EAE5E,MAAA,IAAI,IAAI,CAACuT,UAAU,KAAK,KAAK,EAAE;UAC7B,IAAI,CAACU,MAAM,EAAE;EACf,MAAA;QAEA,IAAI,CAACV,UAAU,GAAG,KAAK;MACzB,CAAC;EAED,IAAA,IAAI,CAACle,cAAc,CAAC0M,QAAQ,EAAE,IAAI,CAAC4R,GAAG,EAAE,IAAI,CAACjU,WAAW,EAAE,CAAC;EAC7D,EAAA;EAEA4B,EAAAA,IAAIA,GAAG;EACL,IAAA,IAAI,CAAC,IAAI,CAACD,QAAQ,EAAE,EAAE;EACpB,MAAA;EACF,IAAA;EAEA,IAAA,MAAM4D,SAAS,GAAGtW,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAE,IAAI,CAACX,WAAW,CAACuB,SAAS,CAACwK,YAAU,CAAC,CAAC;MAC7F,IAAIgF,SAAS,CAACzT,gBAAgB,EAAE;EAC9B,MAAA;EACF,IAAA;EAEA,IAAA,MAAMmiB,GAAG,GAAG,IAAI,CAACc,cAAc,EAAE;EACjCd,IAAAA,GAAG,CAAC7pB,SAAS,CAACzD,MAAM,CAACuR,iBAAe,CAAC;;EAErC;EACA;EACA,IAAA,IAAI,cAAc,IAAI7P,QAAQ,CAACqC,eAAe,EAAE;EAC9C,MAAA,KAAK,MAAM3E,OAAO,IAAI,EAAE,CAACwQ,MAAM,CAAC,GAAGlO,QAAQ,CAAC+C,IAAI,CAACsL,QAAQ,CAAC,EAAE;UAC1DzH,YAAY,CAACC,GAAG,CAACnJ,OAAO,EAAE,WAAW,EAAEgF,IAAI,CAAC;EAC9C,MAAA;EACF,IAAA;EAEA,IAAA,IAAI,CAAC+oB,cAAc,CAACrB,aAAa,CAAC,GAAG,KAAK;EAC1C,IAAA,IAAI,CAACqB,cAAc,CAACtB,aAAa,CAAC,GAAG,KAAK;EAC1C,IAAA,IAAI,CAACsB,cAAc,CAACvB,aAAa,CAAC,GAAG,KAAK;EAC1C,IAAA,IAAI,CAACsB,UAAU,GAAG,IAAI,CAAA;;MAEtB,MAAMxR,QAAQ,GAAGA,MAAM;EACrB,MAAA,IAAI,IAAI,CAAC2S,oBAAoB,EAAE,EAAE;EAC/B,QAAA;EACF,MAAA;EAEA,MAAA,IAAI,CAAC,IAAI,CAACnB,UAAU,EAAE;UACpB,IAAI,CAACa,cAAc,EAAE;EACvB,MAAA;EAEA,MAAA,IAAI,CAACvf,QAAQ,CAAC9B,eAAe,CAAC,kBAAkB,CAAC;EACjDpE,MAAAA,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAE,IAAI,CAACX,WAAW,CAACuB,SAAS,CAACyK,cAAY,CAAC,CAAC;MAC/E,CAAC;EAED,IAAA,IAAI,CAAC7K,cAAc,CAAC0M,QAAQ,EAAE,IAAI,CAAC4R,GAAG,EAAE,IAAI,CAACjU,WAAW,EAAE,CAAC;EAC7D,EAAA;EAEAsF,EAAAA,MAAMA,GAAG;MACP,IAAI,IAAI,CAACV,OAAO,EAAE;EAChB,MAAA,IAAI,CAACA,OAAO,CAACU,MAAM,EAAE;EACvB,IAAA;EACF,EAAA;;EAEA;EACAqP,EAAAA,cAAcA,GAAG;EACf,IAAA,OAAOhkB,OAAO,CAAC,IAAI,CAACskB,SAAS,EAAE,CAAC;EAClC,EAAA;EAEAF,EAAAA,cAAcA,GAAG;EACf,IAAA,IAAI,CAAC,IAAI,CAACd,GAAG,EAAE;EACb,MAAA,IAAI,CAACA,GAAG,GAAG,IAAI,CAACiB,iBAAiB,CAAC,IAAI,CAAClB,WAAW,IAAI,IAAI,CAACmB,sBAAsB,EAAE,CAAC;EACtF,IAAA;MAEA,OAAO,IAAI,CAAClB,GAAG;EACjB,EAAA;IAEAiB,iBAAiBA,CAACvE,OAAO,EAAE;MACzB,MAAMsD,GAAG,GAAG,IAAI,CAACmB,mBAAmB,CAACzE,OAAO,CAAC,CAACc,MAAM,EAAE;;EAEtD;MACA,IAAI,CAACwC,GAAG,EAAE;EACR,MAAA,OAAO,IAAI;EACb,IAAA;MAEAA,GAAG,CAAC7pB,SAAS,CAACzD,MAAM,CAACsR,iBAAe,EAAEC,iBAAe,CAAC;EACtD;EACA+b,IAAAA,GAAG,CAAC7pB,SAAS,CAACwQ,GAAG,CAAC,CAAA,GAAA,EAAM,IAAI,CAACpG,WAAW,CAACvI,IAAI,CAAA,KAAA,CAAO,CAAC;EAErD,IAAA,MAAMopB,KAAK,GAAGrtB,MAAM,CAAC,IAAI,CAACwM,WAAW,CAACvI,IAAI,CAAC,CAACpE,QAAQ,EAAE;EAEtDosB,IAAAA,GAAG,CAAC9gB,YAAY,CAAC,IAAI,EAAEkiB,KAAK,CAAC;EAE7B,IAAA,IAAI,IAAI,CAACrV,WAAW,EAAE,EAAE;EACtBiU,MAAAA,GAAG,CAAC7pB,SAAS,CAACwQ,GAAG,CAAC3C,iBAAe,CAAC;EACpC,IAAA;EAEA,IAAA,OAAOgc,GAAG;EACZ,EAAA;IAEAqB,UAAUA,CAAC3E,OAAO,EAAE;MAClB,IAAI,CAACqD,WAAW,GAAGrD,OAAO;EAC1B,IAAA,IAAI,IAAI,CAAChP,QAAQ,EAAE,EAAE;QACnB,IAAI,CAAC+S,cAAc,EAAE;QACrB,IAAI,CAAC7S,IAAI,EAAE;EACb,IAAA;EACF,EAAA;IAEAuT,mBAAmBA,CAACzE,OAAO,EAAE;MAC3B,IAAI,IAAI,CAACoD,gBAAgB,EAAE;EACzB,MAAA,IAAI,CAACA,gBAAgB,CAACxC,aAAa,CAACZ,OAAO,CAAC;EAC9C,IAAA,CAAC,MAAM;EACL,MAAA,IAAI,CAACoD,gBAAgB,GAAG,IAAI5C,eAAe,CAAC;UAC1C,GAAG,IAAI,CAAC/b,OAAO;EACf;EACA;UACAub,OAAO;UACPC,UAAU,EAAE,IAAI,CAACS,wBAAwB,CAAC,IAAI,CAACjc,OAAO,CAACke,WAAW;EACpE,OAAC,CAAC;EACJ,IAAA;MAEA,OAAO,IAAI,CAACS,gBAAgB;EAC9B,EAAA;EAEAoB,EAAAA,sBAAsBA,GAAG;MACvB,OAAO;EACL,MAAA,CAAC/C,sBAAsB,GAAG,IAAI,CAAC6C,SAAS;OACzC;EACH,EAAA;EAEAA,EAAAA,SAASA,GAAG;EACV,IAAA,OAAO,IAAI,CAAC5D,wBAAwB,CAAC,IAAI,CAACjc,OAAO,CAACqe,KAAK,CAAC,IAAI,IAAI,CAACte,QAAQ,CAAC3K,YAAY,CAAC,wBAAwB,CAAC;EAClH,EAAA;;EAEA;IACA+qB,4BAA4BA,CAAC1mB,KAAK,EAAE;EAClC,IAAA,OAAO,IAAI,CAAC2F,WAAW,CAACsB,mBAAmB,CAACjH,KAAK,CAACE,cAAc,EAAE,IAAI,CAACymB,kBAAkB,EAAE,CAAC;EAC9F,EAAA;EAEAxV,EAAAA,WAAWA,GAAG;EACZ,IAAA,OAAO,IAAI,CAAC5K,OAAO,CAACge,SAAS,IAAK,IAAI,CAACa,GAAG,IAAI,IAAI,CAACA,GAAG,CAAC7pB,SAAS,CAACC,QAAQ,CAAC4N,iBAAe,CAAE;EAC7F,EAAA;EAEA0J,EAAAA,QAAQA,GAAG;EACT,IAAA,OAAO,IAAI,CAACsS,GAAG,IAAI,IAAI,CAACA,GAAG,CAAC7pB,SAAS,CAACC,QAAQ,CAAC6N,iBAAe,CAAC;EACjE,EAAA;IAEAgN,aAAaA,CAAC+O,GAAG,EAAE;EACjB,IAAA,MAAM/N,SAAS,GAAG3Z,OAAO,CAAC,IAAI,CAAC6I,OAAO,CAAC8Q,SAAS,EAAE,CAAC,IAAI,EAAE+N,GAAG,EAAE,IAAI,CAAC9e,QAAQ,CAAC,CAAC;MAC7E,MAAMsgB,UAAU,GAAG3C,aAAa,CAAC5M,SAAS,CAAClR,WAAW,EAAE,CAAC;EACzD,IAAA,OAAOwQ,iBAAM,CAACG,YAAY,CAAC,IAAI,CAACxQ,QAAQ,EAAE8e,GAAG,EAAE,IAAI,CAACvO,gBAAgB,CAAC+P,UAAU,CAAC,CAAC;EACnF,EAAA;EAEA1P,EAAAA,UAAUA,GAAG;MACX,MAAM;EAAEvB,MAAAA;OAAQ,GAAG,IAAI,CAACpP,OAAO;EAE/B,IAAA,IAAI,OAAOoP,MAAM,KAAK,QAAQ,EAAE;EAC9B,MAAA,OAAOA,MAAM,CAACzb,KAAK,CAAC,GAAG,CAAC,CAACoN,GAAG,CAAC5D,KAAK,IAAI3J,MAAM,CAACyW,QAAQ,CAAC9M,KAAK,EAAE,EAAE,CAAC,CAAC;EACnE,IAAA;EAEA,IAAA,IAAI,OAAOiS,MAAM,KAAK,UAAU,EAAE;QAChC,OAAOwB,UAAU,IAAIxB,MAAM,CAACwB,UAAU,EAAE,IAAI,CAAC7Q,QAAQ,CAAC;EACxD,IAAA;EAEA,IAAA,OAAOqP,MAAM;EACf,EAAA;IAEA6M,wBAAwBA,CAACS,GAAG,EAAE;EAC5B,IAAA,OAAOvlB,OAAO,CAACulB,GAAG,EAAE,CAAC,IAAI,CAAC3c,QAAQ,EAAE,IAAI,CAACA,QAAQ,CAAC,CAAC;EACrD,EAAA;IAEAuQ,gBAAgBA,CAAC+P,UAAU,EAAE;EAC3B,IAAA,MAAMxP,qBAAqB,GAAG;EAC5BC,MAAAA,SAAS,EAAEuP,UAAU;EACrBtP,MAAAA,SAAS,EAAE,CACT;EACEna,QAAAA,IAAI,EAAE,MAAM;EACZoa,QAAAA,OAAO,EAAE;EACPoN,UAAAA,kBAAkB,EAAE,IAAI,CAACpe,OAAO,CAACoe;EACnC;EACF,OAAC,EACD;EACExnB,QAAAA,IAAI,EAAE,QAAQ;EACdoa,QAAAA,OAAO,EAAE;EACP5B,UAAAA,MAAM,EAAE,IAAI,CAACuB,UAAU;EACzB;EACF,OAAC,EACD;EACE/Z,QAAAA,IAAI,EAAE,iBAAiB;EACvBoa,QAAAA,OAAO,EAAE;EACP9B,UAAAA,QAAQ,EAAE,IAAI,CAAClP,OAAO,CAACkP;EACzB;EACF,OAAC,EACD;EACEtY,QAAAA,IAAI,EAAE,OAAO;EACboa,QAAAA,OAAO,EAAE;EACPrgB,UAAAA,OAAO,EAAE,CAAA,CAAA,EAAI,IAAI,CAACyO,WAAW,CAACvI,IAAI,CAAA,MAAA;EACpC;EACF,OAAC,EACD;EACED,QAAAA,IAAI,EAAE,iBAAiB;EACvBqa,QAAAA,OAAO,EAAE,IAAI;EACbqP,QAAAA,KAAK,EAAE,YAAY;UACnBvpB,EAAE,EAAEqM,IAAI,IAAI;EACV;EACA;EACA,UAAA,IAAI,CAACuc,cAAc,EAAE,CAAC5hB,YAAY,CAAC,uBAAuB,EAAEqF,IAAI,CAACmd,KAAK,CAACzP,SAAS,CAAC;EACnF,QAAA;SACD;OAEJ;MAED,OAAO;EACL,MAAA,GAAGD,qBAAqB;EACxB,MAAA,GAAG1Z,OAAO,CAAC,IAAI,CAAC6I,OAAO,CAACqP,YAAY,EAAE,CAAC/c,SAAS,EAAEue,qBAAqB,CAAC;OACzE;EACH,EAAA;EAEAiO,EAAAA,aAAaA,GAAG;MACd,MAAM0B,QAAQ,GAAG,IAAI,CAACxgB,OAAO,CAAC1D,OAAO,CAAC3I,KAAK,CAAC,GAAG,CAAC;EAEhD,IAAA,KAAK,MAAM2I,OAAO,IAAIkkB,QAAQ,EAAE;QAC9B,IAAIlkB,OAAO,KAAK,OAAO,EAAE;UACvBzC,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAE,IAAI,CAACX,WAAW,CAACuB,SAAS,CAAC6c,aAAW,CAAC,EAAE,IAAI,CAACxd,OAAO,CAACnO,QAAQ,EAAE4H,KAAK,IAAI;EACtG,UAAA,MAAM4X,OAAO,GAAG,IAAI,CAAC8O,4BAA4B,CAAC1mB,KAAK,CAAC;EACxD4X,UAAAA,OAAO,CAACqN,cAAc,CAACrB,aAAa,CAAC,GAAG,EAAEhM,OAAO,CAAC9E,QAAQ,EAAE,IAAI8E,OAAO,CAACqN,cAAc,CAACrB,aAAa,CAAC,CAAC;YACtGhM,OAAO,CAAC3N,MAAM,EAAE;EAClB,QAAA,CAAC,CAAC;EACJ,MAAA,CAAC,MAAM,IAAIpH,OAAO,KAAKghB,cAAc,EAAE;UACrC,MAAMmD,OAAO,GAAGnkB,OAAO,KAAK6gB,aAAa,GACvC,IAAI,CAAC/d,WAAW,CAACuB,SAAS,CAAC2F,gBAAgB,CAAC,GAC5C,IAAI,CAAClH,WAAW,CAACuB,SAAS,CAAC+R,eAAa,CAAC;UAC3C,MAAMgO,QAAQ,GAAGpkB,OAAO,KAAK6gB,aAAa,GACxC,IAAI,CAAC/d,WAAW,CAACuB,SAAS,CAAC4F,gBAAgB,CAAC,GAC5C,IAAI,CAACnH,WAAW,CAACuB,SAAS,CAAC8c,gBAAc,CAAC;EAE5C5jB,QAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAE0gB,OAAO,EAAE,IAAI,CAACzgB,OAAO,CAACnO,QAAQ,EAAE4H,KAAK,IAAI;EACtE,UAAA,MAAM4X,OAAO,GAAG,IAAI,CAAC8O,4BAA4B,CAAC1mB,KAAK,CAAC;EACxD4X,UAAAA,OAAO,CAACqN,cAAc,CAACjlB,KAAK,CAACM,IAAI,KAAK,SAAS,GAAGqjB,aAAa,GAAGD,aAAa,CAAC,GAAG,IAAI;YACvF9L,OAAO,CAAC+N,MAAM,EAAE;EAClB,QAAA,CAAC,CAAC;EACFvlB,QAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAE2gB,QAAQ,EAAE,IAAI,CAAC1gB,OAAO,CAACnO,QAAQ,EAAE4H,KAAK,IAAI;EACvE,UAAA,MAAM4X,OAAO,GAAG,IAAI,CAAC8O,4BAA4B,CAAC1mB,KAAK,CAAC;YACxD4X,OAAO,CAACqN,cAAc,CAACjlB,KAAK,CAACM,IAAI,KAAK,UAAU,GAAGqjB,aAAa,GAAGD,aAAa,CAAC,GAC/E9L,OAAO,CAACtR,QAAQ,CAAC9K,QAAQ,CAACwE,KAAK,CAAC0B,aAAa,CAAC;YAEhDkW,OAAO,CAAC8N,MAAM,EAAE;EAClB,QAAA,CAAC,CAAC;EACJ,MAAA;EACF,IAAA;MAEA,IAAI,CAACE,iBAAiB,GAAG,MAAM;QAC7B,IAAI,IAAI,CAACtf,QAAQ,EAAE;UACjB,IAAI,CAACyM,IAAI,EAAE;EACb,MAAA;MACF,CAAC;EAED3S,IAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,CAACrL,OAAO,CAACuoB,cAAc,CAAC,EAAEC,gBAAgB,EAAE,IAAI,CAACmC,iBAAiB,CAAC;EAClG,EAAA;EAEAN,EAAAA,SAASA,GAAG;MACV,MAAMV,KAAK,GAAG,IAAI,CAACte,QAAQ,CAAC3K,YAAY,CAAC,OAAO,CAAC;MAEjD,IAAI,CAACipB,KAAK,EAAE;EACV,MAAA;EACF,IAAA;MAEA,IAAI,CAAC,IAAI,CAACte,QAAQ,CAAC3K,YAAY,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC2K,QAAQ,CAAC8c,WAAW,CAAC/b,IAAI,EAAE,EAAE;QAClF,IAAI,CAACf,QAAQ,CAAChC,YAAY,CAAC,YAAY,EAAEsgB,KAAK,CAAC;EACjD,IAAA;MAEA,IAAI,CAACte,QAAQ,CAAChC,YAAY,CAAC,wBAAwB,EAAEsgB,KAAK,CAAC,CAAA;EAC3D,IAAA,IAAI,CAACte,QAAQ,CAAC9B,eAAe,CAAC,OAAO,CAAC;EACxC,EAAA;EAEAmhB,EAAAA,MAAMA,GAAG;MACP,IAAI,IAAI,CAAC7S,QAAQ,EAAE,IAAI,IAAI,CAACkS,UAAU,EAAE;QACtC,IAAI,CAACA,UAAU,GAAG,IAAI;EACtB,MAAA;EACF,IAAA;MAEA,IAAI,CAACA,UAAU,GAAG,IAAI;MAEtB,IAAI,CAACkC,WAAW,CAAC,MAAM;QACrB,IAAI,IAAI,CAAClC,UAAU,EAAE;UACnB,IAAI,CAAChS,IAAI,EAAE;EACb,MAAA;MACF,CAAC,EAAE,IAAI,CAACzM,OAAO,CAACme,KAAK,CAAC1R,IAAI,CAAC;EAC7B,EAAA;EAEA0S,EAAAA,MAAMA,GAAG;EACP,IAAA,IAAI,IAAI,CAACS,oBAAoB,EAAE,EAAE;EAC/B,MAAA;EACF,IAAA;MAEA,IAAI,CAACnB,UAAU,GAAG,KAAK;MAEvB,IAAI,CAACkC,WAAW,CAAC,MAAM;EACrB,MAAA,IAAI,CAAC,IAAI,CAAClC,UAAU,EAAE;UACpB,IAAI,CAACjS,IAAI,EAAE;EACb,MAAA;MACF,CAAC,EAAE,IAAI,CAACxM,OAAO,CAACme,KAAK,CAAC3R,IAAI,CAAC;EAC7B,EAAA;EAEAmU,EAAAA,WAAWA,CAAC9oB,OAAO,EAAE+oB,OAAO,EAAE;EAC5BlX,IAAAA,YAAY,CAAC,IAAI,CAAC8U,QAAQ,CAAC;MAC3B,IAAI,CAACA,QAAQ,GAAGxmB,UAAU,CAACH,OAAO,EAAE+oB,OAAO,CAAC;EAC9C,EAAA;EAEAhB,EAAAA,oBAAoBA,GAAG;EACrB,IAAA,OAAOrtB,MAAM,CAACkI,MAAM,CAAC,IAAI,CAACikB,cAAc,CAAC,CAAC7iB,QAAQ,CAAC,IAAI,CAAC;EAC1D,EAAA;IAEAiD,UAAUA,CAACC,MAAM,EAAE;MACjB,MAAM8hB,cAAc,GAAGhjB,WAAW,CAACK,iBAAiB,CAAC,IAAI,CAAC6B,QAAQ,CAAC;MAEnE,KAAK,MAAM+gB,aAAa,IAAIvuB,MAAM,CAACjB,IAAI,CAACuvB,cAAc,CAAC,EAAE;EACvD,MAAA,IAAI/D,qBAAqB,CAAChsB,GAAG,CAACgwB,aAAa,CAAC,EAAE;UAC5C,OAAOD,cAAc,CAACC,aAAa,CAAC;EACtC,MAAA;EACF,IAAA;EAEA/hB,IAAAA,MAAM,GAAG;EACP,MAAA,GAAG8hB,cAAc;QACjB,IAAI,OAAO9hB,MAAM,KAAK,QAAQ,IAAIA,MAAM,GAAGA,MAAM,GAAG,EAAE;OACvD;EACDA,IAAAA,MAAM,GAAG,IAAI,CAACC,eAAe,CAACD,MAAM,CAAC;EACrCA,IAAAA,MAAM,GAAG,IAAI,CAACE,iBAAiB,CAACF,MAAM,CAAC;EACvC,IAAA,IAAI,CAACG,gBAAgB,CAACH,MAAM,CAAC;EAC7B,IAAA,OAAOA,MAAM;EACf,EAAA;IAEAE,iBAAiBA,CAACF,MAAM,EAAE;EACxBA,IAAAA,MAAM,CAACkf,SAAS,GAAGlf,MAAM,CAACkf,SAAS,KAAK,KAAK,GAAGhrB,QAAQ,CAAC+C,IAAI,GAAG9B,UAAU,CAAC6K,MAAM,CAACkf,SAAS,CAAC;EAE5F,IAAA,IAAI,OAAOlf,MAAM,CAACof,KAAK,KAAK,QAAQ,EAAE;QACpCpf,MAAM,CAACof,KAAK,GAAG;UACb1R,IAAI,EAAE1N,MAAM,CAACof,KAAK;UAClB3R,IAAI,EAAEzN,MAAM,CAACof;SACd;EACH,IAAA;EAEA,IAAA,IAAI,OAAOpf,MAAM,CAACsf,KAAK,KAAK,QAAQ,EAAE;QACpCtf,MAAM,CAACsf,KAAK,GAAGtf,MAAM,CAACsf,KAAK,CAAC5rB,QAAQ,EAAE;EACxC,IAAA;EAEA,IAAA,IAAI,OAAOsM,MAAM,CAACwc,OAAO,KAAK,QAAQ,EAAE;QACtCxc,MAAM,CAACwc,OAAO,GAAGxc,MAAM,CAACwc,OAAO,CAAC9oB,QAAQ,EAAE;EAC5C,IAAA;EAEA,IAAA,OAAOsM,MAAM;EACf,EAAA;EAEAqhB,EAAAA,kBAAkBA,GAAG;MACnB,MAAMrhB,MAAM,GAAG,EAAE;EAEjB,IAAA,KAAK,MAAM,CAACnO,GAAG,EAAEuM,KAAK,CAAC,IAAI5K,MAAM,CAACqJ,OAAO,CAAC,IAAI,CAACoE,OAAO,CAAC,EAAE;QACvD,IAAI,IAAI,CAACZ,WAAW,CAACT,OAAO,CAAC/N,GAAG,CAAC,KAAKuM,KAAK,EAAE;EAC3C4B,QAAAA,MAAM,CAACnO,GAAG,CAAC,GAAGuM,KAAK;EACrB,MAAA;EACF,IAAA;MAEA4B,MAAM,CAAClN,QAAQ,GAAG,KAAK;MACvBkN,MAAM,CAACzC,OAAO,GAAG,QAAQ;;EAEzB;EACA;EACA;EACA,IAAA,OAAOyC,MAAM;EACf,EAAA;EAEAugB,EAAAA,cAAcA,GAAG;MACf,IAAI,IAAI,CAAC9P,OAAO,EAAE;EAChB,MAAA,IAAI,CAACA,OAAO,CAACS,OAAO,EAAE;QACtB,IAAI,CAACT,OAAO,GAAG,IAAI;EACrB,IAAA;MAEA,IAAI,IAAI,CAACqP,GAAG,EAAE;EACZ,MAAA,IAAI,CAACA,GAAG,CAACttB,MAAM,EAAE;QACjB,IAAI,CAACstB,GAAG,GAAG,IAAI;EACjB,IAAA;EACF,EAAA;;EAEA;IACA,OAAO7nB,eAAeA,CAAC+H,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACoE,IAAI,CAAC,YAAY;QAC3B,MAAMC,IAAI,GAAGkb,OAAO,CAAC5d,mBAAmB,CAAC,IAAI,EAAE3B,MAAM,CAAC;EAEtD,MAAA,IAAI,OAAOA,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA;EACF,MAAA;EAEA,MAAA,IAAI,OAAOqE,IAAI,CAACrE,MAAM,CAAC,KAAK,WAAW,EAAE;EACvC,QAAA,MAAM,IAAIY,SAAS,CAAC,CAAA,iBAAA,EAAoBZ,MAAM,GAAG,CAAC;EACpD,MAAA;EAEAqE,MAAAA,IAAI,CAACrE,MAAM,CAAC,EAAE;EAChB,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAtI,kBAAkB,CAAC6nB,OAAO,CAAC;;ECtnB3B;EACA;EACA;EACA;EACA;EACA;;;EAKA;EACA;EACA;;EAEA,MAAMznB,MAAI,GAAG,SAAS;EAEtB,MAAMkqB,cAAc,GAAG,iBAAiB;EACxC,MAAMC,gBAAgB,GAAG,eAAe;EAExC,MAAMriB,SAAO,GAAG;IACd,GAAG2f,OAAO,CAAC3f,OAAO;EAClB4c,EAAAA,OAAO,EAAE,EAAE;EACXnM,EAAAA,MAAM,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;EACd0B,EAAAA,SAAS,EAAE,OAAO;IAClB8K,QAAQ,EAAE,sCAAsC,GAC9C,mCAAmC,GACnC,kCAAkC,GAClC,kCAAkC,GAClC,QAAQ;EACVtf,EAAAA,OAAO,EAAE;EACX,CAAC;EAED,MAAMsC,aAAW,GAAG;IAClB,GAAG0f,OAAO,CAAC1f,WAAW;EACtB2c,EAAAA,OAAO,EAAE;EACX,CAAC;;EAED;EACA;EACA;;EAEA,MAAM0F,OAAO,SAAS3C,OAAO,CAAC;EAC5B;IACA,WAAW3f,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACA0oB,EAAAA,cAAcA,GAAG;MACf,OAAO,IAAI,CAACM,SAAS,EAAE,IAAI,IAAI,CAACqB,WAAW,EAAE;EAC/C,EAAA;;EAEA;EACAnB,EAAAA,sBAAsBA,GAAG;MACvB,OAAO;EACL,MAAA,CAACgB,cAAc,GAAG,IAAI,CAAClB,SAAS,EAAE;EAClC,MAAA,CAACmB,gBAAgB,GAAG,IAAI,CAACE,WAAW;OACrC;EACH,EAAA;EAEAA,EAAAA,WAAWA,GAAG;MACZ,OAAO,IAAI,CAACjF,wBAAwB,CAAC,IAAI,CAACjc,OAAO,CAACub,OAAO,CAAC;EAC5D,EAAA;;EAEA;IACA,OAAOvkB,eAAeA,CAAC+H,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACoE,IAAI,CAAC,YAAY;QAC3B,MAAMC,IAAI,GAAG6d,OAAO,CAACvgB,mBAAmB,CAAC,IAAI,EAAE3B,MAAM,CAAC;EAEtD,MAAA,IAAI,OAAOA,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA;EACF,MAAA;EAEA,MAAA,IAAI,OAAOqE,IAAI,CAACrE,MAAM,CAAC,KAAK,WAAW,EAAE;EACvC,QAAA,MAAM,IAAIY,SAAS,CAAC,CAAA,iBAAA,EAAoBZ,MAAM,GAAG,CAAC;EACpD,MAAA;EAEAqE,MAAAA,IAAI,CAACrE,MAAM,CAAC,EAAE;EAChB,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAtI,kBAAkB,CAACwqB,OAAO,CAAC;;EC9F3B;EACA;EACA;EACA;EACA;EACA;;;EASA;EACA;EACA;;EAEA,MAAMpqB,MAAI,GAAG,WAAW;EACxB,MAAMqJ,UAAQ,GAAG,cAAc;EAC/B,MAAME,WAAS,GAAG,CAAA,CAAA,EAAIF,UAAQ,CAAA,CAAE;EAChC,MAAMmD,YAAY,GAAG,WAAW;EAEhC,MAAM8d,cAAc,GAAG,CAAA,QAAA,EAAW/gB,WAAS,CAAA,CAAE;EAC7C,MAAMod,WAAW,GAAG,CAAA,KAAA,EAAQpd,WAAS,CAAA,CAAE;EACvC,MAAMqG,qBAAmB,GAAG,CAAA,IAAA,EAAOrG,WAAS,CAAA,EAAGiD,YAAY,CAAA,CAAE;EAE7D,MAAM+d,wBAAwB,GAAG,eAAe;EAChD,MAAM9d,mBAAiB,GAAG,QAAQ;EAElC,MAAM+d,iBAAiB,GAAG,wBAAwB;EAClD,MAAMC,qBAAqB,GAAG,QAAQ;EACtC,MAAMC,uBAAuB,GAAG,mBAAmB;EACnD,MAAMC,kBAAkB,GAAG,WAAW;EACtC,MAAMC,kBAAkB,GAAG,WAAW;EACtC,MAAMC,mBAAmB,GAAG,kBAAkB;EAC9C,MAAMC,mBAAmB,GAAG,CAAA,EAAGH,kBAAkB,CAAA,EAAA,EAAKC,kBAAkB,CAAA,GAAA,EAAMD,kBAAkB,CAAA,EAAA,EAAKE,mBAAmB,CAAA,CAAE;EAC1H,MAAME,iBAAiB,GAAG,WAAW;EACrC,MAAMC,0BAAwB,GAAG,kBAAkB;EAEnD,MAAMljB,SAAO,GAAG;EACdyQ,EAAAA,MAAM,EAAE,IAAI;EAAE;EACd0S,EAAAA,UAAU,EAAE,cAAc;EAC1BC,EAAAA,YAAY,EAAE,KAAK;EACnBjqB,EAAAA,MAAM,EAAE,IAAI;EACZkqB,EAAAA,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC;EACzB,CAAC;EAED,MAAMpjB,aAAW,GAAG;EAClBwQ,EAAAA,MAAM,EAAE,eAAe;EAAE;EACzB0S,EAAAA,UAAU,EAAE,QAAQ;EACpBC,EAAAA,YAAY,EAAE,SAAS;EACvBjqB,EAAAA,MAAM,EAAE,SAAS;EACjBkqB,EAAAA,SAAS,EAAE;EACb,CAAC;;EAED;EACA;EACA;;EAEA,MAAMC,SAAS,SAASniB,aAAa,CAAC;EACpCV,EAAAA,WAAWA,CAACzO,OAAO,EAAEoO,MAAM,EAAE;EAC3B,IAAA,KAAK,CAACpO,OAAO,EAAEoO,MAAM,CAAC;;EAEtB;EACA,IAAA,IAAI,CAACmjB,YAAY,GAAG,IAAIzxB,GAAG,EAAE;EAC7B,IAAA,IAAI,CAAC0xB,mBAAmB,GAAG,IAAI1xB,GAAG,EAAE;EACpC,IAAA,IAAI,CAAC2xB,YAAY,GAAG9uB,gBAAgB,CAAC,IAAI,CAACyM,QAAQ,CAAC,CAACmX,SAAS,KAAK,SAAS,GAAG,IAAI,GAAG,IAAI,CAACnX,QAAQ;MAClG,IAAI,CAACsiB,aAAa,GAAG,IAAI;MACzB,IAAI,CAACC,SAAS,GAAG,IAAI;MACrB,IAAI,CAACC,mBAAmB,GAAG;EACzBC,MAAAA,eAAe,EAAE,CAAC;EAClBC,MAAAA,eAAe,EAAE;OAClB;EACD,IAAA,IAAI,CAACC,OAAO,EAAE,CAAA;EAChB,EAAA;;EAEA;IACA,WAAW/jB,OAAOA,GAAG;EACnB,IAAA,OAAOA,SAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,aAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACA6rB,EAAAA,OAAOA,GAAG;MACR,IAAI,CAACC,gCAAgC,EAAE;MACvC,IAAI,CAACC,wBAAwB,EAAE;MAE/B,IAAI,IAAI,CAACN,SAAS,EAAE;EAClB,MAAA,IAAI,CAACA,SAAS,CAACO,UAAU,EAAE;EAC7B,IAAA,CAAC,MAAM;EACL,MAAA,IAAI,CAACP,SAAS,GAAG,IAAI,CAACQ,eAAe,EAAE;EACzC,IAAA;MAEA,KAAK,MAAMC,OAAO,IAAI,IAAI,CAACZ,mBAAmB,CAAC1nB,MAAM,EAAE,EAAE;EACvD,MAAA,IAAI,CAAC6nB,SAAS,CAACU,OAAO,CAACD,OAAO,CAAC;EACjC,IAAA;EACF,EAAA;EAEA5iB,EAAAA,OAAOA,GAAG;EACR,IAAA,IAAI,CAACmiB,SAAS,CAACO,UAAU,EAAE;MAC3B,KAAK,CAAC1iB,OAAO,EAAE;EACjB,EAAA;;EAEA;IACAlB,iBAAiBA,CAACF,MAAM,EAAE;EACxB;EACAA,IAAAA,MAAM,CAACjH,MAAM,GAAG5D,UAAU,CAAC6K,MAAM,CAACjH,MAAM,CAAC,IAAI7E,QAAQ,CAAC+C,IAAI;;EAE1D;EACA+I,IAAAA,MAAM,CAAC+iB,UAAU,GAAG/iB,MAAM,CAACqQ,MAAM,GAAG,CAAA,EAAGrQ,MAAM,CAACqQ,MAAM,CAAA,WAAA,CAAa,GAAGrQ,MAAM,CAAC+iB,UAAU;EAErF,IAAA,IAAI,OAAO/iB,MAAM,CAACijB,SAAS,KAAK,QAAQ,EAAE;QACxCjjB,MAAM,CAACijB,SAAS,GAAGjjB,MAAM,CAACijB,SAAS,CAACruB,KAAK,CAAC,GAAG,CAAC,CAACoN,GAAG,CAAC5D,KAAK,IAAI3J,MAAM,CAACC,UAAU,CAAC0J,KAAK,CAAC,CAAC;EACvF,IAAA;EAEA,IAAA,OAAO4B,MAAM;EACf,EAAA;EAEA6jB,EAAAA,wBAAwBA,GAAG;EACzB,IAAA,IAAI,CAAC,IAAI,CAAC5iB,OAAO,CAAC+hB,YAAY,EAAE;EAC9B,MAAA;EACF,IAAA;;EAEA;MACAloB,YAAY,CAACC,GAAG,CAAC,IAAI,CAACkG,OAAO,CAAClI,MAAM,EAAE0lB,WAAW,CAAC;EAElD3jB,IAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACkE,OAAO,CAAClI,MAAM,EAAE0lB,WAAW,EAAE8D,qBAAqB,EAAE7nB,KAAK,IAAI;EAChF,MAAA,MAAMwpB,iBAAiB,GAAG,IAAI,CAACd,mBAAmB,CAACnxB,GAAG,CAACyI,KAAK,CAAC3B,MAAM,CAACorB,IAAI,CAAC;EACzE,MAAA,IAAID,iBAAiB,EAAE;UACrBxpB,KAAK,CAACuD,cAAc,EAAE;EACtB,QAAA,MAAMvH,IAAI,GAAG,IAAI,CAAC2sB,YAAY,IAAItwB,MAAM;UACxC,MAAMqxB,MAAM,GAAGF,iBAAiB,CAACG,SAAS,GAAG,IAAI,CAACrjB,QAAQ,CAACqjB,SAAS;UACpE,IAAI3tB,IAAI,CAAC4tB,QAAQ,EAAE;YACjB5tB,IAAI,CAAC4tB,QAAQ,CAAC;EAAEC,YAAAA,GAAG,EAAEH,MAAM;EAAEI,YAAAA,QAAQ,EAAE;EAAS,WAAC,CAAC;EAClD,UAAA;EACF,QAAA;;EAEA;UACA9tB,IAAI,CAAC+gB,SAAS,GAAG2M,MAAM;EACzB,MAAA;EACF,IAAA,CAAC,CAAC;EACJ,EAAA;EAEAL,EAAAA,eAAeA,GAAG;EAChB,IAAA,MAAM9R,OAAO,GAAG;QACdvb,IAAI,EAAE,IAAI,CAAC2sB,YAAY;EACvBJ,MAAAA,SAAS,EAAE,IAAI,CAAChiB,OAAO,CAACgiB,SAAS;EACjCF,MAAAA,UAAU,EAAE,IAAI,CAAC9hB,OAAO,CAAC8hB;OAC1B;EAED,IAAA,OAAO,IAAI0B,oBAAoB,CAAC5nB,OAAO,IAAI,IAAI,CAAC6nB,iBAAiB,CAAC7nB,OAAO,CAAC,EAAEoV,OAAO,CAAC;EACtF,EAAA;;EAEA;IACAyS,iBAAiBA,CAAC7nB,OAAO,EAAE;EACzB,IAAA,MAAM8nB,aAAa,GAAG5H,KAAK,IAAI,IAAI,CAACoG,YAAY,CAAClxB,GAAG,CAAC,IAAI8qB,KAAK,CAAChkB,MAAM,CAAC3F,EAAE,EAAE,CAAC;MAC3E,MAAMghB,QAAQ,GAAG2I,KAAK,IAAI;QACxB,IAAI,CAACyG,mBAAmB,CAACC,eAAe,GAAG1G,KAAK,CAAChkB,MAAM,CAACsrB,SAAS;EACjE,MAAA,IAAI,CAACO,QAAQ,CAACD,aAAa,CAAC5H,KAAK,CAAC,CAAC;MACrC,CAAC;MAED,MAAM2G,eAAe,GAAG,CAAC,IAAI,CAACL,YAAY,IAAInvB,QAAQ,CAACqC,eAAe,EAAEkhB,SAAS;MACjF,MAAMoN,eAAe,GAAGnB,eAAe,IAAI,IAAI,CAACF,mBAAmB,CAACE,eAAe;EACnF,IAAA,IAAI,CAACF,mBAAmB,CAACE,eAAe,GAAGA,eAAe;EAE1D,IAAA,KAAK,MAAM3G,KAAK,IAAIlgB,OAAO,EAAE;EAC3B,MAAA,IAAI,CAACkgB,KAAK,CAAC+H,cAAc,EAAE;UACzB,IAAI,CAACxB,aAAa,GAAG,IAAI;EACzB,QAAA,IAAI,CAACyB,iBAAiB,CAACJ,aAAa,CAAC5H,KAAK,CAAC,CAAC;EAE5C,QAAA;EACF,MAAA;EAEA,MAAA,MAAMiI,wBAAwB,GAAGjI,KAAK,CAAChkB,MAAM,CAACsrB,SAAS,IAAI,IAAI,CAACb,mBAAmB,CAACC,eAAe;EACnG;QACA,IAAIoB,eAAe,IAAIG,wBAAwB,EAAE;UAC/C5Q,QAAQ,CAAC2I,KAAK,CAAC;EACf;UACA,IAAI,CAAC2G,eAAe,EAAE;EACpB,UAAA;EACF,QAAA;EAEA,QAAA;EACF,MAAA;;EAEA;EACA,MAAA,IAAI,CAACmB,eAAe,IAAI,CAACG,wBAAwB,EAAE;UACjD5Q,QAAQ,CAAC2I,KAAK,CAAC;EACjB,MAAA;EACF,IAAA;EACF,EAAA;EAEA6G,EAAAA,gCAAgCA,GAAG;EACjC,IAAA,IAAI,CAACT,YAAY,GAAG,IAAIzxB,GAAG,EAAE;EAC7B,IAAA,IAAI,CAAC0xB,mBAAmB,GAAG,IAAI1xB,GAAG,EAAE;EAEpC,IAAA,MAAMuzB,WAAW,GAAG9iB,cAAc,CAACxG,IAAI,CAAC4mB,qBAAqB,EAAE,IAAI,CAACthB,OAAO,CAAClI,MAAM,CAAC;EAEnF,IAAA,KAAK,MAAMmsB,MAAM,IAAID,WAAW,EAAE;EAChC;QACA,IAAI,CAACC,MAAM,CAACf,IAAI,IAAIruB,UAAU,CAACovB,MAAM,CAAC,EAAE;EACtC,QAAA;EACF,MAAA;EAEA,MAAA,MAAMhB,iBAAiB,GAAG/hB,cAAc,CAACG,OAAO,CAAC6iB,SAAS,CAACD,MAAM,CAACf,IAAI,CAAC,EAAE,IAAI,CAACnjB,QAAQ,CAAC;;EAEvF;EACA,MAAA,IAAI1L,SAAS,CAAC4uB,iBAAiB,CAAC,EAAE;EAChC,QAAA,IAAI,CAACf,YAAY,CAACxxB,GAAG,CAACwzB,SAAS,CAACD,MAAM,CAACf,IAAI,CAAC,EAAEe,MAAM,CAAC;UACrD,IAAI,CAAC9B,mBAAmB,CAACzxB,GAAG,CAACuzB,MAAM,CAACf,IAAI,EAAED,iBAAiB,CAAC;EAC9D,MAAA;EACF,IAAA;EACF,EAAA;IAEAU,QAAQA,CAAC7rB,MAAM,EAAE;EACf,IAAA,IAAI,IAAI,CAACuqB,aAAa,KAAKvqB,MAAM,EAAE;EACjC,MAAA;EACF,IAAA;MAEA,IAAI,CAACgsB,iBAAiB,CAAC,IAAI,CAAC9jB,OAAO,CAAClI,MAAM,CAAC;MAC3C,IAAI,CAACuqB,aAAa,GAAGvqB,MAAM;EAC3BA,IAAAA,MAAM,CAAC9C,SAAS,CAACwQ,GAAG,CAAClC,mBAAiB,CAAC;EACvC,IAAA,IAAI,CAAC6gB,gBAAgB,CAACrsB,MAAM,CAAC;MAE7B+B,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEohB,cAAc,EAAE;EAAEhmB,MAAAA,aAAa,EAAErD;EAAO,KAAC,CAAC;EAChF,EAAA;IAEAqsB,gBAAgBA,CAACrsB,MAAM,EAAE;EACvB;MACA,IAAIA,MAAM,CAAC9C,SAAS,CAACC,QAAQ,CAACmsB,wBAAwB,CAAC,EAAE;EACvDlgB,MAAAA,cAAc,CAACG,OAAO,CAACwgB,0BAAwB,EAAE/pB,MAAM,CAACpD,OAAO,CAACktB,iBAAiB,CAAC,CAAC,CAChF5sB,SAAS,CAACwQ,GAAG,CAAClC,mBAAiB,CAAC;EACnC,MAAA;EACF,IAAA;MAEA,KAAK,MAAM8gB,SAAS,IAAIljB,cAAc,CAACO,OAAO,CAAC3J,MAAM,EAAEypB,uBAAuB,CAAC,EAAE;EAC/E;EACA;QACA,KAAK,MAAM8C,IAAI,IAAInjB,cAAc,CAACS,IAAI,CAACyiB,SAAS,EAAEzC,mBAAmB,CAAC,EAAE;EACtE0C,QAAAA,IAAI,CAACrvB,SAAS,CAACwQ,GAAG,CAAClC,mBAAiB,CAAC;EACvC,MAAA;EACF,IAAA;EACF,EAAA;IAEAwgB,iBAAiBA,CAACjY,MAAM,EAAE;EACxBA,IAAAA,MAAM,CAAC7W,SAAS,CAACzD,MAAM,CAAC+R,mBAAiB,CAAC;EAE1C,IAAA,MAAMghB,WAAW,GAAGpjB,cAAc,CAACxG,IAAI,CAAC,CAAA,EAAG4mB,qBAAqB,CAAA,CAAA,EAAIhe,mBAAiB,CAAA,CAAE,EAAEuI,MAAM,CAAC;EAChG,IAAA,KAAK,MAAM0Y,IAAI,IAAID,WAAW,EAAE;EAC9BC,MAAAA,IAAI,CAACvvB,SAAS,CAACzD,MAAM,CAAC+R,mBAAiB,CAAC;EAC1C,IAAA;EACF,EAAA;;EAEA;IACA,OAAOtM,eAAeA,CAAC+H,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACoE,IAAI,CAAC,YAAY;QAC3B,MAAMC,IAAI,GAAG6e,SAAS,CAACvhB,mBAAmB,CAAC,IAAI,EAAE3B,MAAM,CAAC;EAExD,MAAA,IAAI,OAAOA,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA;EACF,MAAA;EAEA,MAAA,IAAIqE,IAAI,CAACrE,MAAM,CAAC,KAAKzM,SAAS,IAAIyM,MAAM,CAAC7C,UAAU,CAAC,GAAG,CAAC,IAAI6C,MAAM,KAAK,aAAa,EAAE;EACpF,QAAA,MAAM,IAAIY,SAAS,CAAC,CAAA,iBAAA,EAAoBZ,MAAM,GAAG,CAAC;EACpD,MAAA;EAEAqE,MAAAA,IAAI,CAACrE,MAAM,CAAC,EAAE;EAChB,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAlF,YAAY,CAACiC,EAAE,CAAChK,MAAM,EAAE2U,qBAAmB,EAAE,MAAM;IACjD,KAAK,MAAM+d,GAAG,IAAItjB,cAAc,CAACxG,IAAI,CAAC2mB,iBAAiB,CAAC,EAAE;EACxDY,IAAAA,SAAS,CAACvhB,mBAAmB,CAAC8jB,GAAG,CAAC;EACpC,EAAA;EACF,CAAC,CAAC;;EAEF;EACA;EACA;;EAEA/tB,kBAAkB,CAACwrB,SAAS,CAAC;;ECrS7B;EACA;EACA;EACA;EACA;EACA;;;EAOA;EACA;EACA;;EAEA,MAAMprB,MAAI,GAAG,KAAK;EAClB,MAAMqJ,UAAQ,GAAG,QAAQ;EACzB,MAAME,WAAS,GAAG,CAAA,CAAA,EAAIF,UAAQ,CAAA,CAAE;EAEhC,MAAMiL,YAAU,GAAG,CAAA,IAAA,EAAO/K,WAAS,CAAA,CAAE;EACrC,MAAMgL,cAAY,GAAG,CAAA,MAAA,EAAShL,WAAS,CAAA,CAAE;EACzC,MAAM6K,YAAU,GAAG,CAAA,IAAA,EAAO7K,WAAS,CAAA,CAAE;EACrC,MAAM8K,aAAW,GAAG,CAAA,KAAA,EAAQ9K,WAAS,CAAA,CAAE;EACvC,MAAMoD,oBAAoB,GAAG,CAAA,KAAA,EAAQpD,WAAS,CAAA,CAAE;EAChD,MAAMiG,aAAa,GAAG,CAAA,OAAA,EAAUjG,WAAS,CAAA,CAAE;EAC3C,MAAMqG,mBAAmB,GAAG,CAAA,IAAA,EAAOrG,WAAS,CAAA,CAAE;EAE9C,MAAMwF,cAAc,GAAG,WAAW;EAClC,MAAMC,eAAe,GAAG,YAAY;EACpC,MAAM6H,YAAY,GAAG,SAAS;EAC9B,MAAMC,cAAc,GAAG,WAAW;EAClC,MAAM8W,QAAQ,GAAG,MAAM;EACvB,MAAMC,OAAO,GAAG,KAAK;EAErB,MAAMphB,iBAAiB,GAAG,QAAQ;EAClC,MAAMT,iBAAe,GAAG,MAAM;EAC9B,MAAMC,iBAAe,GAAG,MAAM;EAC9B,MAAM6hB,cAAc,GAAG,UAAU;EAEjC,MAAM9C,wBAAwB,GAAG,kBAAkB;EACnD,MAAM+C,sBAAsB,GAAG,gBAAgB;EAC/C,MAAMC,4BAA4B,GAAG,CAAA,KAAA,EAAQhD,wBAAwB,CAAA,CAAA,CAAG;EAExE,MAAMiD,kBAAkB,GAAG,qCAAqC;EAChE,MAAMC,cAAc,GAAG,6BAA6B;EACpD,MAAMC,cAAc,GAAG,CAAA,SAAA,EAAYH,4BAA4B,qBAAqBA,4BAA4B,CAAA,cAAA,EAAiBA,4BAA4B,CAAA,CAAE;EAC/J,MAAMthB,oBAAoB,GAAG,0EAA0E,CAAA;EACvG,MAAM0hB,mBAAmB,GAAG,CAAA,EAAGD,cAAc,CAAA,EAAA,EAAKzhB,oBAAoB,CAAA,CAAE;EAExE,MAAM2hB,2BAA2B,GAAG,CAAA,CAAA,EAAI5hB,iBAAiB,4BAA4BA,iBAAiB,CAAA,0BAAA,EAA6BA,iBAAiB,CAAA,uBAAA,CAAyB;;EAE7K;EACA;EACA;;EAEA,MAAM6hB,GAAG,SAASrlB,aAAa,CAAC;IAC9BV,WAAWA,CAACzO,OAAO,EAAE;MACnB,KAAK,CAACA,OAAO,CAAC;MACd,IAAI,CAAC8e,OAAO,GAAG,IAAI,CAAC1P,QAAQ,CAACrL,OAAO,CAACowB,kBAAkB,CAAC;EAExD,IAAA,IAAI,CAAC,IAAI,CAACrV,OAAO,EAAE;EACjB,MAAA;EACA;EACA;EACF,IAAA;;EAEA;EACA,IAAA,IAAI,CAAC2V,qBAAqB,CAAC,IAAI,CAAC3V,OAAO,EAAE,IAAI,CAAC4V,YAAY,EAAE,CAAC;EAE7DxrB,IAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAEsG,aAAa,EAAE5M,KAAK,IAAI,IAAI,CAAC6P,QAAQ,CAAC7P,KAAK,CAAC,CAAC;EAC9E,EAAA;;EAEA;IACA,WAAW5C,IAAIA,GAAG;EAChB,IAAA,OAAOA,MAAI;EACb,EAAA;;EAEA;EACA4V,EAAAA,IAAIA,GAAG;EAAE;EACP,IAAA,MAAM6Y,SAAS,GAAG,IAAI,CAACvlB,QAAQ;EAC/B,IAAA,IAAI,IAAI,CAACwlB,aAAa,CAACD,SAAS,CAAC,EAAE;EACjC,MAAA;EACF,IAAA;;EAEA;EACA,IAAA,MAAME,MAAM,GAAG,IAAI,CAACC,cAAc,EAAE;MAEpC,MAAMtV,SAAS,GAAGqV,MAAM,GACtB3rB,YAAY,CAACyC,OAAO,CAACkpB,MAAM,EAAEra,YAAU,EAAE;EAAEhQ,MAAAA,aAAa,EAAEmqB;OAAW,CAAC,GACtE,IAAI;MAEN,MAAMzV,SAAS,GAAGhW,YAAY,CAACyC,OAAO,CAACgpB,SAAS,EAAEra,YAAU,EAAE;EAAE9P,MAAAA,aAAa,EAAEqqB;EAAO,KAAC,CAAC;MAExF,IAAI3V,SAAS,CAACnT,gBAAgB,IAAKyT,SAAS,IAAIA,SAAS,CAACzT,gBAAiB,EAAE;EAC3E,MAAA;EACF,IAAA;EAEA,IAAA,IAAI,CAACgpB,WAAW,CAACF,MAAM,EAAEF,SAAS,CAAC;EACnC,IAAA,IAAI,CAACK,SAAS,CAACL,SAAS,EAAEE,MAAM,CAAC;EACnC,EAAA;;EAEA;EACAG,EAAAA,SAASA,CAACh1B,OAAO,EAAEi1B,WAAW,EAAE;MAC9B,IAAI,CAACj1B,OAAO,EAAE;EACZ,MAAA;EACF,IAAA;EAEAA,IAAAA,OAAO,CAACqE,SAAS,CAACwQ,GAAG,CAAClC,iBAAiB,CAAC;MAExC,IAAI,CAACqiB,SAAS,CAACzkB,cAAc,CAACkB,sBAAsB,CAACzR,OAAO,CAAC,CAAC,CAAA;;MAE9D,MAAMsc,QAAQ,GAAGA,MAAM;QACrB,IAAItc,OAAO,CAACyE,YAAY,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE;EAC1CzE,QAAAA,OAAO,CAACqE,SAAS,CAACwQ,GAAG,CAAC1C,iBAAe,CAAC;EACtC,QAAA;EACF,MAAA;EAEAnS,MAAAA,OAAO,CAACsN,eAAe,CAAC,UAAU,CAAC;EACnCtN,MAAAA,OAAO,CAACoN,YAAY,CAAC,eAAe,EAAE,IAAI,CAAC;EAC3C,MAAA,IAAI,CAAC8nB,eAAe,CAACl1B,OAAO,EAAE,IAAI,CAAC;EACnCkJ,MAAAA,YAAY,CAACyC,OAAO,CAAC3L,OAAO,EAAEua,aAAW,EAAE;EACzC/P,QAAAA,aAAa,EAAEyqB;EACjB,OAAC,CAAC;MACJ,CAAC;EAED,IAAA,IAAI,CAACrlB,cAAc,CAAC0M,QAAQ,EAAEtc,OAAO,EAAEA,OAAO,CAACqE,SAAS,CAACC,QAAQ,CAAC4N,iBAAe,CAAC,CAAC;EACrF,EAAA;EAEA6iB,EAAAA,WAAWA,CAAC/0B,OAAO,EAAEi1B,WAAW,EAAE;MAChC,IAAI,CAACj1B,OAAO,EAAE;EACZ,MAAA;EACF,IAAA;EAEAA,IAAAA,OAAO,CAACqE,SAAS,CAACzD,MAAM,CAAC+R,iBAAiB,CAAC;MAC3C3S,OAAO,CAACinB,IAAI,EAAE;MAEd,IAAI,CAAC8N,WAAW,CAACxkB,cAAc,CAACkB,sBAAsB,CAACzR,OAAO,CAAC,CAAC,CAAA;;MAEhE,MAAMsc,QAAQ,GAAGA,MAAM;QACrB,IAAItc,OAAO,CAACyE,YAAY,CAAC,MAAM,CAAC,KAAK,KAAK,EAAE;EAC1CzE,QAAAA,OAAO,CAACqE,SAAS,CAACzD,MAAM,CAACuR,iBAAe,CAAC;EACzC,QAAA;EACF,MAAA;EAEAnS,MAAAA,OAAO,CAACoN,YAAY,CAAC,eAAe,EAAE,KAAK,CAAC;EAC5CpN,MAAAA,OAAO,CAACoN,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC;EACtC,MAAA,IAAI,CAAC8nB,eAAe,CAACl1B,OAAO,EAAE,KAAK,CAAC;EACpCkJ,MAAAA,YAAY,CAACyC,OAAO,CAAC3L,OAAO,EAAEya,cAAY,EAAE;EAAEjQ,QAAAA,aAAa,EAAEyqB;EAAY,OAAC,CAAC;MAC7E,CAAC;EAED,IAAA,IAAI,CAACrlB,cAAc,CAAC0M,QAAQ,EAAEtc,OAAO,EAAEA,OAAO,CAACqE,SAAS,CAACC,QAAQ,CAAC4N,iBAAe,CAAC,CAAC;EACrF,EAAA;IAEAyG,QAAQA,CAAC7P,KAAK,EAAE;MACd,IAAI,CAAE,CAACmM,cAAc,EAAEC,eAAe,EAAE6H,YAAY,EAAEC,cAAc,EAAE8W,QAAQ,EAAEC,OAAO,CAAC,CAAC7oB,QAAQ,CAACpC,KAAK,CAAC7I,GAAG,CAAE,EAAE;EAC7G,MAAA;EACF,IAAA;MAEA6I,KAAK,CAACoY,eAAe,EAAE,CAAA;MACvBpY,KAAK,CAACuD,cAAc,EAAE;EAEtB,IAAA,MAAMsE,QAAQ,GAAG,IAAI,CAAC+jB,YAAY,EAAE,CAAC/mB,MAAM,CAAC3N,OAAO,IAAI,CAACkE,UAAU,CAAClE,OAAO,CAAC,CAAC;EAC5E,IAAA,IAAIm1B,iBAAiB;EAErB,IAAA,IAAI,CAACrB,QAAQ,EAAEC,OAAO,CAAC,CAAC7oB,QAAQ,CAACpC,KAAK,CAAC7I,GAAG,CAAC,EAAE;EAC3Ck1B,MAAAA,iBAAiB,GAAGxkB,QAAQ,CAAC7H,KAAK,CAAC7I,GAAG,KAAK6zB,QAAQ,GAAG,CAAC,GAAGnjB,QAAQ,CAACnN,MAAM,GAAG,CAAC,CAAC;EAChF,IAAA,CAAC,MAAM;EACL,MAAA,MAAM+V,MAAM,GAAG,CAACrE,eAAe,EAAE8H,cAAc,CAAC,CAAC9R,QAAQ,CAACpC,KAAK,CAAC7I,GAAG,CAAC;EACpEk1B,MAAAA,iBAAiB,GAAG7tB,oBAAoB,CAACqJ,QAAQ,EAAE7H,KAAK,CAAC3B,MAAM,EAAEoS,MAAM,EAAE,IAAI,CAAC;EAChF,IAAA;EAEA,IAAA,IAAI4b,iBAAiB,EAAE;QACrBA,iBAAiB,CAAC/V,KAAK,CAAC;EAAEgW,QAAAA,aAAa,EAAE;EAAK,OAAC,CAAC;QAChDZ,GAAG,CAACzkB,mBAAmB,CAAColB,iBAAiB,CAAC,CAACrZ,IAAI,EAAE;EACnD,IAAA;EACF,EAAA;EAEA4Y,EAAAA,YAAYA,GAAG;EAAE;MACf,OAAOnkB,cAAc,CAACxG,IAAI,CAACuqB,mBAAmB,EAAE,IAAI,CAACxV,OAAO,CAAC;EAC/D,EAAA;EAEAgW,EAAAA,cAAcA,GAAG;EACf,IAAA,OAAO,IAAI,CAACJ,YAAY,EAAE,CAAC3qB,IAAI,CAAC6G,KAAK,IAAI,IAAI,CAACgkB,aAAa,CAAChkB,KAAK,CAAC,CAAC,IAAI,IAAI;EAC7E,EAAA;EAEA6jB,EAAAA,qBAAqBA,CAACvZ,MAAM,EAAEvK,QAAQ,EAAE;MACtC,IAAI,CAAC0kB,wBAAwB,CAACna,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC;EAExD,IAAA,KAAK,MAAMtK,KAAK,IAAID,QAAQ,EAAE;EAC5B,MAAA,IAAI,CAAC2kB,4BAA4B,CAAC1kB,KAAK,CAAC;EAC1C,IAAA;EACF,EAAA;IAEA0kB,4BAA4BA,CAAC1kB,KAAK,EAAE;EAClCA,IAAAA,KAAK,GAAG,IAAI,CAAC2kB,gBAAgB,CAAC3kB,KAAK,CAAC;EACpC,IAAA,MAAM4kB,QAAQ,GAAG,IAAI,CAACZ,aAAa,CAAChkB,KAAK,CAAC;EAC1C,IAAA,MAAM6kB,SAAS,GAAG,IAAI,CAACC,gBAAgB,CAAC9kB,KAAK,CAAC;EAC9CA,IAAAA,KAAK,CAACxD,YAAY,CAAC,eAAe,EAAEooB,QAAQ,CAAC;MAE7C,IAAIC,SAAS,KAAK7kB,KAAK,EAAE;QACvB,IAAI,CAACykB,wBAAwB,CAACI,SAAS,EAAE,MAAM,EAAE,cAAc,CAAC;EAClE,IAAA;MAEA,IAAI,CAACD,QAAQ,EAAE;EACb5kB,MAAAA,KAAK,CAACxD,YAAY,CAAC,UAAU,EAAE,IAAI,CAAC;EACtC,IAAA;MAEA,IAAI,CAACioB,wBAAwB,CAACzkB,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC;;EAEnD;EACA,IAAA,IAAI,CAAC+kB,kCAAkC,CAAC/kB,KAAK,CAAC;EAChD,EAAA;IAEA+kB,kCAAkCA,CAAC/kB,KAAK,EAAE;EACxC,IAAA,MAAMzJ,MAAM,GAAGoJ,cAAc,CAACkB,sBAAsB,CAACb,KAAK,CAAC;MAE3D,IAAI,CAACzJ,MAAM,EAAE;EACX,MAAA;EACF,IAAA;MAEA,IAAI,CAACkuB,wBAAwB,CAACluB,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC;MAEzD,IAAIyJ,KAAK,CAACpP,EAAE,EAAE;EACZ,MAAA,IAAI,CAAC6zB,wBAAwB,CAACluB,MAAM,EAAE,iBAAiB,EAAE,CAAA,EAAGyJ,KAAK,CAACpP,EAAE,CAAA,CAAE,CAAC;EACzE,IAAA;EACF,EAAA;EAEA0zB,EAAAA,eAAeA,CAACl1B,OAAO,EAAE41B,IAAI,EAAE;EAC7B,IAAA,MAAMH,SAAS,GAAG,IAAI,CAACC,gBAAgB,CAAC11B,OAAO,CAAC;MAChD,IAAI,CAACy1B,SAAS,CAACpxB,SAAS,CAACC,QAAQ,CAAC0vB,cAAc,CAAC,EAAE;EACjD,MAAA;EACF,IAAA;EAEA,IAAA,MAAMjhB,MAAM,GAAGA,CAAC7R,QAAQ,EAAEkgB,SAAS,KAAK;QACtC,MAAMphB,OAAO,GAAGuQ,cAAc,CAACG,OAAO,CAACxP,QAAQ,EAAEu0B,SAAS,CAAC;EAC3D,MAAA,IAAIz1B,OAAO,EAAE;UACXA,OAAO,CAACqE,SAAS,CAAC0O,MAAM,CAACqO,SAAS,EAAEwU,IAAI,CAAC;EAC3C,MAAA;MACF,CAAC;EAED7iB,IAAAA,MAAM,CAACme,wBAAwB,EAAEve,iBAAiB,CAAC;EACnDI,IAAAA,MAAM,CAACkhB,sBAAsB,EAAE9hB,iBAAe,CAAC;EAC/CsjB,IAAAA,SAAS,CAACroB,YAAY,CAAC,eAAe,EAAEwoB,IAAI,CAAC;EAC/C,EAAA;EAEAP,EAAAA,wBAAwBA,CAACr1B,OAAO,EAAEwpB,SAAS,EAAEhd,KAAK,EAAE;EAClD,IAAA,IAAI,CAACxM,OAAO,CAACwE,YAAY,CAACglB,SAAS,CAAC,EAAE;EACpCxpB,MAAAA,OAAO,CAACoN,YAAY,CAACoc,SAAS,EAAEhd,KAAK,CAAC;EACxC,IAAA;EACF,EAAA;IAEAooB,aAAaA,CAACrZ,IAAI,EAAE;EAClB,IAAA,OAAOA,IAAI,CAAClX,SAAS,CAACC,QAAQ,CAACqO,iBAAiB,CAAC;EACnD,EAAA;;EAEA;IACA4iB,gBAAgBA,CAACha,IAAI,EAAE;EACrB,IAAA,OAAOA,IAAI,CAAC1K,OAAO,CAACyjB,mBAAmB,CAAC,GAAG/Y,IAAI,GAAGhL,cAAc,CAACG,OAAO,CAAC4jB,mBAAmB,EAAE/Y,IAAI,CAAC;EACrG,EAAA;;EAEA;IACAma,gBAAgBA,CAACna,IAAI,EAAE;EACrB,IAAA,OAAOA,IAAI,CAACxX,OAAO,CAACqwB,cAAc,CAAC,IAAI7Y,IAAI;EAC7C,EAAA;;EAEA;IACA,OAAOlV,eAAeA,CAAC+H,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACoE,IAAI,CAAC,YAAY;EAC3B,MAAA,MAAMC,IAAI,GAAG+hB,GAAG,CAACzkB,mBAAmB,CAAC,IAAI,CAAC;EAE1C,MAAA,IAAI,OAAO3B,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA;EACF,MAAA;EAEA,MAAA,IAAIqE,IAAI,CAACrE,MAAM,CAAC,KAAKzM,SAAS,IAAIyM,MAAM,CAAC7C,UAAU,CAAC,GAAG,CAAC,IAAI6C,MAAM,KAAK,aAAa,EAAE;EACpF,QAAA,MAAM,IAAIY,SAAS,CAAC,CAAA,iBAAA,EAAoBZ,MAAM,GAAG,CAAC;EACpD,MAAA;EAEAqE,MAAAA,IAAI,CAACrE,MAAM,CAAC,EAAE;EAChB,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAlF,YAAY,CAACiC,EAAE,CAAC7I,QAAQ,EAAEuQ,oBAAoB,EAAED,oBAAoB,EAAE,UAAU9J,KAAK,EAAE;EACrF,EAAA,IAAI,CAAC,GAAG,EAAE,MAAM,CAAC,CAACoC,QAAQ,CAAC,IAAI,CAAC6G,OAAO,CAAC,EAAE;MACxCjJ,KAAK,CAACuD,cAAc,EAAE;EACxB,EAAA;EAEA,EAAA,IAAInI,UAAU,CAAC,IAAI,CAAC,EAAE;EACpB,IAAA;EACF,EAAA;IAEAswB,GAAG,CAACzkB,mBAAmB,CAAC,IAAI,CAAC,CAAC+L,IAAI,EAAE;EACtC,CAAC,CAAC;;EAEF;EACA;EACA;EACA5S,YAAY,CAACiC,EAAE,CAAChK,MAAM,EAAE2U,mBAAmB,EAAE,MAAM;IACjD,KAAK,MAAM9V,OAAO,IAAIuQ,cAAc,CAACxG,IAAI,CAACwqB,2BAA2B,CAAC,EAAE;EACtEC,IAAAA,GAAG,CAACzkB,mBAAmB,CAAC/P,OAAO,CAAC;EAClC,EAAA;EACF,CAAC,CAAC;EACF;EACA;EACA;;EAEA8F,kBAAkB,CAAC0uB,GAAG,CAAC;;ECxTvB;EACA;EACA;EACA;EACA;EACA;;;EAOA;EACA;EACA;;EAEA,MAAMtuB,IAAI,GAAG,OAAO;EACpB,MAAMqJ,QAAQ,GAAG,UAAU;EAC3B,MAAME,SAAS,GAAG,CAAA,CAAA,EAAIF,QAAQ,CAAA,CAAE;EAEhC,MAAMsmB,eAAe,GAAG,CAAA,SAAA,EAAYpmB,SAAS,CAAA,CAAE;EAC/C,MAAMqmB,cAAc,GAAG,CAAA,QAAA,EAAWrmB,SAAS,CAAA,CAAE;EAC7C,MAAMsS,aAAa,GAAG,CAAA,OAAA,EAAUtS,SAAS,CAAA,CAAE;EAC3C,MAAMqd,cAAc,GAAG,CAAA,QAAA,EAAWrd,SAAS,CAAA,CAAE;EAC7C,MAAM+K,UAAU,GAAG,CAAA,IAAA,EAAO/K,SAAS,CAAA,CAAE;EACrC,MAAMgL,YAAY,GAAG,CAAA,MAAA,EAAShL,SAAS,CAAA,CAAE;EACzC,MAAM6K,UAAU,GAAG,CAAA,IAAA,EAAO7K,SAAS,CAAA,CAAE;EACrC,MAAM8K,WAAW,GAAG,CAAA,KAAA,EAAQ9K,SAAS,CAAA,CAAE;EAEvC,MAAMyC,eAAe,GAAG,MAAM;EAC9B,MAAM6jB,eAAe,GAAG,MAAM,CAAA;EAC9B,MAAM5jB,eAAe,GAAG,MAAM;EAC9B,MAAMyU,kBAAkB,GAAG,SAAS;EAEpC,MAAM3Y,WAAW,GAAG;EAClBof,EAAAA,SAAS,EAAE,SAAS;EACpB2I,EAAAA,QAAQ,EAAE,SAAS;EACnBxI,EAAAA,KAAK,EAAE;EACT,CAAC;EAED,MAAMxf,OAAO,GAAG;EACdqf,EAAAA,SAAS,EAAE,IAAI;EACf2I,EAAAA,QAAQ,EAAE,IAAI;EACdxI,EAAAA,KAAK,EAAE;EACT,CAAC;;EAED;EACA;EACA;;EAEA,MAAMyI,KAAK,SAAS9mB,aAAa,CAAC;EAChCV,EAAAA,WAAWA,CAACzO,OAAO,EAAEoO,MAAM,EAAE;EAC3B,IAAA,KAAK,CAACpO,OAAO,EAAEoO,MAAM,CAAC;MAEtB,IAAI,CAACyf,QAAQ,GAAG,IAAI;MACpB,IAAI,CAACqI,oBAAoB,GAAG,KAAK;MACjC,IAAI,CAACC,uBAAuB,GAAG,KAAK;MACpC,IAAI,CAAChI,aAAa,EAAE;EACtB,EAAA;;EAEA;IACA,WAAWngB,OAAOA,GAAG;EACnB,IAAA,OAAOA,OAAO;EAChB,EAAA;IAEA,WAAWC,WAAWA,GAAG;EACvB,IAAA,OAAOA,WAAW;EACpB,EAAA;IAEA,WAAW/H,IAAIA,GAAG;EAChB,IAAA,OAAOA,IAAI;EACb,EAAA;;EAEA;EACA4V,EAAAA,IAAIA,GAAG;MACL,MAAMoD,SAAS,GAAGhW,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEkL,UAAU,CAAC;MAEjE,IAAI4E,SAAS,CAACnT,gBAAgB,EAAE;EAC9B,MAAA;EACF,IAAA;MAEA,IAAI,CAACqqB,aAAa,EAAE;EAEpB,IAAA,IAAI,IAAI,CAAC/mB,OAAO,CAACge,SAAS,EAAE;QAC1B,IAAI,CAACje,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAAC3C,eAAe,CAAC;EAC9C,IAAA;MAEA,MAAMoK,QAAQ,GAAGA,MAAM;QACrB,IAAI,CAAClN,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAACgmB,kBAAkB,CAAC;QAClD1d,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEmL,WAAW,CAAC;QAEhD,IAAI,CAAC8b,kBAAkB,EAAE;MAC3B,CAAC;MAED,IAAI,CAACjnB,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAACm1B,eAAe,CAAC,CAAA;EAC/C9wB,IAAAA,MAAM,CAAC,IAAI,CAACmK,QAAQ,CAAC;MACrB,IAAI,CAACA,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAAC1C,eAAe,EAAEyU,kBAAkB,CAAC;EAEhE,IAAA,IAAI,CAAChX,cAAc,CAAC0M,QAAQ,EAAE,IAAI,CAAClN,QAAQ,EAAE,IAAI,CAACC,OAAO,CAACge,SAAS,CAAC;EACtE,EAAA;EAEAxR,EAAAA,IAAIA,GAAG;EACL,IAAA,IAAI,CAAC,IAAI,CAACya,OAAO,EAAE,EAAE;EACnB,MAAA;EACF,IAAA;MAEA,MAAM9W,SAAS,GAAGtW,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEoL,UAAU,CAAC;MAEjE,IAAIgF,SAAS,CAACzT,gBAAgB,EAAE;EAC9B,MAAA;EACF,IAAA;MAEA,MAAMuQ,QAAQ,GAAGA,MAAM;QACrB,IAAI,CAAClN,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAACkhB,eAAe,CAAC,CAAA;QAC5C,IAAI,CAAC3mB,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAACgmB,kBAAkB,EAAEzU,eAAe,CAAC;QACnEjJ,YAAY,CAACyC,OAAO,CAAC,IAAI,CAACyD,QAAQ,EAAEqL,YAAY,CAAC;MACnD,CAAC;MAED,IAAI,CAACrL,QAAQ,CAAC/K,SAAS,CAACwQ,GAAG,CAAC+R,kBAAkB,CAAC;EAC/C,IAAA,IAAI,CAAChX,cAAc,CAAC0M,QAAQ,EAAE,IAAI,CAAClN,QAAQ,EAAE,IAAI,CAACC,OAAO,CAACge,SAAS,CAAC;EACtE,EAAA;EAEA7d,EAAAA,OAAOA,GAAG;MACR,IAAI,CAAC4mB,aAAa,EAAE;EAEpB,IAAA,IAAI,IAAI,CAACE,OAAO,EAAE,EAAE;QAClB,IAAI,CAAClnB,QAAQ,CAAC/K,SAAS,CAACzD,MAAM,CAACuR,eAAe,CAAC;EACjD,IAAA;MAEA,KAAK,CAAC3C,OAAO,EAAE;EACjB,EAAA;EAEA8mB,EAAAA,OAAOA,GAAG;MACR,OAAO,IAAI,CAAClnB,QAAQ,CAAC/K,SAAS,CAACC,QAAQ,CAAC6N,eAAe,CAAC;EAC1D,EAAA;;EAEA;EACAkkB,EAAAA,kBAAkBA,GAAG;EACnB,IAAA,IAAI,CAAC,IAAI,CAAChnB,OAAO,CAAC2mB,QAAQ,EAAE;EAC1B,MAAA;EACF,IAAA;EAEA,IAAA,IAAI,IAAI,CAACE,oBAAoB,IAAI,IAAI,CAACC,uBAAuB,EAAE;EAC7D,MAAA;EACF,IAAA;EAEA,IAAA,IAAI,CAACtI,QAAQ,GAAGxmB,UAAU,CAAC,MAAM;QAC/B,IAAI,CAACwU,IAAI,EAAE;EACb,IAAA,CAAC,EAAE,IAAI,CAACxM,OAAO,CAACme,KAAK,CAAC;EACxB,EAAA;EAEA+I,EAAAA,cAAcA,CAACztB,KAAK,EAAE0tB,aAAa,EAAE;MACnC,QAAQ1tB,KAAK,CAACM,IAAI;EAChB,MAAA,KAAK,WAAW;EAChB,MAAA,KAAK,UAAU;EAAE,QAAA;YACf,IAAI,CAAC8sB,oBAAoB,GAAGM,aAAa;EACzC,UAAA;EACF,QAAA;EAEA,MAAA,KAAK,SAAS;EACd,MAAA,KAAK,UAAU;EAAE,QAAA;YACf,IAAI,CAACL,uBAAuB,GAAGK,aAAa;EAC5C,UAAA;EACF,QAAA;EAKF;EAEA,IAAA,IAAIA,aAAa,EAAE;QACjB,IAAI,CAACJ,aAAa,EAAE;EACpB,MAAA;EACF,IAAA;EAEA,IAAA,MAAM5c,WAAW,GAAG1Q,KAAK,CAAC0B,aAAa;EACvC,IAAA,IAAI,IAAI,CAAC4E,QAAQ,KAAKoK,WAAW,IAAI,IAAI,CAACpK,QAAQ,CAAC9K,QAAQ,CAACkV,WAAW,CAAC,EAAE;EACxE,MAAA;EACF,IAAA;MAEA,IAAI,CAAC6c,kBAAkB,EAAE;EAC3B,EAAA;EAEAlI,EAAAA,aAAaA,GAAG;EACdjlB,IAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAEymB,eAAe,EAAE/sB,KAAK,IAAI,IAAI,CAACytB,cAAc,CAACztB,KAAK,EAAE,IAAI,CAAC,CAAC;EAC1FI,IAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAE0mB,cAAc,EAAEhtB,KAAK,IAAI,IAAI,CAACytB,cAAc,CAACztB,KAAK,EAAE,KAAK,CAAC,CAAC;EAC1FI,IAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAE2S,aAAa,EAAEjZ,KAAK,IAAI,IAAI,CAACytB,cAAc,CAACztB,KAAK,EAAE,IAAI,CAAC,CAAC;EACxFI,IAAAA,YAAY,CAACiC,EAAE,CAAC,IAAI,CAACiE,QAAQ,EAAE0d,cAAc,EAAEhkB,KAAK,IAAI,IAAI,CAACytB,cAAc,CAACztB,KAAK,EAAE,KAAK,CAAC,CAAC;EAC5F,EAAA;EAEAstB,EAAAA,aAAaA,GAAG;EACdrd,IAAAA,YAAY,CAAC,IAAI,CAAC8U,QAAQ,CAAC;MAC3B,IAAI,CAACA,QAAQ,GAAG,IAAI;EACtB,EAAA;;EAEA;IACA,OAAOxnB,eAAeA,CAAC+H,MAAM,EAAE;EAC7B,IAAA,OAAO,IAAI,CAACoE,IAAI,CAAC,YAAY;QAC3B,MAAMC,IAAI,GAAGwjB,KAAK,CAAClmB,mBAAmB,CAAC,IAAI,EAAE3B,MAAM,CAAC;EAEpD,MAAA,IAAI,OAAOA,MAAM,KAAK,QAAQ,EAAE;EAC9B,QAAA,IAAI,OAAOqE,IAAI,CAACrE,MAAM,CAAC,KAAK,WAAW,EAAE;EACvC,UAAA,MAAM,IAAIY,SAAS,CAAC,CAAA,iBAAA,EAAoBZ,MAAM,GAAG,CAAC;EACpD,QAAA;EAEAqE,QAAAA,IAAI,CAACrE,MAAM,CAAC,CAAC,IAAI,CAAC;EACpB,MAAA;EACF,IAAA,CAAC,CAAC;EACJ,EAAA;EACF;;EAEA;EACA;EACA;;EAEAuD,oBAAoB,CAACskB,KAAK,CAAC;;EAE3B;EACA;EACA;;EAEAnwB,kBAAkB,CAACmwB,KAAK,CAAC;;EC7NzB;EACA;EACA;EACA;EACA;EACA;;AAeA,oBAAe;IACb7jB,KAAK;IACLU,MAAM;IACNqE,QAAQ;IACRgE,QAAQ;IACRyD,QAAQ;IACRsG,KAAK;IACL8B,SAAS;IACTsJ,OAAO;IACPgB,SAAS;IACTkD,GAAG;IACHyB,KAAK;EACLtI,EAAAA;EACF,CAAC;;;;;;;;"} \ No newline at end of file diff --git a/extensions/pagetop-bootsier/static/scss/_customs.scss b/extensions/pagetop-bootsier/static/scss/_customs.scss new file mode 100644 index 0000000..988d705 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/_customs.scss @@ -0,0 +1,108 @@ +// Enable CSS Grid +$enable-grid-classes: false; +$enable-cssgrid: true; + +// Opacity +.bg-opacity-0 { + --bs-bg-opacity: 0; +} + +.border-opacity-0 { + --bs-border-opacity: 0; +} + +.text-opacity-0 { + --bs-text-opacity: 0; +} +.text-opacity-10 { + --bs-text-opacity: 0.1; +} + +// Extending utilities +$utilities: map-merge( + $utilities, + ( + // Individual border widths + "border-top": ( + property: border-top-width, + class: border-top, + values: $border-widths + ), + "border-end": ( + property: border-right-width, + class: border-end, + values: $border-widths + ), + "border-bottom": ( + property: border-bottom-width, + class: border-bottom, + values: $border-widths + ), + "border-start": ( + property: border-left-width, + class: border-start, + values: $border-widths + ), + // Individual rounded values + "rounded-top-start": ( + property: border-top-left-radius, + class: rounded-top-start, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-top-end": ( + property: border-top-right-radius, + class: rounded-top-end, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-bottom-start": ( + property: border-bottom-left-radius, + class: rounded-bottom-start, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-bottom-end": ( + property: border-bottom-right-radius, + class: rounded-bottom-end, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + ) +); diff --git a/extensions/pagetop-bootsier/static/scss/bootsier.scss b/extensions/pagetop-bootsier/static/scss/bootsier.scss new file mode 100644 index 0000000..0d52046 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootsier.scss @@ -0,0 +1,55 @@ +@import "bootstrap-5.3.8/mixins/banner"; +@include bsBanner(""); + + +// scss-docs-start import-stack +// Configuration +@import "bootstrap-5.3.8/functions"; +@import "bootstrap-5.3.8/variables"; +@import "bootstrap-5.3.8/variables-dark"; +@import "bootstrap-5.3.8/maps"; +@import "bootstrap-5.3.8/mixins"; +@import "bootstrap-5.3.8/utilities"; + +// Layout & components +@import "bootstrap-5.3.8/root"; +@import "bootstrap-5.3.8/reboot"; +@import "bootstrap-5.3.8/type"; +@import "bootstrap-5.3.8/images"; +@import "bootstrap-5.3.8/containers"; +@import "bootstrap-5.3.8/grid"; +@import "bootstrap-5.3.8/tables"; +@import "bootstrap-5.3.8/forms"; +@import "bootstrap-5.3.8/buttons"; +@import "bootstrap-5.3.8/transitions"; +@import "bootstrap-5.3.8/dropdown"; +@import "bootstrap-5.3.8/button-group"; +@import "bootstrap-5.3.8/nav"; +@import "bootstrap-5.3.8/navbar"; +@import "bootstrap-5.3.8/card"; +@import "bootstrap-5.3.8/accordion"; +@import "bootstrap-5.3.8/breadcrumb"; +@import "bootstrap-5.3.8/pagination"; +@import "bootstrap-5.3.8/badge"; +@import "bootstrap-5.3.8/alert"; +@import "bootstrap-5.3.8/progress"; +@import "bootstrap-5.3.8/list-group"; +@import "bootstrap-5.3.8/close"; +@import "bootstrap-5.3.8/toasts"; +@import "bootstrap-5.3.8/modal"; +@import "bootstrap-5.3.8/tooltip"; +@import "bootstrap-5.3.8/popover"; +@import "bootstrap-5.3.8/carousel"; +@import "bootstrap-5.3.8/spinners"; +@import "bootstrap-5.3.8/offcanvas"; +@import "bootstrap-5.3.8/placeholders"; + +// Helpers +@import "bootstrap-5.3.8/helpers"; + +// Custom definitions +@import "customs"; + +// Utilities +@import "bootstrap-5.3.8/utilities/api"; +// scss-docs-end import-stack diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_accordion.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_accordion.scss new file mode 100644 index 0000000..e9f267f --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_accordion.scss @@ -0,0 +1,153 @@ +// +// Base styles +// + +.accordion { + // scss-docs-start accordion-css-vars + --#{$prefix}accordion-color: #{$accordion-color}; + --#{$prefix}accordion-bg: #{$accordion-bg}; + --#{$prefix}accordion-transition: #{$accordion-transition}; + --#{$prefix}accordion-border-color: #{$accordion-border-color}; + --#{$prefix}accordion-border-width: #{$accordion-border-width}; + --#{$prefix}accordion-border-radius: #{$accordion-border-radius}; + --#{$prefix}accordion-inner-border-radius: #{$accordion-inner-border-radius}; + --#{$prefix}accordion-btn-padding-x: #{$accordion-button-padding-x}; + --#{$prefix}accordion-btn-padding-y: #{$accordion-button-padding-y}; + --#{$prefix}accordion-btn-color: #{$accordion-button-color}; + --#{$prefix}accordion-btn-bg: #{$accordion-button-bg}; + --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon)}; + --#{$prefix}accordion-btn-icon-width: #{$accordion-icon-width}; + --#{$prefix}accordion-btn-icon-transform: #{$accordion-icon-transform}; + --#{$prefix}accordion-btn-icon-transition: #{$accordion-icon-transition}; + --#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon)}; + --#{$prefix}accordion-btn-focus-box-shadow: #{$accordion-button-focus-box-shadow}; + --#{$prefix}accordion-body-padding-x: #{$accordion-body-padding-x}; + --#{$prefix}accordion-body-padding-y: #{$accordion-body-padding-y}; + --#{$prefix}accordion-active-color: #{$accordion-button-active-color}; + --#{$prefix}accordion-active-bg: #{$accordion-button-active-bg}; + // scss-docs-end accordion-css-vars +} + +.accordion-button { + position: relative; + display: flex; + align-items: center; + width: 100%; + padding: var(--#{$prefix}accordion-btn-padding-y) var(--#{$prefix}accordion-btn-padding-x); + @include font-size($font-size-base); + color: var(--#{$prefix}accordion-btn-color); + text-align: left; // Reset button style + background-color: var(--#{$prefix}accordion-btn-bg); + border: 0; + @include border-radius(0); + overflow-anchor: none; + @include transition(var(--#{$prefix}accordion-transition)); + + &:not(.collapsed) { + color: var(--#{$prefix}accordion-active-color); + background-color: var(--#{$prefix}accordion-active-bg); + box-shadow: inset 0 calc(-1 * var(--#{$prefix}accordion-border-width)) 0 var(--#{$prefix}accordion-border-color); // stylelint-disable-line function-disallowed-list + + &::after { + background-image: var(--#{$prefix}accordion-btn-active-icon); + transform: var(--#{$prefix}accordion-btn-icon-transform); + } + } + + // Accordion icon + &::after { + flex-shrink: 0; + width: var(--#{$prefix}accordion-btn-icon-width); + height: var(--#{$prefix}accordion-btn-icon-width); + margin-left: auto; + content: ""; + background-image: var(--#{$prefix}accordion-btn-icon); + background-repeat: no-repeat; + background-size: var(--#{$prefix}accordion-btn-icon-width); + @include transition(var(--#{$prefix}accordion-btn-icon-transition)); + } + + &:hover { + z-index: 2; + } + + &:focus { + z-index: 3; + outline: 0; + box-shadow: var(--#{$prefix}accordion-btn-focus-box-shadow); + } +} + +.accordion-header { + margin-bottom: 0; +} + +.accordion-item { + color: var(--#{$prefix}accordion-color); + background-color: var(--#{$prefix}accordion-bg); + border: var(--#{$prefix}accordion-border-width) solid var(--#{$prefix}accordion-border-color); + + &:first-of-type { + @include border-top-radius(var(--#{$prefix}accordion-border-radius)); + + > .accordion-header .accordion-button { + @include border-top-radius(var(--#{$prefix}accordion-inner-border-radius)); + } + } + + &:not(:first-of-type) { + border-top: 0; + } + + // Only set a border-radius on the last item if the accordion is collapsed + &:last-of-type { + @include border-bottom-radius(var(--#{$prefix}accordion-border-radius)); + + > .accordion-header .accordion-button { + &.collapsed { + @include border-bottom-radius(var(--#{$prefix}accordion-inner-border-radius)); + } + } + + > .accordion-collapse { + @include border-bottom-radius(var(--#{$prefix}accordion-border-radius)); + } + } +} + +.accordion-body { + padding: var(--#{$prefix}accordion-body-padding-y) var(--#{$prefix}accordion-body-padding-x); +} + + +// Flush accordion items +// +// Remove borders and border-radius to keep accordion items edge-to-edge. + +.accordion-flush { + > .accordion-item { + border-right: 0; + border-left: 0; + @include border-radius(0); + + &:first-child { border-top: 0; } + &:last-child { border-bottom: 0; } + + // stylelint-disable selector-max-class + > .accordion-collapse, + > .accordion-header .accordion-button, + > .accordion-header .accordion-button.collapsed { + @include border-radius(0); + } + // stylelint-enable selector-max-class + } +} + +@if $enable-dark-mode { + @include color-mode(dark) { + .accordion-button::after { + --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon-dark)}; + --#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon-dark)}; + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_alert.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_alert.scss new file mode 100644 index 0000000..b8cff9b --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_alert.scss @@ -0,0 +1,68 @@ +// +// Base styles +// + +.alert { + // scss-docs-start alert-css-vars + --#{$prefix}alert-bg: transparent; + --#{$prefix}alert-padding-x: #{$alert-padding-x}; + --#{$prefix}alert-padding-y: #{$alert-padding-y}; + --#{$prefix}alert-margin-bottom: #{$alert-margin-bottom}; + --#{$prefix}alert-color: inherit; + --#{$prefix}alert-border-color: transparent; + --#{$prefix}alert-border: #{$alert-border-width} solid var(--#{$prefix}alert-border-color); + --#{$prefix}alert-border-radius: #{$alert-border-radius}; + --#{$prefix}alert-link-color: inherit; + // scss-docs-end alert-css-vars + + position: relative; + padding: var(--#{$prefix}alert-padding-y) var(--#{$prefix}alert-padding-x); + margin-bottom: var(--#{$prefix}alert-margin-bottom); + color: var(--#{$prefix}alert-color); + background-color: var(--#{$prefix}alert-bg); + border: var(--#{$prefix}alert-border); + @include border-radius(var(--#{$prefix}alert-border-radius)); +} + +// Headings for larger alerts +.alert-heading { + // Specified to prevent conflicts of changing $headings-color + color: inherit; +} + +// Provide class for links that match alerts +.alert-link { + font-weight: $alert-link-font-weight; + color: var(--#{$prefix}alert-link-color); +} + + +// Dismissible alerts +// +// Expand the right padding and account for the close button's positioning. + +.alert-dismissible { + padding-right: $alert-dismissible-padding-r; + + // Adjust close link position + .btn-close { + position: absolute; + top: 0; + right: 0; + z-index: $stretched-link-z-index + 1; + padding: $alert-padding-y * 1.25 $alert-padding-x; + } +} + + +// scss-docs-start alert-modifiers +// Generate contextual modifier classes for colorizing the alert +@each $state in map-keys($theme-colors) { + .alert-#{$state} { + --#{$prefix}alert-color: var(--#{$prefix}#{$state}-text-emphasis); + --#{$prefix}alert-bg: var(--#{$prefix}#{$state}-bg-subtle); + --#{$prefix}alert-border-color: var(--#{$prefix}#{$state}-border-subtle); + --#{$prefix}alert-link-color: var(--#{$prefix}#{$state}-text-emphasis); + } +} +// scss-docs-end alert-modifiers diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_badge.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_badge.scss new file mode 100644 index 0000000..cc3d269 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_badge.scss @@ -0,0 +1,38 @@ +// Base class +// +// Requires one of the contextual, color modifier classes for `color` and +// `background-color`. + +.badge { + // scss-docs-start badge-css-vars + --#{$prefix}badge-padding-x: #{$badge-padding-x}; + --#{$prefix}badge-padding-y: #{$badge-padding-y}; + @include rfs($badge-font-size, --#{$prefix}badge-font-size); + --#{$prefix}badge-font-weight: #{$badge-font-weight}; + --#{$prefix}badge-color: #{$badge-color}; + --#{$prefix}badge-border-radius: #{$badge-border-radius}; + // scss-docs-end badge-css-vars + + display: inline-block; + padding: var(--#{$prefix}badge-padding-y) var(--#{$prefix}badge-padding-x); + @include font-size(var(--#{$prefix}badge-font-size)); + font-weight: var(--#{$prefix}badge-font-weight); + line-height: 1; + color: var(--#{$prefix}badge-color); + text-align: center; + white-space: nowrap; + vertical-align: baseline; + @include border-radius(var(--#{$prefix}badge-border-radius)); + @include gradient-bg(); + + // Empty badges collapse automatically + &:empty { + display: none; + } +} + +// Quick fix for badges in buttons +.btn .badge { + position: relative; + top: -1px; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_breadcrumb.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_breadcrumb.scss new file mode 100644 index 0000000..b8252ff --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_breadcrumb.scss @@ -0,0 +1,40 @@ +.breadcrumb { + // scss-docs-start breadcrumb-css-vars + --#{$prefix}breadcrumb-padding-x: #{$breadcrumb-padding-x}; + --#{$prefix}breadcrumb-padding-y: #{$breadcrumb-padding-y}; + --#{$prefix}breadcrumb-margin-bottom: #{$breadcrumb-margin-bottom}; + @include rfs($breadcrumb-font-size, --#{$prefix}breadcrumb-font-size); + --#{$prefix}breadcrumb-bg: #{$breadcrumb-bg}; + --#{$prefix}breadcrumb-border-radius: #{$breadcrumb-border-radius}; + --#{$prefix}breadcrumb-divider-color: #{$breadcrumb-divider-color}; + --#{$prefix}breadcrumb-item-padding-x: #{$breadcrumb-item-padding-x}; + --#{$prefix}breadcrumb-item-active-color: #{$breadcrumb-active-color}; + // scss-docs-end breadcrumb-css-vars + + display: flex; + flex-wrap: wrap; + padding: var(--#{$prefix}breadcrumb-padding-y) var(--#{$prefix}breadcrumb-padding-x); + margin-bottom: var(--#{$prefix}breadcrumb-margin-bottom); + @include font-size(var(--#{$prefix}breadcrumb-font-size)); + list-style: none; + background-color: var(--#{$prefix}breadcrumb-bg); + @include border-radius(var(--#{$prefix}breadcrumb-border-radius)); +} + +.breadcrumb-item { + // The separator between breadcrumbs (by default, a forward-slash: "/") + + .breadcrumb-item { + padding-left: var(--#{$prefix}breadcrumb-item-padding-x); + + &::before { + float: left; // Suppress inline spacings and underlining of the separator + padding-right: var(--#{$prefix}breadcrumb-item-padding-x); + color: var(--#{$prefix}breadcrumb-divider-color); + content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"}; + } + } + + &.active { + color: var(--#{$prefix}breadcrumb-item-active-color); + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_button-group.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_button-group.scss new file mode 100644 index 0000000..78e1252 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_button-group.scss @@ -0,0 +1,147 @@ +// Make the div behave like a button +.btn-group, +.btn-group-vertical { + position: relative; + display: inline-flex; + vertical-align: middle; // match .btn alignment given font-size hack above + + > .btn { + position: relative; + flex: 1 1 auto; + } + + // Bring the hover, focused, and "active" buttons to the front to overlay + // the borders properly + > .btn-check:checked + .btn, + > .btn-check:focus + .btn, + > .btn:hover, + > .btn:focus, + > .btn:active, + > .btn.active { + z-index: 1; + } +} + +// Optional: Group multiple button groups together for a toolbar +.btn-toolbar { + display: flex; + flex-wrap: wrap; + justify-content: flex-start; + + .input-group { + width: auto; + } +} + +.btn-group { + @include border-radius($btn-border-radius); + + // Prevent double borders when buttons are next to each other + > :not(.btn-check:first-child) + .btn, + > .btn-group:not(:first-child) { + margin-left: calc(-1 * #{$btn-border-width}); // stylelint-disable-line function-disallowed-list + } + + // Reset rounded corners + > .btn:not(:last-child):not(.dropdown-toggle), + > .btn.dropdown-toggle-split:first-child, + > .btn-group:not(:last-child) > .btn { + @include border-end-radius(0); + } + + // The left radius should be 0 if the button is: + // - the "third or more" child + // - the second child and the previous element isn't `.btn-check` (making it the first child visually) + // - part of a btn-group which isn't the first child + > .btn:nth-child(n + 3), + > :not(.btn-check) + .btn, + > .btn-group:not(:first-child) > .btn { + @include border-start-radius(0); + } +} + +// Sizing +// +// Remix the default button sizing classes into new ones for easier manipulation. + +.btn-group-sm > .btn { @extend .btn-sm; } +.btn-group-lg > .btn { @extend .btn-lg; } + + +// +// Split button dropdowns +// + +.dropdown-toggle-split { + padding-right: $btn-padding-x * .75; + padding-left: $btn-padding-x * .75; + + &::after, + .dropup &::after, + .dropend &::after { + margin-left: 0; + } + + .dropstart &::before { + margin-right: 0; + } +} + +.btn-sm + .dropdown-toggle-split { + padding-right: $btn-padding-x-sm * .75; + padding-left: $btn-padding-x-sm * .75; +} + +.btn-lg + .dropdown-toggle-split { + padding-right: $btn-padding-x-lg * .75; + padding-left: $btn-padding-x-lg * .75; +} + + +// The clickable button for toggling the menu +// Set the same inset shadow as the :active state +.btn-group.show .dropdown-toggle { + @include box-shadow($btn-active-box-shadow); + + // Show no shadow for `.btn-link` since it has no other button styles. + &.btn-link { + @include box-shadow(none); + } +} + + +// +// Vertical button groups +// + +.btn-group-vertical { + flex-direction: column; + align-items: flex-start; + justify-content: center; + + > .btn, + > .btn-group { + width: 100%; + } + + > .btn:not(:first-child), + > .btn-group:not(:first-child) { + margin-top: calc(-1 * #{$btn-border-width}); // stylelint-disable-line function-disallowed-list + } + + // Reset rounded corners + > .btn:not(:last-child):not(.dropdown-toggle), + > .btn-group:not(:last-child) > .btn { + @include border-bottom-radius(0); + } + + // The top radius should be 0 if the button is: + // - the "third or more" child + // - the second child and the previous element isn't `.btn-check` (making it the first child visually) + // - part of a btn-group which isn't the first child + > .btn:nth-child(n + 3), + > :not(.btn-check) + .btn, + > .btn-group:not(:first-child) > .btn { + @include border-top-radius(0); + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_buttons.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_buttons.scss new file mode 100644 index 0000000..caa4518 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_buttons.scss @@ -0,0 +1,216 @@ +// +// Base styles +// + +.btn { + // scss-docs-start btn-css-vars + --#{$prefix}btn-padding-x: #{$btn-padding-x}; + --#{$prefix}btn-padding-y: #{$btn-padding-y}; + --#{$prefix}btn-font-family: #{$btn-font-family}; + @include rfs($btn-font-size, --#{$prefix}btn-font-size); + --#{$prefix}btn-font-weight: #{$btn-font-weight}; + --#{$prefix}btn-line-height: #{$btn-line-height}; + --#{$prefix}btn-color: #{$btn-color}; + --#{$prefix}btn-bg: transparent; + --#{$prefix}btn-border-width: #{$btn-border-width}; + --#{$prefix}btn-border-color: transparent; + --#{$prefix}btn-border-radius: #{$btn-border-radius}; + --#{$prefix}btn-hover-border-color: transparent; + --#{$prefix}btn-box-shadow: #{$btn-box-shadow}; + --#{$prefix}btn-disabled-opacity: #{$btn-disabled-opacity}; + --#{$prefix}btn-focus-box-shadow: 0 0 0 #{$btn-focus-width} rgba(var(--#{$prefix}btn-focus-shadow-rgb), .5); + // scss-docs-end btn-css-vars + + display: inline-block; + padding: var(--#{$prefix}btn-padding-y) var(--#{$prefix}btn-padding-x); + font-family: var(--#{$prefix}btn-font-family); + @include font-size(var(--#{$prefix}btn-font-size)); + font-weight: var(--#{$prefix}btn-font-weight); + line-height: var(--#{$prefix}btn-line-height); + color: var(--#{$prefix}btn-color); + text-align: center; + text-decoration: if($link-decoration == none, null, none); + white-space: $btn-white-space; + vertical-align: middle; + cursor: if($enable-button-pointers, pointer, null); + user-select: none; + border: var(--#{$prefix}btn-border-width) solid var(--#{$prefix}btn-border-color); + @include border-radius(var(--#{$prefix}btn-border-radius)); + @include gradient-bg(var(--#{$prefix}btn-bg)); + @include box-shadow(var(--#{$prefix}btn-box-shadow)); + @include transition($btn-transition); + + &:hover { + color: var(--#{$prefix}btn-hover-color); + text-decoration: if($link-hover-decoration == underline, none, null); + background-color: var(--#{$prefix}btn-hover-bg); + border-color: var(--#{$prefix}btn-hover-border-color); + } + + .btn-check + &:hover { + // override for the checkbox/radio buttons + color: var(--#{$prefix}btn-color); + background-color: var(--#{$prefix}btn-bg); + border-color: var(--#{$prefix}btn-border-color); + } + + &:focus-visible { + color: var(--#{$prefix}btn-hover-color); + @include gradient-bg(var(--#{$prefix}btn-hover-bg)); + border-color: var(--#{$prefix}btn-hover-border-color); + outline: 0; + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + + .btn-check:focus-visible + & { + border-color: var(--#{$prefix}btn-hover-border-color); + outline: 0; + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + + .btn-check:checked + &, + :not(.btn-check) + &:active, + &:first-child:active, + &.active, + &.show { + color: var(--#{$prefix}btn-active-color); + background-color: var(--#{$prefix}btn-active-bg); + // Remove CSS gradients if they're enabled + background-image: if($enable-gradients, none, null); + border-color: var(--#{$prefix}btn-active-border-color); + @include box-shadow(var(--#{$prefix}btn-active-shadow)); + + &:focus-visible { + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + } + + .btn-check:checked:focus-visible + & { + // Avoid using mixin so we can pass custom focus shadow properly + @if $enable-shadows { + box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow); + } @else { + box-shadow: var(--#{$prefix}btn-focus-box-shadow); + } + } + + &:disabled, + &.disabled, + fieldset:disabled & { + color: var(--#{$prefix}btn-disabled-color); + pointer-events: none; + background-color: var(--#{$prefix}btn-disabled-bg); + background-image: if($enable-gradients, none, null); + border-color: var(--#{$prefix}btn-disabled-border-color); + opacity: var(--#{$prefix}btn-disabled-opacity); + @include box-shadow(none); + } +} + + +// +// Alternate buttons +// + +// scss-docs-start btn-variant-loops +@each $color, $value in $theme-colors { + .btn-#{$color} { + @if $color == "light" { + @include button-variant( + $value, + $value, + $hover-background: shade-color($value, $btn-hover-bg-shade-amount), + $hover-border: shade-color($value, $btn-hover-border-shade-amount), + $active-background: shade-color($value, $btn-active-bg-shade-amount), + $active-border: shade-color($value, $btn-active-border-shade-amount) + ); + } @else if $color == "dark" { + @include button-variant( + $value, + $value, + $hover-background: tint-color($value, $btn-hover-bg-tint-amount), + $hover-border: tint-color($value, $btn-hover-border-tint-amount), + $active-background: tint-color($value, $btn-active-bg-tint-amount), + $active-border: tint-color($value, $btn-active-border-tint-amount) + ); + } @else { + @include button-variant($value, $value); + } + } +} + +@each $color, $value in $theme-colors { + .btn-outline-#{$color} { + @include button-outline-variant($value); + } +} +// scss-docs-end btn-variant-loops + + +// +// Link buttons +// + +// Make a button look and behave like a link +.btn-link { + --#{$prefix}btn-font-weight: #{$font-weight-normal}; + --#{$prefix}btn-color: #{$btn-link-color}; + --#{$prefix}btn-bg: transparent; + --#{$prefix}btn-border-color: transparent; + --#{$prefix}btn-hover-color: #{$btn-link-hover-color}; + --#{$prefix}btn-hover-border-color: transparent; + --#{$prefix}btn-active-color: #{$btn-link-hover-color}; + --#{$prefix}btn-active-border-color: transparent; + --#{$prefix}btn-disabled-color: #{$btn-link-disabled-color}; + --#{$prefix}btn-disabled-border-color: transparent; + --#{$prefix}btn-box-shadow: 0 0 0 #000; // Can't use `none` as keyword negates all values when used with multiple shadows + --#{$prefix}btn-focus-shadow-rgb: #{$btn-link-focus-shadow-rgb}; + + text-decoration: $link-decoration; + @if $enable-gradients { + background-image: none; + } + + &:hover, + &:focus-visible { + text-decoration: $link-hover-decoration; + } + + &:focus-visible { + color: var(--#{$prefix}btn-color); + } + + &:hover { + color: var(--#{$prefix}btn-hover-color); + } + + // No need for an active state here +} + + +// +// Button Sizes +// + +.btn-lg { + @include button-size($btn-padding-y-lg, $btn-padding-x-lg, $btn-font-size-lg, $btn-border-radius-lg); +} + +.btn-sm { + @include button-size($btn-padding-y-sm, $btn-padding-x-sm, $btn-font-size-sm, $btn-border-radius-sm); +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_card.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_card.scss new file mode 100644 index 0000000..dcebe6a --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_card.scss @@ -0,0 +1,238 @@ +// +// Base styles +// + +.card { + // scss-docs-start card-css-vars + --#{$prefix}card-spacer-y: #{$card-spacer-y}; + --#{$prefix}card-spacer-x: #{$card-spacer-x}; + --#{$prefix}card-title-spacer-y: #{$card-title-spacer-y}; + --#{$prefix}card-title-color: #{$card-title-color}; + --#{$prefix}card-subtitle-color: #{$card-subtitle-color}; + --#{$prefix}card-border-width: #{$card-border-width}; + --#{$prefix}card-border-color: #{$card-border-color}; + --#{$prefix}card-border-radius: #{$card-border-radius}; + --#{$prefix}card-box-shadow: #{$card-box-shadow}; + --#{$prefix}card-inner-border-radius: #{$card-inner-border-radius}; + --#{$prefix}card-cap-padding-y: #{$card-cap-padding-y}; + --#{$prefix}card-cap-padding-x: #{$card-cap-padding-x}; + --#{$prefix}card-cap-bg: #{$card-cap-bg}; + --#{$prefix}card-cap-color: #{$card-cap-color}; + --#{$prefix}card-height: #{$card-height}; + --#{$prefix}card-color: #{$card-color}; + --#{$prefix}card-bg: #{$card-bg}; + --#{$prefix}card-img-overlay-padding: #{$card-img-overlay-padding}; + --#{$prefix}card-group-margin: #{$card-group-margin}; + // scss-docs-end card-css-vars + + position: relative; + display: flex; + flex-direction: column; + min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106 + height: var(--#{$prefix}card-height); + color: var(--#{$prefix}body-color); + word-wrap: break-word; + background-color: var(--#{$prefix}card-bg); + background-clip: border-box; + border: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color); + @include border-radius(var(--#{$prefix}card-border-radius)); + @include box-shadow(var(--#{$prefix}card-box-shadow)); + + > hr { + margin-right: 0; + margin-left: 0; + } + + > .list-group { + border-top: inherit; + border-bottom: inherit; + + &:first-child { + border-top-width: 0; + @include border-top-radius(var(--#{$prefix}card-inner-border-radius)); + } + + &:last-child { + border-bottom-width: 0; + @include border-bottom-radius(var(--#{$prefix}card-inner-border-radius)); + } + } + + // Due to specificity of the above selector (`.card > .list-group`), we must + // use a child selector here to prevent double borders. + > .card-header + .list-group, + > .list-group + .card-footer { + border-top: 0; + } +} + +.card-body { + // Enable `flex-grow: 1` for decks and groups so that card blocks take up + // as much space as possible, ensuring footers are aligned to the bottom. + flex: 1 1 auto; + padding: var(--#{$prefix}card-spacer-y) var(--#{$prefix}card-spacer-x); + color: var(--#{$prefix}card-color); +} + +.card-title { + margin-bottom: var(--#{$prefix}card-title-spacer-y); + color: var(--#{$prefix}card-title-color); +} + +.card-subtitle { + margin-top: calc(-.5 * var(--#{$prefix}card-title-spacer-y)); // stylelint-disable-line function-disallowed-list + margin-bottom: 0; + color: var(--#{$prefix}card-subtitle-color); +} + +.card-text:last-child { + margin-bottom: 0; +} + +.card-link { + &:hover { + text-decoration: if($link-hover-decoration == underline, none, null); + } + + + .card-link { + margin-left: var(--#{$prefix}card-spacer-x); + } +} + +// +// Optional textual caps +// + +.card-header { + padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x); + margin-bottom: 0; // Removes the default margin-bottom of <hN> + color: var(--#{$prefix}card-cap-color); + background-color: var(--#{$prefix}card-cap-bg); + border-bottom: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color); + + &:first-child { + @include border-radius(var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius) 0 0); + } +} + +.card-footer { + padding: var(--#{$prefix}card-cap-padding-y) var(--#{$prefix}card-cap-padding-x); + color: var(--#{$prefix}card-cap-color); + background-color: var(--#{$prefix}card-cap-bg); + border-top: var(--#{$prefix}card-border-width) solid var(--#{$prefix}card-border-color); + + &:last-child { + @include border-radius(0 0 var(--#{$prefix}card-inner-border-radius) var(--#{$prefix}card-inner-border-radius)); + } +} + + +// +// Header navs +// + +.card-header-tabs { + margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list + margin-bottom: calc(-1 * var(--#{$prefix}card-cap-padding-y)); // stylelint-disable-line function-disallowed-list + margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list + border-bottom: 0; + + .nav-link.active { + background-color: var(--#{$prefix}card-bg); + border-bottom-color: var(--#{$prefix}card-bg); + } +} + +.card-header-pills { + margin-right: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list + margin-left: calc(-.5 * var(--#{$prefix}card-cap-padding-x)); // stylelint-disable-line function-disallowed-list +} + +// Card image +.card-img-overlay { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + padding: var(--#{$prefix}card-img-overlay-padding); + @include border-radius(var(--#{$prefix}card-inner-border-radius)); +} + +.card-img, +.card-img-top, +.card-img-bottom { + width: 100%; // Required because we use flexbox and this inherently applies align-self: stretch +} + +.card-img, +.card-img-top { + @include border-top-radius(var(--#{$prefix}card-inner-border-radius)); +} + +.card-img, +.card-img-bottom { + @include border-bottom-radius(var(--#{$prefix}card-inner-border-radius)); +} + + +// +// Card groups +// + +.card-group { + // The child selector allows nested `.card` within `.card-group` + // to display properly. + > .card { + margin-bottom: var(--#{$prefix}card-group-margin); + } + + @include media-breakpoint-up(sm) { + display: flex; + flex-flow: row wrap; + // The child selector allows nested `.card` within `.card-group` + // to display properly. + > .card { + flex: 1 0 0; + margin-bottom: 0; + + + .card { + margin-left: 0; + border-left: 0; + } + + // Handle rounded corners + @if $enable-rounded { + &:not(:last-child) { + @include border-end-radius(0); + + > .card-img-top, + > .card-header { + // stylelint-disable-next-line property-disallowed-list + border-top-right-radius: 0; + } + > .card-img-bottom, + > .card-footer { + // stylelint-disable-next-line property-disallowed-list + border-bottom-right-radius: 0; + } + } + + &:not(:first-child) { + @include border-start-radius(0); + + > .card-img-top, + > .card-header { + // stylelint-disable-next-line property-disallowed-list + border-top-left-radius: 0; + } + > .card-img-bottom, + > .card-footer { + // stylelint-disable-next-line property-disallowed-list + border-bottom-left-radius: 0; + } + } + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_carousel.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_carousel.scss new file mode 100644 index 0000000..5ebf6b1 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_carousel.scss @@ -0,0 +1,226 @@ +// Notes on the classes: +// +// 1. .carousel.pointer-event should ideally be pan-y (to allow for users to scroll vertically) +// even when their scroll action started on a carousel, but for compatibility (with Firefox) +// we're preventing all actions instead +// 2. The .carousel-item-start and .carousel-item-end is used to indicate where +// the active slide is heading. +// 3. .active.carousel-item is the current slide. +// 4. .active.carousel-item-start and .active.carousel-item-end is the current +// slide in its in-transition state. Only one of these occurs at a time. +// 5. .carousel-item-next.carousel-item-start and .carousel-item-prev.carousel-item-end +// is the upcoming slide in transition. + +.carousel { + position: relative; +} + +.carousel.pointer-event { + touch-action: pan-y; +} + +.carousel-inner { + position: relative; + width: 100%; + overflow: hidden; + @include clearfix(); +} + +.carousel-item { + position: relative; + display: none; + float: left; + width: 100%; + margin-right: -100%; + backface-visibility: hidden; + @include transition($carousel-transition); +} + +.carousel-item.active, +.carousel-item-next, +.carousel-item-prev { + display: block; +} + +.carousel-item-next:not(.carousel-item-start), +.active.carousel-item-end { + transform: translateX(100%); +} + +.carousel-item-prev:not(.carousel-item-end), +.active.carousel-item-start { + transform: translateX(-100%); +} + + +// +// Alternate transitions +// + +.carousel-fade { + .carousel-item { + opacity: 0; + transition-property: opacity; + transform: none; + } + + .carousel-item.active, + .carousel-item-next.carousel-item-start, + .carousel-item-prev.carousel-item-end { + z-index: 1; + opacity: 1; + } + + .active.carousel-item-start, + .active.carousel-item-end { + z-index: 0; + opacity: 0; + @include transition(opacity 0s $carousel-transition-duration); + } +} + + +// +// Left/right controls for nav +// + +.carousel-control-prev, +.carousel-control-next { + position: absolute; + top: 0; + bottom: 0; + z-index: 1; + // Use flex for alignment (1-3) + display: flex; // 1. allow flex styles + align-items: center; // 2. vertically center contents + justify-content: center; // 3. horizontally center contents + width: $carousel-control-width; + padding: 0; + color: $carousel-control-color; + text-align: center; + background: none; + filter: var(--#{$prefix}carousel-control-icon-filter); + border: 0; + opacity: $carousel-control-opacity; + @include transition($carousel-control-transition); + + // Hover/focus state + &:hover, + &:focus { + color: $carousel-control-color; + text-decoration: none; + outline: 0; + opacity: $carousel-control-hover-opacity; + } +} +.carousel-control-prev { + left: 0; + background-image: if($enable-gradients, linear-gradient(90deg, rgba($black, .25), rgba($black, .001)), null); +} +.carousel-control-next { + right: 0; + background-image: if($enable-gradients, linear-gradient(270deg, rgba($black, .25), rgba($black, .001)), null); +} + +// Icons for within +.carousel-control-prev-icon, +.carousel-control-next-icon { + display: inline-block; + width: $carousel-control-icon-width; + height: $carousel-control-icon-width; + background-repeat: no-repeat; + background-position: 50%; + background-size: 100% 100%; +} + +.carousel-control-prev-icon { + background-image: escape-svg($carousel-control-prev-icon-bg) #{"/*rtl:" + escape-svg($carousel-control-next-icon-bg) + "*/"}; +} +.carousel-control-next-icon { + background-image: escape-svg($carousel-control-next-icon-bg) #{"/*rtl:" + escape-svg($carousel-control-prev-icon-bg) + "*/"}; +} + +// Optional indicator pips/controls +// +// Add a container (such as a list) with the following class and add an item (ideally a focusable control, +// like a button) with data-bs-target for each slide your carousel holds. + +.carousel-indicators { + position: absolute; + right: 0; + bottom: 0; + left: 0; + z-index: 2; + display: flex; + justify-content: center; + padding: 0; + // Use the .carousel-control's width as margin so we don't overlay those + margin-right: $carousel-control-width; + margin-bottom: 1rem; + margin-left: $carousel-control-width; + + [data-bs-target] { + box-sizing: content-box; + flex: 0 1 auto; + width: $carousel-indicator-width; + height: $carousel-indicator-height; + padding: 0; + margin-right: $carousel-indicator-spacer; + margin-left: $carousel-indicator-spacer; + text-indent: -999px; + cursor: pointer; + background-color: var(--#{$prefix}carousel-indicator-active-bg); + background-clip: padding-box; + border: 0; + // Use transparent borders to increase the hit area by 10px on top and bottom. + border-top: $carousel-indicator-hit-area-height solid transparent; + border-bottom: $carousel-indicator-hit-area-height solid transparent; + opacity: $carousel-indicator-opacity; + @include transition($carousel-indicator-transition); + } + + .active { + opacity: $carousel-indicator-active-opacity; + } +} + + +// Optional captions +// +// + +.carousel-caption { + position: absolute; + right: (100% - $carousel-caption-width) * .5; + bottom: $carousel-caption-spacer; + left: (100% - $carousel-caption-width) * .5; + padding-top: $carousel-caption-padding-y; + padding-bottom: $carousel-caption-padding-y; + color: var(--#{$prefix}carousel-caption-color); + text-align: center; +} + +// Dark mode carousel + +@mixin carousel-dark() { + --#{$prefix}carousel-indicator-active-bg: #{$carousel-indicator-active-bg-dark}; + --#{$prefix}carousel-caption-color: #{$carousel-caption-color-dark}; + --#{$prefix}carousel-control-icon-filter: #{$carousel-control-icon-filter-dark}; +} + +.carousel-dark { + @include carousel-dark(); +} + +:root, +[data-bs-theme="light"] { + --#{$prefix}carousel-indicator-active-bg: #{$carousel-indicator-active-bg}; + --#{$prefix}carousel-caption-color: #{$carousel-caption-color}; + --#{$prefix}carousel-control-icon-filter: #{$carousel-control-icon-filter}; +} + +@if $enable-dark-mode { + @include color-mode(dark, true) { + @include carousel-dark(); + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_close.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_close.scss new file mode 100644 index 0000000..d53c96f --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_close.scss @@ -0,0 +1,66 @@ +// Transparent background and border properties included for button version. +// iOS requires the button element instead of an anchor tag. +// If you want the anchor version, it requires `href="#"`. +// See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile + +.btn-close { + // scss-docs-start close-css-vars + --#{$prefix}btn-close-color: #{$btn-close-color}; + --#{$prefix}btn-close-bg: #{ escape-svg($btn-close-bg) }; + --#{$prefix}btn-close-opacity: #{$btn-close-opacity}; + --#{$prefix}btn-close-hover-opacity: #{$btn-close-hover-opacity}; + --#{$prefix}btn-close-focus-shadow: #{$btn-close-focus-shadow}; + --#{$prefix}btn-close-focus-opacity: #{$btn-close-focus-opacity}; + --#{$prefix}btn-close-disabled-opacity: #{$btn-close-disabled-opacity}; + // scss-docs-end close-css-vars + + box-sizing: content-box; + width: $btn-close-width; + height: $btn-close-height; + padding: $btn-close-padding-y $btn-close-padding-x; + color: var(--#{$prefix}btn-close-color); + background: transparent var(--#{$prefix}btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements + filter: var(--#{$prefix}btn-close-filter); + border: 0; // for button elements + @include border-radius(); + opacity: var(--#{$prefix}btn-close-opacity); + + // Override <a>'s hover style + &:hover { + color: var(--#{$prefix}btn-close-color); + text-decoration: none; + opacity: var(--#{$prefix}btn-close-hover-opacity); + } + + &:focus { + outline: 0; + box-shadow: var(--#{$prefix}btn-close-focus-shadow); + opacity: var(--#{$prefix}btn-close-focus-opacity); + } + + &:disabled, + &.disabled { + pointer-events: none; + user-select: none; + opacity: var(--#{$prefix}btn-close-disabled-opacity); + } +} + +@mixin btn-close-white() { + --#{$prefix}btn-close-filter: #{$btn-close-filter-dark}; +} + +.btn-close-white { + @include btn-close-white(); +} + +:root, +[data-bs-theme="light"] { + --#{$prefix}btn-close-filter: #{$btn-close-filter}; +} + +@if $enable-dark-mode { + @include color-mode(dark, true) { + @include btn-close-white(); + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_containers.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_containers.scss new file mode 100644 index 0000000..83b3138 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_containers.scss @@ -0,0 +1,41 @@ +// Container widths +// +// Set the container width, and override it for fixed navbars in media queries. + +@if $enable-container-classes { + // Single container class with breakpoint max-widths + .container, + // 100% wide container at all breakpoints + .container-fluid { + @include make-container(); + } + + // Responsive containers that are 100% wide until a breakpoint + @each $breakpoint, $container-max-width in $container-max-widths { + .container-#{$breakpoint} { + @extend .container-fluid; + } + + @include media-breakpoint-up($breakpoint, $grid-breakpoints) { + %responsive-container-#{$breakpoint} { + max-width: $container-max-width; + } + + // Extend each breakpoint which is smaller or equal to the current breakpoint + $extend-breakpoint: true; + + @each $name, $width in $grid-breakpoints { + @if ($extend-breakpoint) { + .container#{breakpoint-infix($name, $grid-breakpoints)} { + @extend %responsive-container-#{$breakpoint}; + } + + // Once the current breakpoint is reached, stop extending + @if ($breakpoint == $name) { + $extend-breakpoint: false; + } + } + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_dropdown.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_dropdown.scss new file mode 100644 index 0000000..587ebb4 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_dropdown.scss @@ -0,0 +1,250 @@ +// The dropdown wrapper (`<div>`) +.dropup, +.dropend, +.dropdown, +.dropstart, +.dropup-center, +.dropdown-center { + position: relative; +} + +.dropdown-toggle { + white-space: nowrap; + + // Generate the caret automatically + @include caret(); +} + +// The dropdown menu +.dropdown-menu { + // scss-docs-start dropdown-css-vars + --#{$prefix}dropdown-zindex: #{$zindex-dropdown}; + --#{$prefix}dropdown-min-width: #{$dropdown-min-width}; + --#{$prefix}dropdown-padding-x: #{$dropdown-padding-x}; + --#{$prefix}dropdown-padding-y: #{$dropdown-padding-y}; + --#{$prefix}dropdown-spacer: #{$dropdown-spacer}; + @include rfs($dropdown-font-size, --#{$prefix}dropdown-font-size); + --#{$prefix}dropdown-color: #{$dropdown-color}; + --#{$prefix}dropdown-bg: #{$dropdown-bg}; + --#{$prefix}dropdown-border-color: #{$dropdown-border-color}; + --#{$prefix}dropdown-border-radius: #{$dropdown-border-radius}; + --#{$prefix}dropdown-border-width: #{$dropdown-border-width}; + --#{$prefix}dropdown-inner-border-radius: #{$dropdown-inner-border-radius}; + --#{$prefix}dropdown-divider-bg: #{$dropdown-divider-bg}; + --#{$prefix}dropdown-divider-margin-y: #{$dropdown-divider-margin-y}; + --#{$prefix}dropdown-box-shadow: #{$dropdown-box-shadow}; + --#{$prefix}dropdown-link-color: #{$dropdown-link-color}; + --#{$prefix}dropdown-link-hover-color: #{$dropdown-link-hover-color}; + --#{$prefix}dropdown-link-hover-bg: #{$dropdown-link-hover-bg}; + --#{$prefix}dropdown-link-active-color: #{$dropdown-link-active-color}; + --#{$prefix}dropdown-link-active-bg: #{$dropdown-link-active-bg}; + --#{$prefix}dropdown-link-disabled-color: #{$dropdown-link-disabled-color}; + --#{$prefix}dropdown-item-padding-x: #{$dropdown-item-padding-x}; + --#{$prefix}dropdown-item-padding-y: #{$dropdown-item-padding-y}; + --#{$prefix}dropdown-header-color: #{$dropdown-header-color}; + --#{$prefix}dropdown-header-padding-x: #{$dropdown-header-padding-x}; + --#{$prefix}dropdown-header-padding-y: #{$dropdown-header-padding-y}; + // scss-docs-end dropdown-css-vars + + position: absolute; + z-index: var(--#{$prefix}dropdown-zindex); + display: none; // none by default, but block on "open" of the menu + min-width: var(--#{$prefix}dropdown-min-width); + padding: var(--#{$prefix}dropdown-padding-y) var(--#{$prefix}dropdown-padding-x); + margin: 0; // Override default margin of ul + @include font-size(var(--#{$prefix}dropdown-font-size)); + color: var(--#{$prefix}dropdown-color); + text-align: left; // Ensures proper alignment if parent has it changed (e.g., modal footer) + list-style: none; + background-color: var(--#{$prefix}dropdown-bg); + background-clip: padding-box; + border: var(--#{$prefix}dropdown-border-width) solid var(--#{$prefix}dropdown-border-color); + @include border-radius(var(--#{$prefix}dropdown-border-radius)); + @include box-shadow(var(--#{$prefix}dropdown-box-shadow)); + + &[data-bs-popper] { + top: 100%; + left: 0; + margin-top: var(--#{$prefix}dropdown-spacer); + } + + @if $dropdown-padding-y == 0 { + > .dropdown-item:first-child, + > li:first-child .dropdown-item { + @include border-top-radius(var(--#{$prefix}dropdown-inner-border-radius)); + } + > .dropdown-item:last-child, + > li:last-child .dropdown-item { + @include border-bottom-radius(var(--#{$prefix}dropdown-inner-border-radius)); + } + + } +} + +// scss-docs-start responsive-breakpoints +// We deliberately hardcode the `bs-` prefix because we check +// this custom property in JS to determine Popper's positioning + +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + .dropdown-menu#{$infix}-start { + --bs-position: start; + + &[data-bs-popper] { + right: auto; + left: 0; + } + } + + .dropdown-menu#{$infix}-end { + --bs-position: end; + + &[data-bs-popper] { + right: 0; + left: auto; + } + } + } +} +// scss-docs-end responsive-breakpoints + +// Allow for dropdowns to go bottom up (aka, dropup-menu) +// Just add .dropup after the standard .dropdown class and you're set. +.dropup { + .dropdown-menu[data-bs-popper] { + top: auto; + bottom: 100%; + margin-top: 0; + margin-bottom: var(--#{$prefix}dropdown-spacer); + } + + .dropdown-toggle { + @include caret(up); + } +} + +.dropend { + .dropdown-menu[data-bs-popper] { + top: 0; + right: auto; + left: 100%; + margin-top: 0; + margin-left: var(--#{$prefix}dropdown-spacer); + } + + .dropdown-toggle { + @include caret(end); + &::after { + vertical-align: 0; + } + } +} + +.dropstart { + .dropdown-menu[data-bs-popper] { + top: 0; + right: 100%; + left: auto; + margin-top: 0; + margin-right: var(--#{$prefix}dropdown-spacer); + } + + .dropdown-toggle { + @include caret(start); + &::before { + vertical-align: 0; + } + } +} + + +// Dividers (basically an `<hr>`) within the dropdown +.dropdown-divider { + height: 0; + margin: var(--#{$prefix}dropdown-divider-margin-y) 0; + overflow: hidden; + border-top: 1px solid var(--#{$prefix}dropdown-divider-bg); + opacity: 1; // Revisit in v6 to de-dupe styles that conflict with <hr> element +} + +// Links, buttons, and more within the dropdown menu +// +// `<button>`-specific styles are denoted with `// For <button>s` +.dropdown-item { + display: block; + width: 100%; // For `<button>`s + padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x); + clear: both; + font-weight: $font-weight-normal; + color: var(--#{$prefix}dropdown-link-color); + text-align: inherit; // For `<button>`s + text-decoration: if($link-decoration == none, null, none); + white-space: nowrap; // prevent links from randomly breaking onto new lines + background-color: transparent; // For `<button>`s + border: 0; // For `<button>`s + @include border-radius(var(--#{$prefix}dropdown-item-border-radius, 0)); + + &:hover, + &:focus { + color: var(--#{$prefix}dropdown-link-hover-color); + text-decoration: if($link-hover-decoration == underline, none, null); + @include gradient-bg(var(--#{$prefix}dropdown-link-hover-bg)); + } + + &.active, + &:active { + color: var(--#{$prefix}dropdown-link-active-color); + text-decoration: none; + @include gradient-bg(var(--#{$prefix}dropdown-link-active-bg)); + } + + &.disabled, + &:disabled { + color: var(--#{$prefix}dropdown-link-disabled-color); + pointer-events: none; + background-color: transparent; + // Remove CSS gradients if they're enabled + background-image: if($enable-gradients, none, null); + } +} + +.dropdown-menu.show { + display: block; +} + +// Dropdown section headers +.dropdown-header { + display: block; + padding: var(--#{$prefix}dropdown-header-padding-y) var(--#{$prefix}dropdown-header-padding-x); + margin-bottom: 0; // for use with heading elements + @include font-size($font-size-sm); + color: var(--#{$prefix}dropdown-header-color); + white-space: nowrap; // as with > li > a +} + +// Dropdown text +.dropdown-item-text { + display: block; + padding: var(--#{$prefix}dropdown-item-padding-y) var(--#{$prefix}dropdown-item-padding-x); + color: var(--#{$prefix}dropdown-link-color); +} + +// Dark dropdowns +.dropdown-menu-dark { + // scss-docs-start dropdown-dark-css-vars + --#{$prefix}dropdown-color: #{$dropdown-dark-color}; + --#{$prefix}dropdown-bg: #{$dropdown-dark-bg}; + --#{$prefix}dropdown-border-color: #{$dropdown-dark-border-color}; + --#{$prefix}dropdown-box-shadow: #{$dropdown-dark-box-shadow}; + --#{$prefix}dropdown-link-color: #{$dropdown-dark-link-color}; + --#{$prefix}dropdown-link-hover-color: #{$dropdown-dark-link-hover-color}; + --#{$prefix}dropdown-divider-bg: #{$dropdown-dark-divider-bg}; + --#{$prefix}dropdown-link-hover-bg: #{$dropdown-dark-link-hover-bg}; + --#{$prefix}dropdown-link-active-color: #{$dropdown-dark-link-active-color}; + --#{$prefix}dropdown-link-active-bg: #{$dropdown-dark-link-active-bg}; + --#{$prefix}dropdown-link-disabled-color: #{$dropdown-dark-link-disabled-color}; + --#{$prefix}dropdown-header-color: #{$dropdown-dark-header-color}; + // scss-docs-end dropdown-dark-css-vars +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_forms.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_forms.scss new file mode 100644 index 0000000..7b17d84 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_forms.scss @@ -0,0 +1,9 @@ +@import "forms/labels"; +@import "forms/form-text"; +@import "forms/form-control"; +@import "forms/form-select"; +@import "forms/form-check"; +@import "forms/form-range"; +@import "forms/floating-labels"; +@import "forms/input-group"; +@import "forms/validation"; diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_functions.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_functions.scss new file mode 100644 index 0000000..59d431a --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_functions.scss @@ -0,0 +1,302 @@ +// Bootstrap functions +// +// Utility mixins and functions for evaluating source code across our variables, maps, and mixins. + +// Ascending +// Used to evaluate Sass maps like our grid breakpoints. +@mixin _assert-ascending($map, $map-name) { + $prev-key: null; + $prev-num: null; + @each $key, $num in $map { + @if $prev-num == null or unit($num) == "%" or unit($prev-num) == "%" { + // Do nothing + } @else if not comparable($prev-num, $num) { + @warn "Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !"; + } @else if $prev-num >= $num { + @warn "Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !"; + } + $prev-key: $key; + $prev-num: $num; + } +} + +// Starts at zero +// Used to ensure the min-width of the lowest breakpoint starts at 0. +@mixin _assert-starts-at-zero($map, $map-name: "$grid-breakpoints") { + @if length($map) > 0 { + $values: map-values($map); + $first-value: nth($values, 1); + @if $first-value != 0 { + @warn "First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}."; + } + } +} + +// Colors +@function to-rgb($value) { + @return red($value), green($value), blue($value); +} + +// stylelint-disable scss/dollar-variable-pattern +@function rgba-css-var($identifier, $target) { + @if $identifier == "body" and $target == "bg" { + @return rgba(var(--#{$prefix}#{$identifier}-bg-rgb), var(--#{$prefix}#{$target}-opacity)); + } @if $identifier == "body" and $target == "text" { + @return rgba(var(--#{$prefix}#{$identifier}-color-rgb), var(--#{$prefix}#{$target}-opacity)); + } @else { + @return rgba(var(--#{$prefix}#{$identifier}-rgb), var(--#{$prefix}#{$target}-opacity)); + } +} + +@function map-loop($map, $func, $args...) { + $_map: (); + + @each $key, $value in $map { + // allow to pass the $key and $value of the map as an function argument + $_args: (); + @each $arg in $args { + $_args: append($_args, if($arg == "$key", $key, if($arg == "$value", $value, $arg))); + } + + $_map: map-merge($_map, ($key: call(get-function($func), $_args...))); + } + + @return $_map; +} +// stylelint-enable scss/dollar-variable-pattern + +@function varify($list) { + $result: null; + @each $entry in $list { + $result: append($result, var(--#{$prefix}#{$entry}), space); + } + @return $result; +} + +// Internal Bootstrap function to turn maps into its negative variant. +// It prefixes the keys with `n` and makes the value negative. +@function negativify-map($map) { + $result: (); + @each $key, $value in $map { + @if $key != 0 { + $result: map-merge($result, ("n" + $key: (-$value))); + } + } + @return $result; +} + +// Get multiple keys from a sass map +@function map-get-multiple($map, $values) { + $result: (); + @each $key, $value in $map { + @if (index($values, $key) != null) { + $result: map-merge($result, ($key: $value)); + } + } + @return $result; +} + +// Merge multiple maps +@function map-merge-multiple($maps...) { + $merged-maps: (); + + @each $map in $maps { + $merged-maps: map-merge($merged-maps, $map); + } + @return $merged-maps; +} + +// Replace `$search` with `$replace` in `$string` +// Used on our SVG icon backgrounds for custom forms. +// +// @author Kitty Giraudel +// @param {String} $string - Initial string +// @param {String} $search - Substring to replace +// @param {String} $replace ('') - New value +// @return {String} - Updated string +@function str-replace($string, $search, $replace: "") { + $index: str-index($string, $search); + + @if $index { + @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace); + } + + @return $string; +} + +// See https://codepen.io/kevinweber/pen/dXWoRw +// +// Requires the use of quotes around data URIs. + +@function escape-svg($string) { + @if str-index($string, "data:image/svg+xml") { + @each $char, $encoded in $escaped-characters { + // Do not escape the url brackets + @if str-index($string, "url(") == 1 { + $string: url("#{str-replace(str-slice($string, 6, -3), $char, $encoded)}"); + } @else { + $string: str-replace($string, $char, $encoded); + } + } + } + + @return $string; +} + +// Color contrast +// See https://github.com/twbs/bootstrap/pull/30168 + +// A list of pre-calculated numbers of pow(divide((divide($value, 255) + .055), 1.055), 2.4). (from 0 to 255) +// stylelint-disable-next-line scss/dollar-variable-default, scss/dollar-variable-pattern +$_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 .0033 .0037 .004 .0044 .0048 .0052 .0056 .006 .0065 .007 .0075 .008 .0086 .0091 .0097 .0103 .011 .0116 .0123 .013 .0137 .0144 .0152 .016 .0168 .0176 .0185 .0194 .0203 .0212 .0222 .0232 .0242 .0252 .0262 .0273 .0284 .0296 .0307 .0319 .0331 .0343 .0356 .0369 .0382 .0395 .0409 .0423 .0437 .0452 .0467 .0482 .0497 .0513 .0529 .0545 .0561 .0578 .0595 .0612 .063 .0648 .0666 .0685 .0704 .0723 .0742 .0762 .0782 .0802 .0823 .0844 .0865 .0887 .0908 .0931 .0953 .0976 .0999 .1022 .1046 .107 .1095 .1119 .1144 .117 .1195 .1221 .1248 .1274 .1301 .1329 .1356 .1384 .1413 .1441 .147 .15 .1529 .1559 .159 .162 .1651 .1683 .1714 .1746 .1779 .1812 .1845 .1878 .1912 .1946 .1981 .2016 .2051 .2086 .2122 .2159 .2195 .2232 .227 .2307 .2346 .2384 .2423 .2462 .2502 .2542 .2582 .2623 .2664 .2705 .2747 .2789 .2831 .2874 .2918 .2961 .3005 .305 .3095 .314 .3185 .3231 .3278 .3325 .3372 .3419 .3467 .3515 .3564 .3613 .3663 .3712 .3763 .3813 .3864 .3916 .3968 .402 .4072 .4125 .4179 .4233 .4287 .4342 .4397 .4452 .4508 .4564 .4621 .4678 .4735 .4793 .4851 .491 .4969 .5029 .5089 .5149 .521 .5271 .5333 .5395 .5457 .552 .5583 .5647 .5711 .5776 .5841 .5906 .5972 .6038 .6105 .6172 .624 .6308 .6376 .6445 .6514 .6584 .6654 .6724 .6795 .6867 .6939 .7011 .7084 .7157 .7231 .7305 .7379 .7454 .7529 .7605 .7682 .7758 .7835 .7913 .7991 .807 .8148 .8228 .8308 .8388 .8469 .855 .8632 .8714 .8796 .8879 .8963 .9047 .9131 .9216 .9301 .9387 .9473 .956 .9647 .9734 .9823 .9911 1; + +@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light, $min-contrast-ratio: $min-contrast-ratio) { + $foregrounds: $color-contrast-light, $color-contrast-dark, $white, $black; + $max-ratio: 0; + $max-ratio-color: null; + + @each $color in $foregrounds { + $contrast-ratio: contrast-ratio($background, $color); + @if $contrast-ratio >= $min-contrast-ratio { + @return $color; + } @else if $contrast-ratio > $max-ratio { + $max-ratio: $contrast-ratio; + $max-ratio-color: $color; + } + } + + @warn "Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$background}..."; + + @return $max-ratio-color; +} + +@function contrast-ratio($background, $foreground: $color-contrast-light) { + $l1: luminance($background); + $l2: luminance(opaque($background, $foreground)); + + @return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05)); +} + +// Return WCAG2.2 relative luminance +// See https://www.w3.org/TR/WCAG/#dfn-relative-luminance +// See https://www.w3.org/TR/WCAG/#dfn-contrast-ratio +@function luminance($color) { + $rgb: ( + "r": red($color), + "g": green($color), + "b": blue($color) + ); + + @each $name, $value in $rgb { + $value: if(divide($value, 255) < .04045, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1)); + $rgb: map-merge($rgb, ($name: $value)); + } + + @return (map-get($rgb, "r") * .2126) + (map-get($rgb, "g") * .7152) + (map-get($rgb, "b") * .0722); +} + +// Return opaque color +// opaque(#fff, rgba(0, 0, 0, .5)) => #808080 +@function opaque($background, $foreground) { + @return mix(rgba($foreground, 1), $background, opacity($foreground) * 100%); +} + +// scss-docs-start color-functions +// Tint a color: mix a color with white +@function tint-color($color, $weight) { + @return mix(white, $color, $weight); +} + +// Shade a color: mix a color with black +@function shade-color($color, $weight) { + @return mix(black, $color, $weight); +} + +// Shade the color if the weight is positive, else tint it +@function shift-color($color, $weight) { + @return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight)); +} +// scss-docs-end color-functions + +// Return valid calc +@function add($value1, $value2, $return-calc: true) { + @if $value1 == null { + @return $value2; + } + + @if $value2 == null { + @return $value1; + } + + @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { + @return $value1 + $value2; + } + + @return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(" + ") + $value2); +} + +@function subtract($value1, $value2, $return-calc: true) { + @if $value1 == null and $value2 == null { + @return null; + } + + @if $value1 == null { + @return -$value2; + } + + @if $value2 == null { + @return $value1; + } + + @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) { + @return $value1 - $value2; + } + + @if type-of($value2) != number { + $value2: unquote("(") + $value2 + unquote(")"); + } + + @return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(" - ") + $value2); +} + +@function divide($dividend, $divisor, $precision: 10) { + $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1); + $dividend: abs($dividend); + $divisor: abs($divisor); + @if $dividend == 0 { + @return 0; + } + @if $divisor == 0 { + @error "Cannot divide by 0"; + } + $remainder: $dividend; + $result: 0; + $factor: 10; + @while ($remainder > 0 and $precision >= 0) { + $quotient: 0; + @while ($remainder >= $divisor) { + $remainder: $remainder - $divisor; + $quotient: $quotient + 1; + } + $result: $result * 10 + $quotient; + $factor: $factor * .1; + $remainder: $remainder * 10; + $precision: $precision - 1; + @if ($precision < 0 and $remainder >= $divisor * 5) { + $result: $result + 1; + } + } + $result: $result * $factor * $sign; + $dividend-unit: unit($dividend); + $divisor-unit: unit($divisor); + $unit-map: ( + "px": 1px, + "rem": 1rem, + "em": 1em, + "%": 1% + ); + @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) { + $result: $result * map-get($unit-map, $dividend-unit); + } + @return $result; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_grid.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_grid.scss new file mode 100644 index 0000000..048f800 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_grid.scss @@ -0,0 +1,39 @@ +// Row +// +// Rows contain your columns. + +:root { + @each $name, $value in $grid-breakpoints { + --#{$prefix}breakpoint-#{$name}: #{$value}; + } +} + +@if $enable-grid-classes { + .row { + @include make-row(); + + > * { + @include make-col-ready(); + } + } +} + +@if $enable-cssgrid { + .grid { + display: grid; + grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr); + grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr); + gap: var(--#{$prefix}gap, #{$grid-gutter-width}); + + @include make-cssgrid(); + } +} + + +// Columns +// +// Common styles for small and large grid columns + +@if $enable-grid-classes { + @include make-grid-columns(); +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_helpers.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_helpers.scss new file mode 100644 index 0000000..13f2752 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_helpers.scss @@ -0,0 +1,12 @@ +@import "helpers/clearfix"; +@import "helpers/color-bg"; +@import "helpers/colored-links"; +@import "helpers/focus-ring"; +@import "helpers/icon-link"; +@import "helpers/ratio"; +@import "helpers/position"; +@import "helpers/stacks"; +@import "helpers/visually-hidden"; +@import "helpers/stretched-link"; +@import "helpers/text-truncation"; +@import "helpers/vr"; diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_images.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_images.scss new file mode 100644 index 0000000..3d6a101 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_images.scss @@ -0,0 +1,42 @@ +// Responsive images (ensure images don't scale beyond their parents) +// +// This is purposefully opt-in via an explicit class rather than being the default for all `<img>`s. +// We previously tried the "images are responsive by default" approach in Bootstrap v2, +// and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps) +// which weren't expecting the images within themselves to be involuntarily resized. +// See also https://github.com/twbs/bootstrap/issues/18178 +.img-fluid { + @include img-fluid(); +} + + +// Image thumbnails +.img-thumbnail { + padding: $thumbnail-padding; + background-color: $thumbnail-bg; + border: $thumbnail-border-width solid $thumbnail-border-color; + @include border-radius($thumbnail-border-radius); + @include box-shadow($thumbnail-box-shadow); + + // Keep them at most 100% wide + @include img-fluid(); +} + +// +// Figures +// + +.figure { + // Ensures the caption's text aligns with the image. + display: inline-block; +} + +.figure-img { + margin-bottom: $spacer * .5; + line-height: 1; +} + +.figure-caption { + @include font-size($figure-caption-font-size); + color: $figure-caption-color; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_list-group.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_list-group.scss new file mode 100644 index 0000000..3bdff67 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_list-group.scss @@ -0,0 +1,199 @@ +// Base class +// +// Easily usable on <ul>, <ol>, or <div>. + +.list-group { + // scss-docs-start list-group-css-vars + --#{$prefix}list-group-color: #{$list-group-color}; + --#{$prefix}list-group-bg: #{$list-group-bg}; + --#{$prefix}list-group-border-color: #{$list-group-border-color}; + --#{$prefix}list-group-border-width: #{$list-group-border-width}; + --#{$prefix}list-group-border-radius: #{$list-group-border-radius}; + --#{$prefix}list-group-item-padding-x: #{$list-group-item-padding-x}; + --#{$prefix}list-group-item-padding-y: #{$list-group-item-padding-y}; + --#{$prefix}list-group-action-color: #{$list-group-action-color}; + --#{$prefix}list-group-action-hover-color: #{$list-group-action-hover-color}; + --#{$prefix}list-group-action-hover-bg: #{$list-group-hover-bg}; + --#{$prefix}list-group-action-active-color: #{$list-group-action-active-color}; + --#{$prefix}list-group-action-active-bg: #{$list-group-action-active-bg}; + --#{$prefix}list-group-disabled-color: #{$list-group-disabled-color}; + --#{$prefix}list-group-disabled-bg: #{$list-group-disabled-bg}; + --#{$prefix}list-group-active-color: #{$list-group-active-color}; + --#{$prefix}list-group-active-bg: #{$list-group-active-bg}; + --#{$prefix}list-group-active-border-color: #{$list-group-active-border-color}; + // scss-docs-end list-group-css-vars + + display: flex; + flex-direction: column; + + // No need to set list-style: none; since .list-group-item is block level + padding-left: 0; // reset padding because ul and ol + margin-bottom: 0; + @include border-radius(var(--#{$prefix}list-group-border-radius)); +} + +.list-group-numbered { + list-style-type: none; + counter-reset: section; + + > .list-group-item::before { + // Increments only this instance of the section counter + content: counters(section, ".") ". "; + counter-increment: section; + } +} + +// Individual list items +// +// Use on `li`s or `div`s within the `.list-group` parent. + +.list-group-item { + position: relative; + display: block; + padding: var(--#{$prefix}list-group-item-padding-y) var(--#{$prefix}list-group-item-padding-x); + color: var(--#{$prefix}list-group-color); + text-decoration: if($link-decoration == none, null, none); + background-color: var(--#{$prefix}list-group-bg); + border: var(--#{$prefix}list-group-border-width) solid var(--#{$prefix}list-group-border-color); + + &:first-child { + @include border-top-radius(inherit); + } + + &:last-child { + @include border-bottom-radius(inherit); + } + + &.disabled, + &:disabled { + color: var(--#{$prefix}list-group-disabled-color); + pointer-events: none; + background-color: var(--#{$prefix}list-group-disabled-bg); + } + + // Include both here for `<a>`s and `<button>`s + &.active { + z-index: 2; // Place active items above their siblings for proper border styling + color: var(--#{$prefix}list-group-active-color); + background-color: var(--#{$prefix}list-group-active-bg); + border-color: var(--#{$prefix}list-group-active-border-color); + } + + // stylelint-disable-next-line scss/selector-no-redundant-nesting-selector + & + .list-group-item { + border-top-width: 0; + + &.active { + margin-top: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list + border-top-width: var(--#{$prefix}list-group-border-width); + } + } +} + +// Interactive list items +// +// Use anchor or button elements instead of `li`s or `div`s to create interactive +// list items. Includes an extra `.active` modifier class for selected items. + +.list-group-item-action { + width: 100%; // For `<button>`s (anchors become 100% by default though) + color: var(--#{$prefix}list-group-action-color); + text-align: inherit; // For `<button>`s (anchors inherit) + + &:not(.active) { + // Hover state + &:hover, + &:focus { + z-index: 1; // Place hover/focus items above their siblings for proper border styling + color: var(--#{$prefix}list-group-action-hover-color); + text-decoration: none; + background-color: var(--#{$prefix}list-group-action-hover-bg); + } + + &:active { + color: var(--#{$prefix}list-group-action-active-color); + background-color: var(--#{$prefix}list-group-action-active-bg); + } + } +} + +// Horizontal +// +// Change the layout of list group items from vertical (default) to horizontal. + +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + .list-group-horizontal#{$infix} { + flex-direction: row; + + > .list-group-item { + &:first-child:not(:last-child) { + @include border-bottom-start-radius(var(--#{$prefix}list-group-border-radius)); + @include border-top-end-radius(0); + } + + &:last-child:not(:first-child) { + @include border-top-end-radius(var(--#{$prefix}list-group-border-radius)); + @include border-bottom-start-radius(0); + } + + &.active { + margin-top: 0; + } + + + .list-group-item { + border-top-width: var(--#{$prefix}list-group-border-width); + border-left-width: 0; + + &.active { + margin-left: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list + border-left-width: var(--#{$prefix}list-group-border-width); + } + } + } + } + } +} + + +// Flush list items +// +// Remove borders and border-radius to keep list group items edge-to-edge. Most +// useful within other components (e.g., cards). + +.list-group-flush { + @include border-radius(0); + + > .list-group-item { + border-width: 0 0 var(--#{$prefix}list-group-border-width); + + &:last-child { + border-bottom-width: 0; + } + } +} + + +// scss-docs-start list-group-modifiers +// List group contextual variants +// +// Add modifier classes to change text and background color on individual items. +// Organizationally, this must come after the `:hover` states. + +@each $state in map-keys($theme-colors) { + .list-group-item-#{$state} { + --#{$prefix}list-group-color: var(--#{$prefix}#{$state}-text-emphasis); + --#{$prefix}list-group-bg: var(--#{$prefix}#{$state}-bg-subtle); + --#{$prefix}list-group-border-color: var(--#{$prefix}#{$state}-border-subtle); + --#{$prefix}list-group-action-hover-color: var(--#{$prefix}emphasis-color); + --#{$prefix}list-group-action-hover-bg: var(--#{$prefix}#{$state}-border-subtle); + --#{$prefix}list-group-action-active-color: var(--#{$prefix}emphasis-color); + --#{$prefix}list-group-action-active-bg: var(--#{$prefix}#{$state}-border-subtle); + --#{$prefix}list-group-active-color: var(--#{$prefix}#{$state}-bg-subtle); + --#{$prefix}list-group-active-bg: var(--#{$prefix}#{$state}-text-emphasis); + --#{$prefix}list-group-active-border-color: var(--#{$prefix}#{$state}-text-emphasis); + } +} +// scss-docs-end list-group-modifiers diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_maps.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_maps.scss new file mode 100644 index 0000000..68ee421 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_maps.scss @@ -0,0 +1,174 @@ +// Re-assigned maps +// +// Placed here so that others can override the default Sass maps and see automatic updates to utilities and more. + +// scss-docs-start theme-colors-rgb +$theme-colors-rgb: map-loop($theme-colors, to-rgb, "$value") !default; +// scss-docs-end theme-colors-rgb + +// scss-docs-start theme-text-map +$theme-colors-text: ( + "primary": $primary-text-emphasis, + "secondary": $secondary-text-emphasis, + "success": $success-text-emphasis, + "info": $info-text-emphasis, + "warning": $warning-text-emphasis, + "danger": $danger-text-emphasis, + "light": $light-text-emphasis, + "dark": $dark-text-emphasis, +) !default; +// scss-docs-end theme-text-map + +// scss-docs-start theme-bg-subtle-map +$theme-colors-bg-subtle: ( + "primary": $primary-bg-subtle, + "secondary": $secondary-bg-subtle, + "success": $success-bg-subtle, + "info": $info-bg-subtle, + "warning": $warning-bg-subtle, + "danger": $danger-bg-subtle, + "light": $light-bg-subtle, + "dark": $dark-bg-subtle, +) !default; +// scss-docs-end theme-bg-subtle-map + +// scss-docs-start theme-border-subtle-map +$theme-colors-border-subtle: ( + "primary": $primary-border-subtle, + "secondary": $secondary-border-subtle, + "success": $success-border-subtle, + "info": $info-border-subtle, + "warning": $warning-border-subtle, + "danger": $danger-border-subtle, + "light": $light-border-subtle, + "dark": $dark-border-subtle, +) !default; +// scss-docs-end theme-border-subtle-map + +$theme-colors-text-dark: null !default; +$theme-colors-bg-subtle-dark: null !default; +$theme-colors-border-subtle-dark: null !default; + +@if $enable-dark-mode { + // scss-docs-start theme-text-dark-map + $theme-colors-text-dark: ( + "primary": $primary-text-emphasis-dark, + "secondary": $secondary-text-emphasis-dark, + "success": $success-text-emphasis-dark, + "info": $info-text-emphasis-dark, + "warning": $warning-text-emphasis-dark, + "danger": $danger-text-emphasis-dark, + "light": $light-text-emphasis-dark, + "dark": $dark-text-emphasis-dark, + ) !default; + // scss-docs-end theme-text-dark-map + + // scss-docs-start theme-bg-subtle-dark-map + $theme-colors-bg-subtle-dark: ( + "primary": $primary-bg-subtle-dark, + "secondary": $secondary-bg-subtle-dark, + "success": $success-bg-subtle-dark, + "info": $info-bg-subtle-dark, + "warning": $warning-bg-subtle-dark, + "danger": $danger-bg-subtle-dark, + "light": $light-bg-subtle-dark, + "dark": $dark-bg-subtle-dark, + ) !default; + // scss-docs-end theme-bg-subtle-dark-map + + // scss-docs-start theme-border-subtle-dark-map + $theme-colors-border-subtle-dark: ( + "primary": $primary-border-subtle-dark, + "secondary": $secondary-border-subtle-dark, + "success": $success-border-subtle-dark, + "info": $info-border-subtle-dark, + "warning": $warning-border-subtle-dark, + "danger": $danger-border-subtle-dark, + "light": $light-border-subtle-dark, + "dark": $dark-border-subtle-dark, + ) !default; + // scss-docs-end theme-border-subtle-dark-map +} + +// Utilities maps +// +// Extends the default `$theme-colors` maps to help create our utilities. + +// Come v6, we'll de-dupe these variables. Until then, for backward compatibility, we keep them to reassign. +// scss-docs-start utilities-colors +$utilities-colors: $theme-colors-rgb !default; +// scss-docs-end utilities-colors + +// scss-docs-start utilities-text-colors +$utilities-text: map-merge( + $utilities-colors, + ( + "black": to-rgb($black), + "white": to-rgb($white), + "body": to-rgb($body-color) + ) +) !default; +$utilities-text-colors: map-loop($utilities-text, rgba-css-var, "$key", "text") !default; + +$utilities-text-emphasis-colors: ( + "primary-emphasis": var(--#{$prefix}primary-text-emphasis), + "secondary-emphasis": var(--#{$prefix}secondary-text-emphasis), + "success-emphasis": var(--#{$prefix}success-text-emphasis), + "info-emphasis": var(--#{$prefix}info-text-emphasis), + "warning-emphasis": var(--#{$prefix}warning-text-emphasis), + "danger-emphasis": var(--#{$prefix}danger-text-emphasis), + "light-emphasis": var(--#{$prefix}light-text-emphasis), + "dark-emphasis": var(--#{$prefix}dark-text-emphasis) +) !default; +// scss-docs-end utilities-text-colors + +// scss-docs-start utilities-bg-colors +$utilities-bg: map-merge( + $utilities-colors, + ( + "black": to-rgb($black), + "white": to-rgb($white), + "body": to-rgb($body-bg) + ) +) !default; +$utilities-bg-colors: map-loop($utilities-bg, rgba-css-var, "$key", "bg") !default; + +$utilities-bg-subtle: ( + "primary-subtle": var(--#{$prefix}primary-bg-subtle), + "secondary-subtle": var(--#{$prefix}secondary-bg-subtle), + "success-subtle": var(--#{$prefix}success-bg-subtle), + "info-subtle": var(--#{$prefix}info-bg-subtle), + "warning-subtle": var(--#{$prefix}warning-bg-subtle), + "danger-subtle": var(--#{$prefix}danger-bg-subtle), + "light-subtle": var(--#{$prefix}light-bg-subtle), + "dark-subtle": var(--#{$prefix}dark-bg-subtle) +) !default; +// scss-docs-end utilities-bg-colors + +// scss-docs-start utilities-border-colors +$utilities-border: map-merge( + $utilities-colors, + ( + "black": to-rgb($black), + "white": to-rgb($white) + ) +) !default; +$utilities-border-colors: map-loop($utilities-border, rgba-css-var, "$key", "border") !default; + +$utilities-border-subtle: ( + "primary-subtle": var(--#{$prefix}primary-border-subtle), + "secondary-subtle": var(--#{$prefix}secondary-border-subtle), + "success-subtle": var(--#{$prefix}success-border-subtle), + "info-subtle": var(--#{$prefix}info-border-subtle), + "warning-subtle": var(--#{$prefix}warning-border-subtle), + "danger-subtle": var(--#{$prefix}danger-border-subtle), + "light-subtle": var(--#{$prefix}light-border-subtle), + "dark-subtle": var(--#{$prefix}dark-border-subtle) +) !default; +// scss-docs-end utilities-border-colors + +$utilities-links-underline: map-loop($utilities-colors, rgba-css-var, "$key", "link-underline") !default; + +$negative-spacers: if($enable-negative-margins, negativify-map($spacers), null) !default; + +$gutters: $spacers !default; diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_mixins.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_mixins.scss new file mode 100644 index 0000000..e1e130b --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_mixins.scss @@ -0,0 +1,42 @@ +// Toggles +// +// Used in conjunction with global variables to enable certain theme features. + +// Vendor +@import "vendor/rfs"; + +// Deprecate +@import "mixins/deprecate"; + +// Helpers +@import "mixins/breakpoints"; +@import "mixins/color-mode"; +@import "mixins/color-scheme"; +@import "mixins/image"; +@import "mixins/resize"; +@import "mixins/visually-hidden"; +@import "mixins/reset-text"; +@import "mixins/text-truncate"; + +// Utilities +@import "mixins/utilities"; + +// Components +@import "mixins/backdrop"; +@import "mixins/buttons"; +@import "mixins/caret"; +@import "mixins/pagination"; +@import "mixins/lists"; +@import "mixins/forms"; +@import "mixins/table-variants"; + +// Skins +@import "mixins/border-radius"; +@import "mixins/box-shadow"; +@import "mixins/gradients"; +@import "mixins/transition"; + +// Layout +@import "mixins/clearfix"; +@import "mixins/container"; +@import "mixins/grid"; diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_modal.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_modal.scss new file mode 100644 index 0000000..a3492c1 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_modal.scss @@ -0,0 +1,240 @@ +// stylelint-disable function-disallowed-list + +// .modal-open - body class for killing the scroll +// .modal - container to scroll within +// .modal-dialog - positioning shell for the actual modal +// .modal-content - actual modal w/ bg and corners and stuff + + +// Container that the modal scrolls within +.modal { + // scss-docs-start modal-css-vars + --#{$prefix}modal-zindex: #{$zindex-modal}; + --#{$prefix}modal-width: #{$modal-md}; + --#{$prefix}modal-padding: #{$modal-inner-padding}; + --#{$prefix}modal-margin: #{$modal-dialog-margin}; + --#{$prefix}modal-color: #{$modal-content-color}; + --#{$prefix}modal-bg: #{$modal-content-bg}; + --#{$prefix}modal-border-color: #{$modal-content-border-color}; + --#{$prefix}modal-border-width: #{$modal-content-border-width}; + --#{$prefix}modal-border-radius: #{$modal-content-border-radius}; + --#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-xs}; + --#{$prefix}modal-inner-border-radius: #{$modal-content-inner-border-radius}; + --#{$prefix}modal-header-padding-x: #{$modal-header-padding-x}; + --#{$prefix}modal-header-padding-y: #{$modal-header-padding-y}; + --#{$prefix}modal-header-padding: #{$modal-header-padding}; // Todo in v6: Split this padding into x and y + --#{$prefix}modal-header-border-color: #{$modal-header-border-color}; + --#{$prefix}modal-header-border-width: #{$modal-header-border-width}; + --#{$prefix}modal-title-line-height: #{$modal-title-line-height}; + --#{$prefix}modal-footer-gap: #{$modal-footer-margin-between}; + --#{$prefix}modal-footer-bg: #{$modal-footer-bg}; + --#{$prefix}modal-footer-border-color: #{$modal-footer-border-color}; + --#{$prefix}modal-footer-border-width: #{$modal-footer-border-width}; + // scss-docs-end modal-css-vars + + position: fixed; + top: 0; + left: 0; + z-index: var(--#{$prefix}modal-zindex); + display: none; + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; + // Prevent Chrome on Windows from adding a focus outline. For details, see + // https://github.com/twbs/bootstrap/pull/10951. + outline: 0; + // We deliberately don't use `-webkit-overflow-scrolling: touch;` due to a + // gnarly iOS Safari bug: https://bugs.webkit.org/show_bug.cgi?id=158342 + // See also https://github.com/twbs/bootstrap/issues/17695 +} + +// Shell div to position the modal with bottom padding +.modal-dialog { + position: relative; + width: auto; + margin: var(--#{$prefix}modal-margin); + // allow clicks to pass through for custom click handling to close modal + pointer-events: none; + + // When fading in the modal, animate it to slide down + .modal.fade & { + transform: $modal-fade-transform; + @include transition($modal-transition); + } + .modal.show & { + transform: $modal-show-transform; + } + + // When trying to close, animate focus to scale + .modal.modal-static & { + transform: $modal-scale-transform; + } +} + +.modal-dialog-scrollable { + height: calc(100% - var(--#{$prefix}modal-margin) * 2); + + .modal-content { + max-height: 100%; + overflow: hidden; + } + + .modal-body { + overflow-y: auto; + } +} + +.modal-dialog-centered { + display: flex; + align-items: center; + min-height: calc(100% - var(--#{$prefix}modal-margin) * 2); +} + +// Actual modal +.modal-content { + position: relative; + display: flex; + flex-direction: column; + width: 100%; // Ensure `.modal-content` extends the full width of the parent `.modal-dialog` + // counteract the pointer-events: none; in the .modal-dialog + color: var(--#{$prefix}modal-color); + pointer-events: auto; + background-color: var(--#{$prefix}modal-bg); + background-clip: padding-box; + border: var(--#{$prefix}modal-border-width) solid var(--#{$prefix}modal-border-color); + @include border-radius(var(--#{$prefix}modal-border-radius)); + @include box-shadow(var(--#{$prefix}modal-box-shadow)); + // Remove focus outline from opened modal + outline: 0; +} + +// Modal background +.modal-backdrop { + // scss-docs-start modal-backdrop-css-vars + --#{$prefix}backdrop-zindex: #{$zindex-modal-backdrop}; + --#{$prefix}backdrop-bg: #{$modal-backdrop-bg}; + --#{$prefix}backdrop-opacity: #{$modal-backdrop-opacity}; + // scss-docs-end modal-backdrop-css-vars + + @include overlay-backdrop(var(--#{$prefix}backdrop-zindex), var(--#{$prefix}backdrop-bg), var(--#{$prefix}backdrop-opacity)); +} + +// Modal header +// Top section of the modal w/ title and dismiss +.modal-header { + display: flex; + flex-shrink: 0; + align-items: center; + padding: var(--#{$prefix}modal-header-padding); + border-bottom: var(--#{$prefix}modal-header-border-width) solid var(--#{$prefix}modal-header-border-color); + @include border-top-radius(var(--#{$prefix}modal-inner-border-radius)); + + .btn-close { + padding: calc(var(--#{$prefix}modal-header-padding-y) * .5) calc(var(--#{$prefix}modal-header-padding-x) * .5); + // Split properties to avoid invalid calc() function if value is 0 + margin-top: calc(-.5 * var(--#{$prefix}modal-header-padding-y)); + margin-right: calc(-.5 * var(--#{$prefix}modal-header-padding-x)); + margin-bottom: calc(-.5 * var(--#{$prefix}modal-header-padding-y)); + margin-left: auto; + } +} + +// Title text within header +.modal-title { + margin-bottom: 0; + line-height: var(--#{$prefix}modal-title-line-height); +} + +// Modal body +// Where all modal content resides (sibling of .modal-header and .modal-footer) +.modal-body { + position: relative; + // Enable `flex-grow: 1` so that the body take up as much space as possible + // when there should be a fixed height on `.modal-dialog`. + flex: 1 1 auto; + padding: var(--#{$prefix}modal-padding); +} + +// Footer (for actions) +.modal-footer { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + align-items: center; // vertically center + justify-content: flex-end; // Right align buttons with flex property because text-align doesn't work on flex items + padding: calc(var(--#{$prefix}modal-padding) - var(--#{$prefix}modal-footer-gap) * .5); + background-color: var(--#{$prefix}modal-footer-bg); + border-top: var(--#{$prefix}modal-footer-border-width) solid var(--#{$prefix}modal-footer-border-color); + @include border-bottom-radius(var(--#{$prefix}modal-inner-border-radius)); + + // Place margin between footer elements + // This solution is far from ideal because of the universal selector usage, + // but is needed to fix https://github.com/twbs/bootstrap/issues/24800 + > * { + margin: calc(var(--#{$prefix}modal-footer-gap) * .5); // Todo in v6: replace with gap on parent class + } +} + +// Scale up the modal +@include media-breakpoint-up(sm) { + .modal { + --#{$prefix}modal-margin: #{$modal-dialog-margin-y-sm-up}; + --#{$prefix}modal-box-shadow: #{$modal-content-box-shadow-sm-up}; + } + + // Automatically set modal's width for larger viewports + .modal-dialog { + max-width: var(--#{$prefix}modal-width); + margin-right: auto; + margin-left: auto; + } + + .modal-sm { + --#{$prefix}modal-width: #{$modal-sm}; + } +} + +@include media-breakpoint-up(lg) { + .modal-lg, + .modal-xl { + --#{$prefix}modal-width: #{$modal-lg}; + } +} + +@include media-breakpoint-up(xl) { + .modal-xl { + --#{$prefix}modal-width: #{$modal-xl}; + } +} + +// scss-docs-start modal-fullscreen-loop +@each $breakpoint in map-keys($grid-breakpoints) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + $postfix: if($infix != "", $infix + "-down", ""); + + @include media-breakpoint-down($breakpoint) { + .modal-fullscreen#{$postfix} { + width: 100vw; + max-width: none; + height: 100%; + margin: 0; + + .modal-content { + height: 100%; + border: 0; + @include border-radius(0); + } + + .modal-header, + .modal-footer { + @include border-radius(0); + } + + .modal-body { + overflow-y: auto; + } + } + } +} +// scss-docs-end modal-fullscreen-loop diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_nav.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_nav.scss new file mode 100644 index 0000000..96fa528 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_nav.scss @@ -0,0 +1,197 @@ +// Base class +// +// Kickstart any navigation component with a set of style resets. Works with +// `<nav>`s, `<ul>`s or `<ol>`s. + +.nav { + // scss-docs-start nav-css-vars + --#{$prefix}nav-link-padding-x: #{$nav-link-padding-x}; + --#{$prefix}nav-link-padding-y: #{$nav-link-padding-y}; + @include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size); + --#{$prefix}nav-link-font-weight: #{$nav-link-font-weight}; + --#{$prefix}nav-link-color: #{$nav-link-color}; + --#{$prefix}nav-link-hover-color: #{$nav-link-hover-color}; + --#{$prefix}nav-link-disabled-color: #{$nav-link-disabled-color}; + // scss-docs-end nav-css-vars + + display: flex; + flex-wrap: wrap; + padding-left: 0; + margin-bottom: 0; + list-style: none; +} + +.nav-link { + display: block; + padding: var(--#{$prefix}nav-link-padding-y) var(--#{$prefix}nav-link-padding-x); + @include font-size(var(--#{$prefix}nav-link-font-size)); + font-weight: var(--#{$prefix}nav-link-font-weight); + color: var(--#{$prefix}nav-link-color); + text-decoration: if($link-decoration == none, null, none); + background: none; + border: 0; + @include transition($nav-link-transition); + + &:hover, + &:focus { + color: var(--#{$prefix}nav-link-hover-color); + text-decoration: if($link-hover-decoration == underline, none, null); + } + + &:focus-visible { + outline: 0; + box-shadow: $nav-link-focus-box-shadow; + } + + // Disabled state lightens text + &.disabled, + &:disabled { + color: var(--#{$prefix}nav-link-disabled-color); + pointer-events: none; + cursor: default; + } +} + +// +// Tabs +// + +.nav-tabs { + // scss-docs-start nav-tabs-css-vars + --#{$prefix}nav-tabs-border-width: #{$nav-tabs-border-width}; + --#{$prefix}nav-tabs-border-color: #{$nav-tabs-border-color}; + --#{$prefix}nav-tabs-border-radius: #{$nav-tabs-border-radius}; + --#{$prefix}nav-tabs-link-hover-border-color: #{$nav-tabs-link-hover-border-color}; + --#{$prefix}nav-tabs-link-active-color: #{$nav-tabs-link-active-color}; + --#{$prefix}nav-tabs-link-active-bg: #{$nav-tabs-link-active-bg}; + --#{$prefix}nav-tabs-link-active-border-color: #{$nav-tabs-link-active-border-color}; + // scss-docs-end nav-tabs-css-vars + + border-bottom: var(--#{$prefix}nav-tabs-border-width) solid var(--#{$prefix}nav-tabs-border-color); + + .nav-link { + margin-bottom: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list + border: var(--#{$prefix}nav-tabs-border-width) solid transparent; + @include border-top-radius(var(--#{$prefix}nav-tabs-border-radius)); + + &:hover, + &:focus { + // Prevents active .nav-link tab overlapping focus outline of previous/next .nav-link + isolation: isolate; + border-color: var(--#{$prefix}nav-tabs-link-hover-border-color); + } + } + + .nav-link.active, + .nav-item.show .nav-link { + color: var(--#{$prefix}nav-tabs-link-active-color); + background-color: var(--#{$prefix}nav-tabs-link-active-bg); + border-color: var(--#{$prefix}nav-tabs-link-active-border-color); + } + + .dropdown-menu { + // Make dropdown border overlap tab border + margin-top: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list + // Remove the top rounded corners here since there is a hard edge above the menu + @include border-top-radius(0); + } +} + + +// +// Pills +// + +.nav-pills { + // scss-docs-start nav-pills-css-vars + --#{$prefix}nav-pills-border-radius: #{$nav-pills-border-radius}; + --#{$prefix}nav-pills-link-active-color: #{$nav-pills-link-active-color}; + --#{$prefix}nav-pills-link-active-bg: #{$nav-pills-link-active-bg}; + // scss-docs-end nav-pills-css-vars + + .nav-link { + @include border-radius(var(--#{$prefix}nav-pills-border-radius)); + } + + .nav-link.active, + .show > .nav-link { + color: var(--#{$prefix}nav-pills-link-active-color); + @include gradient-bg(var(--#{$prefix}nav-pills-link-active-bg)); + } +} + + +// +// Underline +// + +.nav-underline { + // scss-docs-start nav-underline-css-vars + --#{$prefix}nav-underline-gap: #{$nav-underline-gap}; + --#{$prefix}nav-underline-border-width: #{$nav-underline-border-width}; + --#{$prefix}nav-underline-link-active-color: #{$nav-underline-link-active-color}; + // scss-docs-end nav-underline-css-vars + + gap: var(--#{$prefix}nav-underline-gap); + + .nav-link { + padding-right: 0; + padding-left: 0; + border-bottom: var(--#{$prefix}nav-underline-border-width) solid transparent; + + &:hover, + &:focus { + border-bottom-color: currentcolor; + } + } + + .nav-link.active, + .show > .nav-link { + font-weight: $font-weight-bold; + color: var(--#{$prefix}nav-underline-link-active-color); + border-bottom-color: currentcolor; + } +} + + +// +// Justified variants +// + +.nav-fill { + > .nav-link, + .nav-item { + flex: 1 1 auto; + text-align: center; + } +} + +.nav-justified { + > .nav-link, + .nav-item { + flex-grow: 1; + flex-basis: 0; + text-align: center; + } +} + +.nav-fill, +.nav-justified { + .nav-item .nav-link { + width: 100%; // Make sure button will grow + } +} + + +// Tabbable tabs +// +// Hide tabbable panes to start, show them when `.active` + +.tab-content { + > .tab-pane { + display: none; + } + > .active { + display: block; + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_navbar.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_navbar.scss new file mode 100644 index 0000000..86aa441 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_navbar.scss @@ -0,0 +1,289 @@ +// Navbar +// +// Provide a static navbar from which we expand to create full-width, fixed, and +// other navbar variations. + +.navbar { + // scss-docs-start navbar-css-vars + --#{$prefix}navbar-padding-x: #{if($navbar-padding-x == null, 0, $navbar-padding-x)}; + --#{$prefix}navbar-padding-y: #{$navbar-padding-y}; + --#{$prefix}navbar-color: #{$navbar-light-color}; + --#{$prefix}navbar-hover-color: #{$navbar-light-hover-color}; + --#{$prefix}navbar-disabled-color: #{$navbar-light-disabled-color}; + --#{$prefix}navbar-active-color: #{$navbar-light-active-color}; + --#{$prefix}navbar-brand-padding-y: #{$navbar-brand-padding-y}; + --#{$prefix}navbar-brand-margin-end: #{$navbar-brand-margin-end}; + --#{$prefix}navbar-brand-font-size: #{$navbar-brand-font-size}; + --#{$prefix}navbar-brand-color: #{$navbar-light-brand-color}; + --#{$prefix}navbar-brand-hover-color: #{$navbar-light-brand-hover-color}; + --#{$prefix}navbar-nav-link-padding-x: #{$navbar-nav-link-padding-x}; + --#{$prefix}navbar-toggler-padding-y: #{$navbar-toggler-padding-y}; + --#{$prefix}navbar-toggler-padding-x: #{$navbar-toggler-padding-x}; + --#{$prefix}navbar-toggler-font-size: #{$navbar-toggler-font-size}; + --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-light-toggler-icon-bg)}; + --#{$prefix}navbar-toggler-border-color: #{$navbar-light-toggler-border-color}; + --#{$prefix}navbar-toggler-border-radius: #{$navbar-toggler-border-radius}; + --#{$prefix}navbar-toggler-focus-width: #{$navbar-toggler-focus-width}; + --#{$prefix}navbar-toggler-transition: #{$navbar-toggler-transition}; + // scss-docs-end navbar-css-vars + + position: relative; + display: flex; + flex-wrap: wrap; // allow us to do the line break for collapsing content + align-items: center; + justify-content: space-between; // space out brand from logo + padding: var(--#{$prefix}navbar-padding-y) var(--#{$prefix}navbar-padding-x); + @include gradient-bg(); + + // Because flex properties aren't inherited, we need to redeclare these first + // few properties so that content nested within behave properly. + // The `flex-wrap` property is inherited to simplify the expanded navbars + %container-flex-properties { + display: flex; + flex-wrap: inherit; + align-items: center; + justify-content: space-between; + } + + > .container, + > .container-fluid { + @extend %container-flex-properties; + } + + @each $breakpoint, $container-max-width in $container-max-widths { + > .container#{breakpoint-infix($breakpoint, $container-max-widths)} { + @extend %container-flex-properties; + } + } +} + + +// Navbar brand +// +// Used for brand, project, or site names. + +.navbar-brand { + padding-top: var(--#{$prefix}navbar-brand-padding-y); + padding-bottom: var(--#{$prefix}navbar-brand-padding-y); + margin-right: var(--#{$prefix}navbar-brand-margin-end); + @include font-size(var(--#{$prefix}navbar-brand-font-size)); + color: var(--#{$prefix}navbar-brand-color); + text-decoration: if($link-decoration == none, null, none); + white-space: nowrap; + + &:hover, + &:focus { + color: var(--#{$prefix}navbar-brand-hover-color); + text-decoration: if($link-hover-decoration == underline, none, null); + } +} + + +// Navbar nav +// +// Custom navbar navigation (doesn't require `.nav`, but does make use of `.nav-link`). + +.navbar-nav { + // scss-docs-start navbar-nav-css-vars + --#{$prefix}nav-link-padding-x: 0; + --#{$prefix}nav-link-padding-y: #{$nav-link-padding-y}; + @include rfs($nav-link-font-size, --#{$prefix}nav-link-font-size); + --#{$prefix}nav-link-font-weight: #{$nav-link-font-weight}; + --#{$prefix}nav-link-color: var(--#{$prefix}navbar-color); + --#{$prefix}nav-link-hover-color: var(--#{$prefix}navbar-hover-color); + --#{$prefix}nav-link-disabled-color: var(--#{$prefix}navbar-disabled-color); + // scss-docs-end navbar-nav-css-vars + + display: flex; + flex-direction: column; // cannot use `inherit` to get the `.navbar`s value + padding-left: 0; + margin-bottom: 0; + list-style: none; + + .nav-link { + &.active, + &.show { + color: var(--#{$prefix}navbar-active-color); + } + } + + .dropdown-menu { + position: static; + } +} + + +// Navbar text +// +// + +.navbar-text { + padding-top: $nav-link-padding-y; + padding-bottom: $nav-link-padding-y; + color: var(--#{$prefix}navbar-color); + + a, + a:hover, + a:focus { + color: var(--#{$prefix}navbar-active-color); + } +} + + +// Responsive navbar +// +// Custom styles for responsive collapsing and toggling of navbar contents. +// Powered by the collapse Bootstrap JavaScript plugin. + +// When collapsed, prevent the toggleable navbar contents from appearing in +// the default flexbox row orientation. Requires the use of `flex-wrap: wrap` +// on the `.navbar` parent. +.navbar-collapse { + flex-grow: 1; + flex-basis: 100%; + // For always expanded or extra full navbars, ensure content aligns itself + // properly vertically. Can be easily overridden with flex utilities. + align-items: center; +} + +// Button for toggling the navbar when in its collapsed state +.navbar-toggler { + padding: var(--#{$prefix}navbar-toggler-padding-y) var(--#{$prefix}navbar-toggler-padding-x); + @include font-size(var(--#{$prefix}navbar-toggler-font-size)); + line-height: 1; + color: var(--#{$prefix}navbar-color); + background-color: transparent; // remove default button style + border: var(--#{$prefix}border-width) solid var(--#{$prefix}navbar-toggler-border-color); // remove default button style + @include border-radius(var(--#{$prefix}navbar-toggler-border-radius)); + @include transition(var(--#{$prefix}navbar-toggler-transition)); + + &:hover { + text-decoration: none; + } + + &:focus { + text-decoration: none; + outline: 0; + box-shadow: 0 0 0 var(--#{$prefix}navbar-toggler-focus-width); + } +} + +// Keep as a separate element so folks can easily override it with another icon +// or image file as needed. +.navbar-toggler-icon { + display: inline-block; + width: 1.5em; + height: 1.5em; + vertical-align: middle; + background-image: var(--#{$prefix}navbar-toggler-icon-bg); + background-repeat: no-repeat; + background-position: center; + background-size: 100%; +} + +.navbar-nav-scroll { + max-height: var(--#{$prefix}scroll-height, 75vh); + overflow-y: auto; +} + +// scss-docs-start navbar-expand-loop +// Generate series of `.navbar-expand-*` responsive classes for configuring +// where your navbar collapses. +.navbar-expand { + @each $breakpoint in map-keys($grid-breakpoints) { + $next: breakpoint-next($breakpoint, $grid-breakpoints); + $infix: breakpoint-infix($next, $grid-breakpoints); + + // stylelint-disable-next-line scss/selector-no-union-class-name + &#{$infix} { + @include media-breakpoint-up($next) { + flex-wrap: nowrap; + justify-content: flex-start; + + .navbar-nav { + flex-direction: row; + + .dropdown-menu { + position: absolute; + } + + .nav-link { + padding-right: var(--#{$prefix}navbar-nav-link-padding-x); + padding-left: var(--#{$prefix}navbar-nav-link-padding-x); + } + } + + .navbar-nav-scroll { + overflow: visible; + } + + .navbar-collapse { + display: flex !important; // stylelint-disable-line declaration-no-important + flex-basis: auto; + } + + .navbar-toggler { + display: none; + } + + .offcanvas { + // stylelint-disable declaration-no-important + position: static; + z-index: auto; + flex-grow: 1; + width: auto !important; + height: auto !important; + visibility: visible !important; + background-color: transparent !important; + border: 0 !important; + transform: none !important; + @include box-shadow(none); + @include transition(none); + // stylelint-enable declaration-no-important + + .offcanvas-header { + display: none; + } + + .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + } + } + } + } + } +} +// scss-docs-end navbar-expand-loop + +// Navbar themes +// +// Styles for switching between navbars with light or dark background. + +.navbar-light { + @include deprecate("`.navbar-light`", "v5.2.0", "v6.0.0", true); +} + +.navbar-dark, +.navbar[data-bs-theme="dark"] { + // scss-docs-start navbar-dark-css-vars + --#{$prefix}navbar-color: #{$navbar-dark-color}; + --#{$prefix}navbar-hover-color: #{$navbar-dark-hover-color}; + --#{$prefix}navbar-disabled-color: #{$navbar-dark-disabled-color}; + --#{$prefix}navbar-active-color: #{$navbar-dark-active-color}; + --#{$prefix}navbar-brand-color: #{$navbar-dark-brand-color}; + --#{$prefix}navbar-brand-hover-color: #{$navbar-dark-brand-hover-color}; + --#{$prefix}navbar-toggler-border-color: #{$navbar-dark-toggler-border-color}; + --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)}; + // scss-docs-end navbar-dark-css-vars +} + +@if $enable-dark-mode { + @include color-mode(dark) { + .navbar-toggler-icon { + --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)}; + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_offcanvas.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_offcanvas.scss new file mode 100644 index 0000000..b40b2cd --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_offcanvas.scss @@ -0,0 +1,147 @@ +// stylelint-disable function-disallowed-list + +%offcanvas-css-vars { + // scss-docs-start offcanvas-css-vars + --#{$prefix}offcanvas-zindex: #{$zindex-offcanvas}; + --#{$prefix}offcanvas-width: #{$offcanvas-horizontal-width}; + --#{$prefix}offcanvas-height: #{$offcanvas-vertical-height}; + --#{$prefix}offcanvas-padding-x: #{$offcanvas-padding-x}; + --#{$prefix}offcanvas-padding-y: #{$offcanvas-padding-y}; + --#{$prefix}offcanvas-color: #{$offcanvas-color}; + --#{$prefix}offcanvas-bg: #{$offcanvas-bg-color}; + --#{$prefix}offcanvas-border-width: #{$offcanvas-border-width}; + --#{$prefix}offcanvas-border-color: #{$offcanvas-border-color}; + --#{$prefix}offcanvas-box-shadow: #{$offcanvas-box-shadow}; + --#{$prefix}offcanvas-transition: #{transform $offcanvas-transition-duration ease-in-out}; + --#{$prefix}offcanvas-title-line-height: #{$offcanvas-title-line-height}; + // scss-docs-end offcanvas-css-vars +} + +@each $breakpoint in map-keys($grid-breakpoints) { + $next: breakpoint-next($breakpoint, $grid-breakpoints); + $infix: breakpoint-infix($next, $grid-breakpoints); + + .offcanvas#{$infix} { + @extend %offcanvas-css-vars; + } +} + +@each $breakpoint in map-keys($grid-breakpoints) { + $next: breakpoint-next($breakpoint, $grid-breakpoints); + $infix: breakpoint-infix($next, $grid-breakpoints); + + .offcanvas#{$infix} { + @include media-breakpoint-down($next) { + position: fixed; + bottom: 0; + z-index: var(--#{$prefix}offcanvas-zindex); + display: flex; + flex-direction: column; + max-width: 100%; + color: var(--#{$prefix}offcanvas-color); + visibility: hidden; + background-color: var(--#{$prefix}offcanvas-bg); + background-clip: padding-box; + outline: 0; + @include box-shadow(var(--#{$prefix}offcanvas-box-shadow)); + @include transition(var(--#{$prefix}offcanvas-transition)); + + &.offcanvas-start { + top: 0; + left: 0; + width: var(--#{$prefix}offcanvas-width); + border-right: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color); + transform: translateX(-100%); + } + + &.offcanvas-end { + top: 0; + right: 0; + width: var(--#{$prefix}offcanvas-width); + border-left: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color); + transform: translateX(100%); + } + + &.offcanvas-top { + top: 0; + right: 0; + left: 0; + height: var(--#{$prefix}offcanvas-height); + max-height: 100%; + border-bottom: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color); + transform: translateY(-100%); + } + + &.offcanvas-bottom { + right: 0; + left: 0; + height: var(--#{$prefix}offcanvas-height); + max-height: 100%; + border-top: var(--#{$prefix}offcanvas-border-width) solid var(--#{$prefix}offcanvas-border-color); + transform: translateY(100%); + } + + &.showing, + &.show:not(.hiding) { + transform: none; + } + + &.showing, + &.hiding, + &.show { + visibility: visible; + } + } + + @if not ($infix == "") { + @include media-breakpoint-up($next) { + --#{$prefix}offcanvas-height: auto; + --#{$prefix}offcanvas-border-width: 0; + background-color: transparent !important; // stylelint-disable-line declaration-no-important + + .offcanvas-header { + display: none; + } + + .offcanvas-body { + display: flex; + flex-grow: 0; + padding: 0; + overflow-y: visible; + // Reset `background-color` in case `.bg-*` classes are used in offcanvas + background-color: transparent !important; // stylelint-disable-line declaration-no-important + } + } + } + } +} + +.offcanvas-backdrop { + @include overlay-backdrop($zindex-offcanvas-backdrop, $offcanvas-backdrop-bg, $offcanvas-backdrop-opacity); +} + +.offcanvas-header { + display: flex; + align-items: center; + padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x); + + .btn-close { + padding: calc(var(--#{$prefix}offcanvas-padding-y) * .5) calc(var(--#{$prefix}offcanvas-padding-x) * .5); + // Split properties to avoid invalid calc() function if value is 0 + margin-top: calc(-.5 * var(--#{$prefix}offcanvas-padding-y)); + margin-right: calc(-.5 * var(--#{$prefix}offcanvas-padding-x)); + margin-bottom: calc(-.5 * var(--#{$prefix}offcanvas-padding-y)); + margin-left: auto; + } +} + +.offcanvas-title { + margin-bottom: 0; + line-height: var(--#{$prefix}offcanvas-title-line-height); +} + +.offcanvas-body { + flex-grow: 1; + padding: var(--#{$prefix}offcanvas-padding-y) var(--#{$prefix}offcanvas-padding-x); + overflow-y: auto; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_pagination.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_pagination.scss new file mode 100644 index 0000000..9f09694 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_pagination.scss @@ -0,0 +1,109 @@ +.pagination { + // scss-docs-start pagination-css-vars + --#{$prefix}pagination-padding-x: #{$pagination-padding-x}; + --#{$prefix}pagination-padding-y: #{$pagination-padding-y}; + @include rfs($pagination-font-size, --#{$prefix}pagination-font-size); + --#{$prefix}pagination-color: #{$pagination-color}; + --#{$prefix}pagination-bg: #{$pagination-bg}; + --#{$prefix}pagination-border-width: #{$pagination-border-width}; + --#{$prefix}pagination-border-color: #{$pagination-border-color}; + --#{$prefix}pagination-border-radius: #{$pagination-border-radius}; + --#{$prefix}pagination-hover-color: #{$pagination-hover-color}; + --#{$prefix}pagination-hover-bg: #{$pagination-hover-bg}; + --#{$prefix}pagination-hover-border-color: #{$pagination-hover-border-color}; + --#{$prefix}pagination-focus-color: #{$pagination-focus-color}; + --#{$prefix}pagination-focus-bg: #{$pagination-focus-bg}; + --#{$prefix}pagination-focus-box-shadow: #{$pagination-focus-box-shadow}; + --#{$prefix}pagination-active-color: #{$pagination-active-color}; + --#{$prefix}pagination-active-bg: #{$pagination-active-bg}; + --#{$prefix}pagination-active-border-color: #{$pagination-active-border-color}; + --#{$prefix}pagination-disabled-color: #{$pagination-disabled-color}; + --#{$prefix}pagination-disabled-bg: #{$pagination-disabled-bg}; + --#{$prefix}pagination-disabled-border-color: #{$pagination-disabled-border-color}; + // scss-docs-end pagination-css-vars + + display: flex; + @include list-unstyled(); +} + +.page-link { + position: relative; + display: block; + padding: var(--#{$prefix}pagination-padding-y) var(--#{$prefix}pagination-padding-x); + @include font-size(var(--#{$prefix}pagination-font-size)); + color: var(--#{$prefix}pagination-color); + text-decoration: if($link-decoration == none, null, none); + background-color: var(--#{$prefix}pagination-bg); + border: var(--#{$prefix}pagination-border-width) solid var(--#{$prefix}pagination-border-color); + @include transition($pagination-transition); + + &:hover { + z-index: 2; + color: var(--#{$prefix}pagination-hover-color); + text-decoration: if($link-hover-decoration == underline, none, null); + background-color: var(--#{$prefix}pagination-hover-bg); + border-color: var(--#{$prefix}pagination-hover-border-color); + } + + &:focus { + z-index: 3; + color: var(--#{$prefix}pagination-focus-color); + background-color: var(--#{$prefix}pagination-focus-bg); + outline: $pagination-focus-outline; + box-shadow: var(--#{$prefix}pagination-focus-box-shadow); + } + + &.active, + .active > & { + z-index: 3; + color: var(--#{$prefix}pagination-active-color); + @include gradient-bg(var(--#{$prefix}pagination-active-bg)); + border-color: var(--#{$prefix}pagination-active-border-color); + } + + &.disabled, + .disabled > & { + color: var(--#{$prefix}pagination-disabled-color); + pointer-events: none; + background-color: var(--#{$prefix}pagination-disabled-bg); + border-color: var(--#{$prefix}pagination-disabled-border-color); + } +} + +.page-item { + &:not(:first-child) .page-link { + margin-left: $pagination-margin-start; + } + + @if $pagination-margin-start == calc(-1 * #{$pagination-border-width}) { + &:first-child { + .page-link { + @include border-start-radius(var(--#{$prefix}pagination-border-radius)); + } + } + + &:last-child { + .page-link { + @include border-end-radius(var(--#{$prefix}pagination-border-radius)); + } + } + } @else { + // Add border-radius to all pageLinks in case they have left margin + .page-link { + @include border-radius(var(--#{$prefix}pagination-border-radius)); + } + } +} + + +// +// Sizing +// + +.pagination-lg { + @include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $pagination-border-radius-lg); +} + +.pagination-sm { + @include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $pagination-border-radius-sm); +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_placeholders.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_placeholders.scss new file mode 100644 index 0000000..6e32e1c --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_placeholders.scss @@ -0,0 +1,51 @@ +.placeholder { + display: inline-block; + min-height: 1em; + vertical-align: middle; + cursor: wait; + background-color: currentcolor; + opacity: $placeholder-opacity-max; + + &.btn::before { + display: inline-block; + content: ""; + } +} + +// Sizing +.placeholder-xs { + min-height: .6em; +} + +.placeholder-sm { + min-height: .8em; +} + +.placeholder-lg { + min-height: 1.2em; +} + +// Animation +.placeholder-glow { + .placeholder { + animation: placeholder-glow 2s ease-in-out infinite; + } +} + +@keyframes placeholder-glow { + 50% { + opacity: $placeholder-opacity-min; + } +} + +.placeholder-wave { + mask-image: linear-gradient(130deg, $black 55%, rgba(0, 0, 0, (1 - $placeholder-opacity-min)) 75%, $black 95%); + mask-size: 200% 100%; + animation: placeholder-wave 2s linear infinite; +} + +@keyframes placeholder-wave { + 100% { + mask-position: -200% 0%; + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_popover.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_popover.scss new file mode 100644 index 0000000..7b69f62 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_popover.scss @@ -0,0 +1,196 @@ +.popover { + // scss-docs-start popover-css-vars + --#{$prefix}popover-zindex: #{$zindex-popover}; + --#{$prefix}popover-max-width: #{$popover-max-width}; + @include rfs($popover-font-size, --#{$prefix}popover-font-size); + --#{$prefix}popover-bg: #{$popover-bg}; + --#{$prefix}popover-border-width: #{$popover-border-width}; + --#{$prefix}popover-border-color: #{$popover-border-color}; + --#{$prefix}popover-border-radius: #{$popover-border-radius}; + --#{$prefix}popover-inner-border-radius: #{$popover-inner-border-radius}; + --#{$prefix}popover-box-shadow: #{$popover-box-shadow}; + --#{$prefix}popover-header-padding-x: #{$popover-header-padding-x}; + --#{$prefix}popover-header-padding-y: #{$popover-header-padding-y}; + @include rfs($popover-header-font-size, --#{$prefix}popover-header-font-size); + --#{$prefix}popover-header-color: #{$popover-header-color}; + --#{$prefix}popover-header-bg: #{$popover-header-bg}; + --#{$prefix}popover-body-padding-x: #{$popover-body-padding-x}; + --#{$prefix}popover-body-padding-y: #{$popover-body-padding-y}; + --#{$prefix}popover-body-color: #{$popover-body-color}; + --#{$prefix}popover-arrow-width: #{$popover-arrow-width}; + --#{$prefix}popover-arrow-height: #{$popover-arrow-height}; + --#{$prefix}popover-arrow-border: var(--#{$prefix}popover-border-color); + // scss-docs-end popover-css-vars + + z-index: var(--#{$prefix}popover-zindex); + display: block; + max-width: var(--#{$prefix}popover-max-width); + // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element. + // So reset our font and text properties to avoid inheriting weird values. + @include reset-text(); + @include font-size(var(--#{$prefix}popover-font-size)); + // Allow breaking very long words so they don't overflow the popover's bounds + word-wrap: break-word; + background-color: var(--#{$prefix}popover-bg); + background-clip: padding-box; + border: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color); + @include border-radius(var(--#{$prefix}popover-border-radius)); + @include box-shadow(var(--#{$prefix}popover-box-shadow)); + + .popover-arrow { + display: block; + width: var(--#{$prefix}popover-arrow-width); + height: var(--#{$prefix}popover-arrow-height); + + &::before, + &::after { + position: absolute; + display: block; + content: ""; + border-color: transparent; + border-style: solid; + border-width: 0; + } + } +} + +.bs-popover-top { + > .popover-arrow { + bottom: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list + + &::before, + &::after { + border-width: var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + } + + &::before { + bottom: 0; + border-top-color: var(--#{$prefix}popover-arrow-border); + } + + &::after { + bottom: var(--#{$prefix}popover-border-width); + border-top-color: var(--#{$prefix}popover-bg); + } + } +} + +/* rtl:begin:ignore */ +.bs-popover-end { + > .popover-arrow { + left: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list + width: var(--#{$prefix}popover-arrow-height); + height: var(--#{$prefix}popover-arrow-width); + + &::before, + &::after { + border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height) calc(var(--#{$prefix}popover-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + } + + &::before { + left: 0; + border-right-color: var(--#{$prefix}popover-arrow-border); + } + + &::after { + left: var(--#{$prefix}popover-border-width); + border-right-color: var(--#{$prefix}popover-bg); + } + } +} + +/* rtl:end:ignore */ + +.bs-popover-bottom { + > .popover-arrow { + top: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list + + &::before, + &::after { + border-width: 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list + } + + &::before { + top: 0; + border-bottom-color: var(--#{$prefix}popover-arrow-border); + } + + &::after { + top: var(--#{$prefix}popover-border-width); + border-bottom-color: var(--#{$prefix}popover-bg); + } + } + + // This will remove the popover-header's border just below the arrow + .popover-header::before { + position: absolute; + top: 0; + left: 50%; + display: block; + width: var(--#{$prefix}popover-arrow-width); + margin-left: calc(-.5 * var(--#{$prefix}popover-arrow-width)); // stylelint-disable-line function-disallowed-list + content: ""; + border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg); + } +} + +/* rtl:begin:ignore */ +.bs-popover-start { + > .popover-arrow { + right: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list + width: var(--#{$prefix}popover-arrow-height); + height: var(--#{$prefix}popover-arrow-width); + + &::before, + &::after { + border-width: calc(var(--#{$prefix}popover-arrow-width) * .5) 0 calc(var(--#{$prefix}popover-arrow-width) * .5) var(--#{$prefix}popover-arrow-height); // stylelint-disable-line function-disallowed-list + } + + &::before { + right: 0; + border-left-color: var(--#{$prefix}popover-arrow-border); + } + + &::after { + right: var(--#{$prefix}popover-border-width); + border-left-color: var(--#{$prefix}popover-bg); + } + } +} + +/* rtl:end:ignore */ + +.bs-popover-auto { + &[data-popper-placement^="top"] { + @extend .bs-popover-top; + } + &[data-popper-placement^="right"] { + @extend .bs-popover-end; + } + &[data-popper-placement^="bottom"] { + @extend .bs-popover-bottom; + } + &[data-popper-placement^="left"] { + @extend .bs-popover-start; + } +} + +// Offset the popover to account for the popover arrow +.popover-header { + padding: var(--#{$prefix}popover-header-padding-y) var(--#{$prefix}popover-header-padding-x); + margin-bottom: 0; // Reset the default from Reboot + @include font-size(var(--#{$prefix}popover-header-font-size)); + color: var(--#{$prefix}popover-header-color); + background-color: var(--#{$prefix}popover-header-bg); + border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-border-color); + @include border-top-radius(var(--#{$prefix}popover-inner-border-radius)); + + &:empty { + display: none; + } +} + +.popover-body { + padding: var(--#{$prefix}popover-body-padding-y) var(--#{$prefix}popover-body-padding-x); + color: var(--#{$prefix}popover-body-color); +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_progress.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_progress.scss new file mode 100644 index 0000000..732365c --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_progress.scss @@ -0,0 +1,68 @@ +// Disable animation if transitions are disabled + +// scss-docs-start progress-keyframes +@if $enable-transitions { + @keyframes progress-bar-stripes { + 0% { background-position-x: var(--#{$prefix}progress-height); } + } +} +// scss-docs-end progress-keyframes + +.progress, +.progress-stacked { + // scss-docs-start progress-css-vars + --#{$prefix}progress-height: #{$progress-height}; + @include rfs($progress-font-size, --#{$prefix}progress-font-size); + --#{$prefix}progress-bg: #{$progress-bg}; + --#{$prefix}progress-border-radius: #{$progress-border-radius}; + --#{$prefix}progress-box-shadow: #{$progress-box-shadow}; + --#{$prefix}progress-bar-color: #{$progress-bar-color}; + --#{$prefix}progress-bar-bg: #{$progress-bar-bg}; + --#{$prefix}progress-bar-transition: #{$progress-bar-transition}; + // scss-docs-end progress-css-vars + + display: flex; + height: var(--#{$prefix}progress-height); + overflow: hidden; // force rounded corners by cropping it + @include font-size(var(--#{$prefix}progress-font-size)); + background-color: var(--#{$prefix}progress-bg); + @include border-radius(var(--#{$prefix}progress-border-radius)); + @include box-shadow(var(--#{$prefix}progress-box-shadow)); +} + +.progress-bar { + display: flex; + flex-direction: column; + justify-content: center; + overflow: hidden; + color: var(--#{$prefix}progress-bar-color); + text-align: center; + white-space: nowrap; + background-color: var(--#{$prefix}progress-bar-bg); + @include transition(var(--#{$prefix}progress-bar-transition)); +} + +.progress-bar-striped { + @include gradient-striped(); + background-size: var(--#{$prefix}progress-height) var(--#{$prefix}progress-height); +} + +.progress-stacked > .progress { + overflow: visible; +} + +.progress-stacked > .progress > .progress-bar { + width: 100%; +} + +@if $enable-transitions { + .progress-bar-animated { + animation: $progress-bar-animation-timing progress-bar-stripes; + + @if $enable-reduced-motion { + @media (prefers-reduced-motion: reduce) { + animation: none; + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_reboot.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_reboot.scss new file mode 100644 index 0000000..524645f --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_reboot.scss @@ -0,0 +1,617 @@ +// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix + + +// Reboot +// +// Normalization of HTML elements, manually forked from Normalize.css to remove +// styles targeting irrelevant browsers while applying new styles. +// +// Normalize is licensed MIT. https://github.com/necolas/normalize.css + + +// Document +// +// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`. + +*, +*::before, +*::after { + box-sizing: border-box; +} + + +// Root +// +// Ability to the value of the root font sizes, affecting the value of `rem`. +// null by default, thus nothing is generated. + +:root { + @if $font-size-root != null { + @include font-size(var(--#{$prefix}root-font-size)); + } + + @if $enable-smooth-scroll { + @media (prefers-reduced-motion: no-preference) { + scroll-behavior: smooth; + } + } +} + + +// Body +// +// 1. Remove the margin in all browsers. +// 2. As a best practice, apply a default `background-color`. +// 3. Prevent adjustments of font size after orientation changes in iOS. +// 4. Change the default tap highlight to be completely transparent in iOS. + +// scss-docs-start reboot-body-rules +body { + margin: 0; // 1 + font-family: var(--#{$prefix}body-font-family); + @include font-size(var(--#{$prefix}body-font-size)); + font-weight: var(--#{$prefix}body-font-weight); + line-height: var(--#{$prefix}body-line-height); + color: var(--#{$prefix}body-color); + text-align: var(--#{$prefix}body-text-align); + background-color: var(--#{$prefix}body-bg); // 2 + -webkit-text-size-adjust: 100%; // 3 + -webkit-tap-highlight-color: rgba($black, 0); // 4 +} +// scss-docs-end reboot-body-rules + + +// Content grouping +// +// 1. Reset Firefox's gray color + +hr { + margin: $hr-margin-y 0; + color: $hr-color; // 1 + border: 0; + border-top: $hr-border-width solid $hr-border-color; + opacity: $hr-opacity; +} + + +// Typography +// +// 1. Remove top margins from headings +// By default, `<h1>`-`<h6>` all receive top and bottom margins. We nuke the top +// margin for easier control within type scales as it avoids margin collapsing. + +%heading { + margin-top: 0; // 1 + margin-bottom: $headings-margin-bottom; + font-family: $headings-font-family; + font-style: $headings-font-style; + font-weight: $headings-font-weight; + line-height: $headings-line-height; + color: var(--#{$prefix}heading-color); +} + +h1 { + @extend %heading; + @include font-size($h1-font-size); +} + +h2 { + @extend %heading; + @include font-size($h2-font-size); +} + +h3 { + @extend %heading; + @include font-size($h3-font-size); +} + +h4 { + @extend %heading; + @include font-size($h4-font-size); +} + +h5 { + @extend %heading; + @include font-size($h5-font-size); +} + +h6 { + @extend %heading; + @include font-size($h6-font-size); +} + + +// Reset margins on paragraphs +// +// Similarly, the top margin on `<p>`s get reset. However, we also reset the +// bottom margin to use `rem` units instead of `em`. + +p { + margin-top: 0; + margin-bottom: $paragraph-margin-bottom; +} + + +// Abbreviations +// +// 1. Add the correct text decoration in Chrome, Edge, Opera, and Safari. +// 2. Add explicit cursor to indicate changed behavior. +// 3. Prevent the text-decoration to be skipped. + +abbr[title] { + text-decoration: underline dotted; // 1 + cursor: help; // 2 + text-decoration-skip-ink: none; // 3 +} + + +// Address + +address { + margin-bottom: 1rem; + font-style: normal; + line-height: inherit; +} + + +// Lists + +ol, +ul { + padding-left: 2rem; +} + +ol, +ul, +dl { + margin-top: 0; + margin-bottom: 1rem; +} + +ol ol, +ul ul, +ol ul, +ul ol { + margin-bottom: 0; +} + +dt { + font-weight: $dt-font-weight; +} + +// 1. Undo browser default + +dd { + margin-bottom: .5rem; + margin-left: 0; // 1 +} + + +// Blockquote + +blockquote { + margin: 0 0 1rem; +} + + +// Strong +// +// Add the correct font weight in Chrome, Edge, and Safari + +b, +strong { + font-weight: $font-weight-bolder; +} + + +// Small +// +// Add the correct font size in all browsers + +small { + @include font-size($small-font-size); +} + + +// Mark + +mark { + padding: $mark-padding; + color: var(--#{$prefix}highlight-color); + background-color: var(--#{$prefix}highlight-bg); +} + + +// Sub and Sup +// +// Prevent `sub` and `sup` elements from affecting the line height in +// all browsers. + +sub, +sup { + position: relative; + @include font-size($sub-sup-font-size); + line-height: 0; + vertical-align: baseline; +} + +sub { bottom: -.25em; } +sup { top: -.5em; } + + +// Links + +a { + color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, 1)); + text-decoration: $link-decoration; + + &:hover { + --#{$prefix}link-color-rgb: var(--#{$prefix}link-hover-color-rgb); + text-decoration: $link-hover-decoration; + } +} + +// And undo these styles for placeholder links/named anchors (without href). +// It would be more straightforward to just use a[href] in previous block, but that +// causes specificity issues in many other styles that are too complex to fix. +// See https://github.com/twbs/bootstrap/issues/19402 + +a:not([href]):not([class]) { + &, + &:hover { + color: inherit; + text-decoration: none; + } +} + + +// Code + +pre, +code, +kbd, +samp { + font-family: $font-family-code; + @include font-size(1em); // Correct the odd `em` font sizing in all browsers. +} + +// 1. Remove browser default top margin +// 2. Reset browser default of `1em` to use `rem`s +// 3. Don't allow content to break outside + +pre { + display: block; + margin-top: 0; // 1 + margin-bottom: 1rem; // 2 + overflow: auto; // 3 + @include font-size($code-font-size); + color: $pre-color; + + // Account for some code outputs that place code tags in pre tags + code { + @include font-size(inherit); + color: inherit; + word-break: normal; + } +} + +code { + @include font-size($code-font-size); + color: var(--#{$prefix}code-color); + word-wrap: break-word; + + // Streamline the style when inside anchors to avoid broken underline and more + a > & { + color: inherit; + } +} + +kbd { + padding: $kbd-padding-y $kbd-padding-x; + @include font-size($kbd-font-size); + color: $kbd-color; + background-color: $kbd-bg; + @include border-radius($border-radius-sm); + + kbd { + padding: 0; + @include font-size(1em); + font-weight: $nested-kbd-font-weight; + } +} + + +// Figures +// +// Apply a consistent margin strategy (matches our type styles). + +figure { + margin: 0 0 1rem; +} + + +// Images and content + +img, +svg { + vertical-align: middle; +} + + +// Tables +// +// Prevent double borders + +table { + caption-side: bottom; + border-collapse: collapse; +} + +caption { + padding-top: $table-cell-padding-y; + padding-bottom: $table-cell-padding-y; + color: $table-caption-color; + text-align: left; +} + +// 1. Removes font-weight bold by inheriting +// 2. Matches default `<td>` alignment by inheriting `text-align`. +// 3. Fix alignment for Safari + +th { + font-weight: $table-th-font-weight; // 1 + text-align: inherit; // 2 + text-align: -webkit-match-parent; // 3 +} + +thead, +tbody, +tfoot, +tr, +td, +th { + border-color: inherit; + border-style: solid; + border-width: 0; +} + + +// Forms +// +// 1. Allow labels to use `margin` for spacing. + +label { + display: inline-block; // 1 +} + +// Remove the default `border-radius` that macOS Chrome adds. +// See https://github.com/twbs/bootstrap/issues/24093 + +button { + // stylelint-disable-next-line property-disallowed-list + border-radius: 0; +} + +// Explicitly remove focus outline in Chromium when it shouldn't be +// visible (e.g. as result of mouse click or touch tap). It already +// should be doing this automatically, but seems to currently be +// confused and applies its very visible two-tone outline anyway. + +button:focus:not(:focus-visible) { + outline: 0; +} + +// 1. Remove the margin in Firefox and Safari + +input, +button, +select, +optgroup, +textarea { + margin: 0; // 1 + font-family: inherit; + @include font-size(inherit); + line-height: inherit; +} + +// Remove the inheritance of text transform in Firefox +button, +select { + text-transform: none; +} +// Set the cursor for non-`<button>` buttons +// +// Details at https://github.com/twbs/bootstrap/pull/30562 +[role="button"] { + cursor: pointer; +} + +select { + // Remove the inheritance of word-wrap in Safari. + // See https://github.com/twbs/bootstrap/issues/24990 + word-wrap: normal; + + // Undo the opacity change from Chrome + &:disabled { + opacity: 1; + } +} + +// Remove the dropdown arrow only from text type inputs built with datalists in Chrome. +// See https://stackoverflow.com/a/54997118 + +[list]:not([type="date"]):not([type="datetime-local"]):not([type="month"]):not([type="week"]):not([type="time"])::-webkit-calendar-picker-indicator { + display: none !important; +} + +// 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` +// controls in Android 4. +// 2. Correct the inability to style clickable types in iOS and Safari. +// 3. Opinionated: add "hand" cursor to non-disabled button elements. + +button, +[type="button"], // 1 +[type="reset"], +[type="submit"] { + -webkit-appearance: button; // 2 + + @if $enable-button-pointers { + &:not(:disabled) { + cursor: pointer; // 3 + } + } +} + +// Remove inner border and padding from Firefox, but don't restore the outline like Normalize. + +::-moz-focus-inner { + padding: 0; + border-style: none; +} + +// 1. Textareas should really only resize vertically so they don't break their (horizontal) containers. + +textarea { + resize: vertical; // 1 +} + +// 1. Browsers set a default `min-width: min-content;` on fieldsets, +// unlike e.g. `<div>`s, which have `min-width: 0;` by default. +// So we reset that to ensure fieldsets behave more like a standard block element. +// See https://github.com/twbs/bootstrap/issues/12359 +// and https://html.spec.whatwg.org/multipage/#the-fieldset-and-legend-elements +// 2. Reset the default outline behavior of fieldsets so they don't affect page layout. + +fieldset { + min-width: 0; // 1 + padding: 0; // 2 + margin: 0; // 2 + border: 0; // 2 +} + +// 1. By using `float: left`, the legend will behave like a block element. +// This way the border of a fieldset wraps around the legend if present. +// 2. Fix wrapping bug. +// See https://github.com/twbs/bootstrap/issues/29712 + +legend { + float: left; // 1 + width: 100%; + padding: 0; + margin-bottom: $legend-margin-bottom; + font-weight: $legend-font-weight; + line-height: inherit; + @include font-size($legend-font-size); + + + * { + clear: left; // 2 + } +} + +// Fix height of inputs with a type of datetime-local, date, month, week, or time +// See https://github.com/twbs/bootstrap/issues/18842 + +::-webkit-datetime-edit-fields-wrapper, +::-webkit-datetime-edit-text, +::-webkit-datetime-edit-minute, +::-webkit-datetime-edit-hour-field, +::-webkit-datetime-edit-day-field, +::-webkit-datetime-edit-month-field, +::-webkit-datetime-edit-year-field { + padding: 0; +} + +::-webkit-inner-spin-button { + height: auto; +} + +// 1. This overrides the extra rounded corners on search inputs in iOS so that our +// `.form-control` class can properly style them. Note that this cannot simply +// be added to `.form-control` as it's not specific enough. For details, see +// https://github.com/twbs/bootstrap/issues/11586. +// 2. Correct the outline style in Safari. + +[type="search"] { + -webkit-appearance: textfield; // 1 + outline-offset: -2px; // 2 + + // 3. Better affordance and consistent appearance for search cancel button + &::-webkit-search-cancel-button { + cursor: pointer; + filter: grayscale(1); + } +} + +// 1. A few input types should stay LTR +// See https://rtlstyling.com/posts/rtl-styling#form-inputs +// 2. RTL only output +// See https://rtlcss.com/learn/usage-guide/control-directives/#raw + +/* rtl:raw: +[type="tel"], +[type="url"], +[type="email"], +[type="number"] { + direction: ltr; +} +*/ + +// Remove the inner padding in Chrome and Safari on macOS. + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +// Remove padding around color pickers in webkit browsers + +::-webkit-color-swatch-wrapper { + padding: 0; +} + + +// 1. Inherit font family and line height for file input buttons +// 2. Correct the inability to style clickable types in iOS and Safari. + +::file-selector-button { + font: inherit; // 1 + -webkit-appearance: button; // 2 +} + +// Correct element displays + +output { + display: inline-block; +} + +// Remove border from iframe + +iframe { + border: 0; +} + +// Summary +// +// 1. Add the correct display in all browsers + +summary { + display: list-item; // 1 + cursor: pointer; +} + + +// Progress +// +// Add the correct vertical alignment in Chrome, Firefox, and Opera. + +progress { + vertical-align: baseline; +} + + +// Hidden attribute +// +// Always hide an element with the `hidden` HTML attribute. + +[hidden] { + display: none !important; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_root.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_root.scss new file mode 100644 index 0000000..becddf1 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_root.scss @@ -0,0 +1,187 @@ +:root, +[data-bs-theme="light"] { + // Note: Custom variable values only support SassScript inside `#{}`. + + // Colors + // + // Generate palettes for full colors, grays, and theme colors. + + @each $color, $value in $colors { + --#{$prefix}#{$color}: #{$value}; + } + + @each $color, $value in $grays { + --#{$prefix}gray-#{$color}: #{$value}; + } + + @each $color, $value in $theme-colors { + --#{$prefix}#{$color}: #{$value}; + } + + @each $color, $value in $theme-colors-rgb { + --#{$prefix}#{$color}-rgb: #{$value}; + } + + @each $color, $value in $theme-colors-text { + --#{$prefix}#{$color}-text-emphasis: #{$value}; + } + + @each $color, $value in $theme-colors-bg-subtle { + --#{$prefix}#{$color}-bg-subtle: #{$value}; + } + + @each $color, $value in $theme-colors-border-subtle { + --#{$prefix}#{$color}-border-subtle: #{$value}; + } + + --#{$prefix}white-rgb: #{to-rgb($white)}; + --#{$prefix}black-rgb: #{to-rgb($black)}; + + // Fonts + + // Note: Use `inspect` for lists so that quoted items keep the quotes. + // See https://github.com/sass/sass/issues/2383#issuecomment-336349172 + --#{$prefix}font-sans-serif: #{inspect($font-family-sans-serif)}; + --#{$prefix}font-monospace: #{inspect($font-family-monospace)}; + --#{$prefix}gradient: #{$gradient}; + + // Root and body + // scss-docs-start root-body-variables + @if $font-size-root != null { + --#{$prefix}root-font-size: #{$font-size-root}; + } + --#{$prefix}body-font-family: #{inspect($font-family-base)}; + @include rfs($font-size-base, --#{$prefix}body-font-size); + --#{$prefix}body-font-weight: #{$font-weight-base}; + --#{$prefix}body-line-height: #{$line-height-base}; + @if $body-text-align != null { + --#{$prefix}body-text-align: #{$body-text-align}; + } + + --#{$prefix}body-color: #{$body-color}; + --#{$prefix}body-color-rgb: #{to-rgb($body-color)}; + --#{$prefix}body-bg: #{$body-bg}; + --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)}; + + --#{$prefix}emphasis-color: #{$body-emphasis-color}; + --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color)}; + + --#{$prefix}secondary-color: #{$body-secondary-color}; + --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color)}; + --#{$prefix}secondary-bg: #{$body-secondary-bg}; + --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg)}; + + --#{$prefix}tertiary-color: #{$body-tertiary-color}; + --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color)}; + --#{$prefix}tertiary-bg: #{$body-tertiary-bg}; + --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg)}; + // scss-docs-end root-body-variables + + --#{$prefix}heading-color: #{$headings-color}; + + --#{$prefix}link-color: #{$link-color}; + --#{$prefix}link-color-rgb: #{to-rgb($link-color)}; + --#{$prefix}link-decoration: #{$link-decoration}; + + --#{$prefix}link-hover-color: #{$link-hover-color}; + --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color)}; + + @if $link-hover-decoration != null { + --#{$prefix}link-hover-decoration: #{$link-hover-decoration}; + } + + --#{$prefix}code-color: #{$code-color}; + --#{$prefix}highlight-color: #{$mark-color}; + --#{$prefix}highlight-bg: #{$mark-bg}; + + // scss-docs-start root-border-var + --#{$prefix}border-width: #{$border-width}; + --#{$prefix}border-style: #{$border-style}; + --#{$prefix}border-color: #{$border-color}; + --#{$prefix}border-color-translucent: #{$border-color-translucent}; + + --#{$prefix}border-radius: #{$border-radius}; + --#{$prefix}border-radius-sm: #{$border-radius-sm}; + --#{$prefix}border-radius-lg: #{$border-radius-lg}; + --#{$prefix}border-radius-xl: #{$border-radius-xl}; + --#{$prefix}border-radius-xxl: #{$border-radius-xxl}; + --#{$prefix}border-radius-2xl: var(--#{$prefix}border-radius-xxl); // Deprecated in v5.3.0 for consistency + --#{$prefix}border-radius-pill: #{$border-radius-pill}; + // scss-docs-end root-border-var + + --#{$prefix}box-shadow: #{$box-shadow}; + --#{$prefix}box-shadow-sm: #{$box-shadow-sm}; + --#{$prefix}box-shadow-lg: #{$box-shadow-lg}; + --#{$prefix}box-shadow-inset: #{$box-shadow-inset}; + + // Focus styles + // scss-docs-start root-focus-variables + --#{$prefix}focus-ring-width: #{$focus-ring-width}; + --#{$prefix}focus-ring-opacity: #{$focus-ring-opacity}; + --#{$prefix}focus-ring-color: #{$focus-ring-color}; + // scss-docs-end root-focus-variables + + // scss-docs-start root-form-validation-variables + --#{$prefix}form-valid-color: #{$form-valid-color}; + --#{$prefix}form-valid-border-color: #{$form-valid-border-color}; + --#{$prefix}form-invalid-color: #{$form-invalid-color}; + --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color}; + // scss-docs-end root-form-validation-variables +} + +@if $enable-dark-mode { + @include color-mode(dark, true) { + color-scheme: dark; + + // scss-docs-start root-dark-mode-vars + --#{$prefix}body-color: #{$body-color-dark}; + --#{$prefix}body-color-rgb: #{to-rgb($body-color-dark)}; + --#{$prefix}body-bg: #{$body-bg-dark}; + --#{$prefix}body-bg-rgb: #{to-rgb($body-bg-dark)}; + + --#{$prefix}emphasis-color: #{$body-emphasis-color-dark}; + --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color-dark)}; + + --#{$prefix}secondary-color: #{$body-secondary-color-dark}; + --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color-dark)}; + --#{$prefix}secondary-bg: #{$body-secondary-bg-dark}; + --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg-dark)}; + + --#{$prefix}tertiary-color: #{$body-tertiary-color-dark}; + --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color-dark)}; + --#{$prefix}tertiary-bg: #{$body-tertiary-bg-dark}; + --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg-dark)}; + + @each $color, $value in $theme-colors-text-dark { + --#{$prefix}#{$color}-text-emphasis: #{$value}; + } + + @each $color, $value in $theme-colors-bg-subtle-dark { + --#{$prefix}#{$color}-bg-subtle: #{$value}; + } + + @each $color, $value in $theme-colors-border-subtle-dark { + --#{$prefix}#{$color}-border-subtle: #{$value}; + } + + --#{$prefix}heading-color: #{$headings-color-dark}; + + --#{$prefix}link-color: #{$link-color-dark}; + --#{$prefix}link-hover-color: #{$link-hover-color-dark}; + --#{$prefix}link-color-rgb: #{to-rgb($link-color-dark)}; + --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color-dark)}; + + --#{$prefix}code-color: #{$code-color-dark}; + --#{$prefix}highlight-color: #{$mark-color-dark}; + --#{$prefix}highlight-bg: #{$mark-bg-dark}; + + --#{$prefix}border-color: #{$border-color-dark}; + --#{$prefix}border-color-translucent: #{$border-color-translucent-dark}; + + --#{$prefix}form-valid-color: #{$form-valid-color-dark}; + --#{$prefix}form-valid-border-color: #{$form-valid-border-color-dark}; + --#{$prefix}form-invalid-color: #{$form-invalid-color-dark}; + --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color-dark}; + // scss-docs-end root-dark-mode-vars + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_spinners.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_spinners.scss new file mode 100644 index 0000000..9dff289 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_spinners.scss @@ -0,0 +1,86 @@ +// +// Rotating border +// + +.spinner-grow, +.spinner-border { + display: inline-block; + flex-shrink: 0; + width: var(--#{$prefix}spinner-width); + height: var(--#{$prefix}spinner-height); + vertical-align: var(--#{$prefix}spinner-vertical-align); + // stylelint-disable-next-line property-disallowed-list + border-radius: 50%; + animation: var(--#{$prefix}spinner-animation-speed) linear infinite var(--#{$prefix}spinner-animation-name); +} + +// scss-docs-start spinner-border-keyframes +@keyframes spinner-border { + to { transform: rotate(360deg) #{"/* rtl:ignore */"}; } +} +// scss-docs-end spinner-border-keyframes + +.spinner-border { + // scss-docs-start spinner-border-css-vars + --#{$prefix}spinner-width: #{$spinner-width}; + --#{$prefix}spinner-height: #{$spinner-height}; + --#{$prefix}spinner-vertical-align: #{$spinner-vertical-align}; + --#{$prefix}spinner-border-width: #{$spinner-border-width}; + --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed}; + --#{$prefix}spinner-animation-name: spinner-border; + // scss-docs-end spinner-border-css-vars + + border: var(--#{$prefix}spinner-border-width) solid currentcolor; + border-right-color: transparent; +} + +.spinner-border-sm { + // scss-docs-start spinner-border-sm-css-vars + --#{$prefix}spinner-width: #{$spinner-width-sm}; + --#{$prefix}spinner-height: #{$spinner-height-sm}; + --#{$prefix}spinner-border-width: #{$spinner-border-width-sm}; + // scss-docs-end spinner-border-sm-css-vars +} + +// +// Growing circle +// + +// scss-docs-start spinner-grow-keyframes +@keyframes spinner-grow { + 0% { + transform: scale(0); + } + 50% { + opacity: 1; + transform: none; + } +} +// scss-docs-end spinner-grow-keyframes + +.spinner-grow { + // scss-docs-start spinner-grow-css-vars + --#{$prefix}spinner-width: #{$spinner-width}; + --#{$prefix}spinner-height: #{$spinner-height}; + --#{$prefix}spinner-vertical-align: #{$spinner-vertical-align}; + --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed}; + --#{$prefix}spinner-animation-name: spinner-grow; + // scss-docs-end spinner-grow-css-vars + + background-color: currentcolor; + opacity: 0; +} + +.spinner-grow-sm { + --#{$prefix}spinner-width: #{$spinner-width-sm}; + --#{$prefix}spinner-height: #{$spinner-height-sm}; +} + +@if $enable-reduced-motion { + @media (prefers-reduced-motion: reduce) { + .spinner-border, + .spinner-grow { + --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed * 2}; + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_tables.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_tables.scss new file mode 100644 index 0000000..276521a --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_tables.scss @@ -0,0 +1,171 @@ +// +// Basic Bootstrap table +// + +.table { + // Reset needed for nesting tables + --#{$prefix}table-color-type: initial; + --#{$prefix}table-bg-type: initial; + --#{$prefix}table-color-state: initial; + --#{$prefix}table-bg-state: initial; + // End of reset + --#{$prefix}table-color: #{$table-color}; + --#{$prefix}table-bg: #{$table-bg}; + --#{$prefix}table-border-color: #{$table-border-color}; + --#{$prefix}table-accent-bg: #{$table-accent-bg}; + --#{$prefix}table-striped-color: #{$table-striped-color}; + --#{$prefix}table-striped-bg: #{$table-striped-bg}; + --#{$prefix}table-active-color: #{$table-active-color}; + --#{$prefix}table-active-bg: #{$table-active-bg}; + --#{$prefix}table-hover-color: #{$table-hover-color}; + --#{$prefix}table-hover-bg: #{$table-hover-bg}; + + width: 100%; + margin-bottom: $spacer; + vertical-align: $table-cell-vertical-align; + border-color: var(--#{$prefix}table-border-color); + + // Target th & td + // We need the child combinator to prevent styles leaking to nested tables which doesn't have a `.table` class. + // We use the universal selectors here to simplify the selector (else we would need 6 different selectors). + // Another advantage is that this generates less code and makes the selector less specific making it easier to override. + // stylelint-disable-next-line selector-max-universal + > :not(caption) > * > * { + padding: $table-cell-padding-y $table-cell-padding-x; + // Following the precept of cascades: https://codepen.io/miriamsuzanne/full/vYNgodb + color: var(--#{$prefix}table-color-state, var(--#{$prefix}table-color-type, var(--#{$prefix}table-color))); + background-color: var(--#{$prefix}table-bg); + border-bottom-width: $table-border-width; + box-shadow: inset 0 0 0 9999px var(--#{$prefix}table-bg-state, var(--#{$prefix}table-bg-type, var(--#{$prefix}table-accent-bg))); + } + + > tbody { + vertical-align: inherit; + } + + > thead { + vertical-align: bottom; + } +} + +.table-group-divider { + border-top: calc(#{$table-border-width} * 2) solid $table-group-separator-color; // stylelint-disable-line function-disallowed-list +} + +// +// Change placement of captions with a class +// + +.caption-top { + caption-side: top; +} + + +// +// Condensed table w/ half padding +// + +.table-sm { + // stylelint-disable-next-line selector-max-universal + > :not(caption) > * > * { + padding: $table-cell-padding-y-sm $table-cell-padding-x-sm; + } +} + + +// Border versions +// +// Add or remove borders all around the table and between all the columns. +// +// When borders are added on all sides of the cells, the corners can render odd when +// these borders do not have the same color or if they are semi-transparent. +// Therefore we add top and border bottoms to the `tr`s and left and right borders +// to the `td`s or `th`s + +.table-bordered { + > :not(caption) > * { + border-width: $table-border-width 0; + + // stylelint-disable-next-line selector-max-universal + > * { + border-width: 0 $table-border-width; + } + } +} + +.table-borderless { + // stylelint-disable-next-line selector-max-universal + > :not(caption) > * > * { + border-bottom-width: 0; + } + + > :not(:first-child) { + border-top-width: 0; + } +} + +// Zebra-striping +// +// Default zebra-stripe styles (alternating gray and transparent backgrounds) + +// For rows +.table-striped { + > tbody > tr:nth-of-type(#{$table-striped-order}) > * { + --#{$prefix}table-color-type: var(--#{$prefix}table-striped-color); + --#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg); + } +} + +// For columns +.table-striped-columns { + > :not(caption) > tr > :nth-child(#{$table-striped-columns-order}) { + --#{$prefix}table-color-type: var(--#{$prefix}table-striped-color); + --#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg); + } +} + +// Active table +// +// The `.table-active` class can be added to highlight rows or cells + +.table-active { + --#{$prefix}table-color-state: var(--#{$prefix}table-active-color); + --#{$prefix}table-bg-state: var(--#{$prefix}table-active-bg); +} + +// Hover effect +// +// Placed here since it has to come after the potential zebra striping + +.table-hover { + > tbody > tr:hover > * { + --#{$prefix}table-color-state: var(--#{$prefix}table-hover-color); + --#{$prefix}table-bg-state: var(--#{$prefix}table-hover-bg); + } +} + + +// Table variants +// +// Table variants set the table cell backgrounds, border colors +// and the colors of the striped, hovered & active tables + +@each $color, $value in $table-variants { + @include table-variant($color, $value); +} + +// Responsive tables +// +// Generate series of `.table-responsive-*` classes for configuring the screen +// size of where your table will overflow. + +@each $breakpoint in map-keys($grid-breakpoints) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + @include media-breakpoint-down($breakpoint) { + .table-responsive#{$infix} { + overflow-x: auto; + -webkit-overflow-scrolling: touch; + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_toasts.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_toasts.scss new file mode 100644 index 0000000..2ce378d --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_toasts.scss @@ -0,0 +1,73 @@ +.toast { + // scss-docs-start toast-css-vars + --#{$prefix}toast-zindex: #{$zindex-toast}; + --#{$prefix}toast-padding-x: #{$toast-padding-x}; + --#{$prefix}toast-padding-y: #{$toast-padding-y}; + --#{$prefix}toast-spacing: #{$toast-spacing}; + --#{$prefix}toast-max-width: #{$toast-max-width}; + @include rfs($toast-font-size, --#{$prefix}toast-font-size); + --#{$prefix}toast-color: #{$toast-color}; + --#{$prefix}toast-bg: #{$toast-background-color}; + --#{$prefix}toast-border-width: #{$toast-border-width}; + --#{$prefix}toast-border-color: #{$toast-border-color}; + --#{$prefix}toast-border-radius: #{$toast-border-radius}; + --#{$prefix}toast-box-shadow: #{$toast-box-shadow}; + --#{$prefix}toast-header-color: #{$toast-header-color}; + --#{$prefix}toast-header-bg: #{$toast-header-background-color}; + --#{$prefix}toast-header-border-color: #{$toast-header-border-color}; + // scss-docs-end toast-css-vars + + width: var(--#{$prefix}toast-max-width); + max-width: 100%; + @include font-size(var(--#{$prefix}toast-font-size)); + color: var(--#{$prefix}toast-color); + pointer-events: auto; + background-color: var(--#{$prefix}toast-bg); + background-clip: padding-box; + border: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-border-color); + box-shadow: var(--#{$prefix}toast-box-shadow); + @include border-radius(var(--#{$prefix}toast-border-radius)); + + &.showing { + opacity: 0; + } + + &:not(.show) { + display: none; + } +} + +.toast-container { + --#{$prefix}toast-zindex: #{$zindex-toast}; + + position: absolute; + z-index: var(--#{$prefix}toast-zindex); + width: max-content; + max-width: 100%; + pointer-events: none; + + > :not(:last-child) { + margin-bottom: var(--#{$prefix}toast-spacing); + } +} + +.toast-header { + display: flex; + align-items: center; + padding: var(--#{$prefix}toast-padding-y) var(--#{$prefix}toast-padding-x); + color: var(--#{$prefix}toast-header-color); + background-color: var(--#{$prefix}toast-header-bg); + background-clip: padding-box; + border-bottom: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-header-border-color); + @include border-top-radius(calc(var(--#{$prefix}toast-border-radius) - var(--#{$prefix}toast-border-width))); + + .btn-close { + margin-right: calc(-.5 * var(--#{$prefix}toast-padding-x)); // stylelint-disable-line function-disallowed-list + margin-left: var(--#{$prefix}toast-padding-x); + } +} + +.toast-body { + padding: var(--#{$prefix}toast-padding-x); + word-wrap: break-word; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_tooltip.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_tooltip.scss new file mode 100644 index 0000000..85de90f --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_tooltip.scss @@ -0,0 +1,119 @@ +// Base class +.tooltip { + // scss-docs-start tooltip-css-vars + --#{$prefix}tooltip-zindex: #{$zindex-tooltip}; + --#{$prefix}tooltip-max-width: #{$tooltip-max-width}; + --#{$prefix}tooltip-padding-x: #{$tooltip-padding-x}; + --#{$prefix}tooltip-padding-y: #{$tooltip-padding-y}; + --#{$prefix}tooltip-margin: #{$tooltip-margin}; + @include rfs($tooltip-font-size, --#{$prefix}tooltip-font-size); + --#{$prefix}tooltip-color: #{$tooltip-color}; + --#{$prefix}tooltip-bg: #{$tooltip-bg}; + --#{$prefix}tooltip-border-radius: #{$tooltip-border-radius}; + --#{$prefix}tooltip-opacity: #{$tooltip-opacity}; + --#{$prefix}tooltip-arrow-width: #{$tooltip-arrow-width}; + --#{$prefix}tooltip-arrow-height: #{$tooltip-arrow-height}; + // scss-docs-end tooltip-css-vars + + z-index: var(--#{$prefix}tooltip-zindex); + display: block; + margin: var(--#{$prefix}tooltip-margin); + @include deprecate("`$tooltip-margin`", "v5", "v5.x", true); + // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element. + // So reset our font and text properties to avoid inheriting weird values. + @include reset-text(); + @include font-size(var(--#{$prefix}tooltip-font-size)); + // Allow breaking very long words so they don't overflow the tooltip's bounds + word-wrap: break-word; + opacity: 0; + + &.show { opacity: var(--#{$prefix}tooltip-opacity); } + + .tooltip-arrow { + display: block; + width: var(--#{$prefix}tooltip-arrow-width); + height: var(--#{$prefix}tooltip-arrow-height); + + &::before { + position: absolute; + content: ""; + border-color: transparent; + border-style: solid; + } + } +} + +.bs-tooltip-top .tooltip-arrow { + bottom: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list + + &::before { + top: -1px; + border-width: var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + border-top-color: var(--#{$prefix}tooltip-bg); + } +} + +/* rtl:begin:ignore */ +.bs-tooltip-end .tooltip-arrow { + left: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list + width: var(--#{$prefix}tooltip-arrow-height); + height: var(--#{$prefix}tooltip-arrow-width); + + &::before { + right: -1px; + border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list + border-right-color: var(--#{$prefix}tooltip-bg); + } +} + +/* rtl:end:ignore */ + +.bs-tooltip-bottom .tooltip-arrow { + top: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list + + &::before { + bottom: -1px; + border-width: 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list + border-bottom-color: var(--#{$prefix}tooltip-bg); + } +} + +/* rtl:begin:ignore */ +.bs-tooltip-start .tooltip-arrow { + right: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list + width: var(--#{$prefix}tooltip-arrow-height); + height: var(--#{$prefix}tooltip-arrow-width); + + &::before { + left: -1px; + border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list + border-left-color: var(--#{$prefix}tooltip-bg); + } +} + +/* rtl:end:ignore */ + +.bs-tooltip-auto { + &[data-popper-placement^="top"] { + @extend .bs-tooltip-top; + } + &[data-popper-placement^="right"] { + @extend .bs-tooltip-end; + } + &[data-popper-placement^="bottom"] { + @extend .bs-tooltip-bottom; + } + &[data-popper-placement^="left"] { + @extend .bs-tooltip-start; + } +} + +// Wrapper for the tooltip content +.tooltip-inner { + max-width: var(--#{$prefix}tooltip-max-width); + padding: var(--#{$prefix}tooltip-padding-y) var(--#{$prefix}tooltip-padding-x); + color: var(--#{$prefix}tooltip-color); + text-align: center; + background-color: var(--#{$prefix}tooltip-bg); + @include border-radius(var(--#{$prefix}tooltip-border-radius)); +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_transitions.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_transitions.scss new file mode 100644 index 0000000..bfb26aa --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_transitions.scss @@ -0,0 +1,27 @@ +.fade { + @include transition($transition-fade); + + &:not(.show) { + opacity: 0; + } +} + +// scss-docs-start collapse-classes +.collapse { + &:not(.show) { + display: none; + } +} + +.collapsing { + height: 0; + overflow: hidden; + @include transition($transition-collapse); + + &.collapse-horizontal { + width: 0; + height: auto; + @include transition($transition-collapse-width); + } +} +// scss-docs-end collapse-classes diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_type.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_type.scss new file mode 100644 index 0000000..6961390 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_type.scss @@ -0,0 +1,106 @@ +// +// Headings +// +.h1 { + @extend h1; +} + +.h2 { + @extend h2; +} + +.h3 { + @extend h3; +} + +.h4 { + @extend h4; +} + +.h5 { + @extend h5; +} + +.h6 { + @extend h6; +} + + +.lead { + @include font-size($lead-font-size); + font-weight: $lead-font-weight; +} + +// Type display classes +@each $display, $font-size in $display-font-sizes { + .display-#{$display} { + font-family: $display-font-family; + font-style: $display-font-style; + font-weight: $display-font-weight; + line-height: $display-line-height; + @include font-size($font-size); + } +} + +// +// Emphasis +// +.small { + @extend small; +} + +.mark { + @extend mark; +} + +// +// Lists +// + +.list-unstyled { + @include list-unstyled(); +} + +// Inline turns list items into inline-block +.list-inline { + @include list-unstyled(); +} +.list-inline-item { + display: inline-block; + + &:not(:last-child) { + margin-right: $list-inline-padding; + } +} + + +// +// Misc +// + +// Builds on `abbr` +.initialism { + @include font-size($initialism-font-size); + text-transform: uppercase; +} + +// Blockquotes +.blockquote { + margin-bottom: $blockquote-margin-y; + @include font-size($blockquote-font-size); + + > :last-child { + margin-bottom: 0; + } +} + +.blockquote-footer { + margin-top: -$blockquote-margin-y; + margin-bottom: $blockquote-margin-y; + @include font-size($blockquote-footer-font-size); + color: $blockquote-footer-color; + + &::before { + content: "\2014\00A0"; // em dash, nbsp + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_utilities.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_utilities.scss new file mode 100644 index 0000000..696f906 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_utilities.scss @@ -0,0 +1,806 @@ +// Utilities + +$utilities: () !default; +// stylelint-disable-next-line scss/dollar-variable-default +$utilities: map-merge( + ( + // scss-docs-start utils-vertical-align + "align": ( + property: vertical-align, + class: align, + values: baseline top middle bottom text-bottom text-top + ), + // scss-docs-end utils-vertical-align + // scss-docs-start utils-float + "float": ( + responsive: true, + property: float, + values: ( + start: left, + end: right, + none: none, + ) + ), + // scss-docs-end utils-float + // Object Fit utilities + // scss-docs-start utils-object-fit + "object-fit": ( + responsive: true, + property: object-fit, + values: ( + contain: contain, + cover: cover, + fill: fill, + scale: scale-down, + none: none, + ) + ), + // scss-docs-end utils-object-fit + // Opacity utilities + // scss-docs-start utils-opacity + "opacity": ( + property: opacity, + values: ( + 0: 0, + 25: .25, + 50: .5, + 75: .75, + 100: 1, + ) + ), + // scss-docs-end utils-opacity + // scss-docs-start utils-overflow + "overflow": ( + property: overflow, + values: auto hidden visible scroll, + ), + "overflow-x": ( + property: overflow-x, + values: auto hidden visible scroll, + ), + "overflow-y": ( + property: overflow-y, + values: auto hidden visible scroll, + ), + // scss-docs-end utils-overflow + // scss-docs-start utils-display + "display": ( + responsive: true, + print: true, + property: display, + class: d, + values: inline inline-block block grid inline-grid table table-row table-cell flex inline-flex none + ), + // scss-docs-end utils-display + // scss-docs-start utils-shadow + "shadow": ( + property: box-shadow, + class: shadow, + values: ( + null: var(--#{$prefix}box-shadow), + sm: var(--#{$prefix}box-shadow-sm), + lg: var(--#{$prefix}box-shadow-lg), + none: none, + ) + ), + // scss-docs-end utils-shadow + // scss-docs-start utils-focus-ring + "focus-ring": ( + css-var: true, + css-variable-name: focus-ring-color, + class: focus-ring, + values: map-loop($theme-colors-rgb, rgba-css-var, "$key", "focus-ring") + ), + // scss-docs-end utils-focus-ring + // scss-docs-start utils-position + "position": ( + property: position, + values: static relative absolute fixed sticky + ), + "top": ( + property: top, + values: $position-values + ), + "bottom": ( + property: bottom, + values: $position-values + ), + "start": ( + property: left, + class: start, + values: $position-values + ), + "end": ( + property: right, + class: end, + values: $position-values + ), + "translate-middle": ( + property: transform, + class: translate-middle, + values: ( + null: translate(-50%, -50%), + x: translateX(-50%), + y: translateY(-50%), + ) + ), + // scss-docs-end utils-position + // scss-docs-start utils-borders + "border": ( + property: border, + values: ( + null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color), + 0: 0, + ) + ), + "border-top": ( + property: border-top, + values: ( + null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color), + 0: 0, + ) + ), + "border-end": ( + property: border-right, + class: border-end, + values: ( + null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color), + 0: 0, + ) + ), + "border-bottom": ( + property: border-bottom, + values: ( + null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color), + 0: 0, + ) + ), + "border-start": ( + property: border-left, + class: border-start, + values: ( + null: var(--#{$prefix}border-width) var(--#{$prefix}border-style) var(--#{$prefix}border-color), + 0: 0, + ) + ), + "border-color": ( + property: border-color, + class: border, + local-vars: ( + "border-opacity": 1 + ), + values: $utilities-border-colors + ), + "subtle-border-color": ( + property: border-color, + class: border, + values: $utilities-border-subtle + ), + "border-width": ( + property: border-width, + class: border, + values: $border-widths + ), + "border-opacity": ( + css-var: true, + class: border-opacity, + values: ( + 10: .1, + 25: .25, + 50: .5, + 75: .75, + 100: 1 + ) + ), + // scss-docs-end utils-borders + // Sizing utilities + // scss-docs-start utils-sizing + "width": ( + property: width, + class: w, + values: ( + 25: 25%, + 50: 50%, + 75: 75%, + 100: 100%, + auto: auto + ) + ), + "max-width": ( + property: max-width, + class: mw, + values: (100: 100%) + ), + "viewport-width": ( + property: width, + class: vw, + values: (100: 100vw) + ), + "min-viewport-width": ( + property: min-width, + class: min-vw, + values: (100: 100vw) + ), + "height": ( + property: height, + class: h, + values: ( + 25: 25%, + 50: 50%, + 75: 75%, + 100: 100%, + auto: auto + ) + ), + "max-height": ( + property: max-height, + class: mh, + values: (100: 100%) + ), + "viewport-height": ( + property: height, + class: vh, + values: (100: 100vh) + ), + "min-viewport-height": ( + property: min-height, + class: min-vh, + values: (100: 100vh) + ), + // scss-docs-end utils-sizing + // Flex utilities + // scss-docs-start utils-flex + "flex": ( + responsive: true, + property: flex, + values: (fill: 1 1 auto) + ), + "flex-direction": ( + responsive: true, + property: flex-direction, + class: flex, + values: row column row-reverse column-reverse + ), + "flex-grow": ( + responsive: true, + property: flex-grow, + class: flex, + values: ( + grow-0: 0, + grow-1: 1, + ) + ), + "flex-shrink": ( + responsive: true, + property: flex-shrink, + class: flex, + values: ( + shrink-0: 0, + shrink-1: 1, + ) + ), + "flex-wrap": ( + responsive: true, + property: flex-wrap, + class: flex, + values: wrap nowrap wrap-reverse + ), + "justify-content": ( + responsive: true, + property: justify-content, + values: ( + start: flex-start, + end: flex-end, + center: center, + between: space-between, + around: space-around, + evenly: space-evenly, + ) + ), + "align-items": ( + responsive: true, + property: align-items, + values: ( + start: flex-start, + end: flex-end, + center: center, + baseline: baseline, + stretch: stretch, + ) + ), + "align-content": ( + responsive: true, + property: align-content, + values: ( + start: flex-start, + end: flex-end, + center: center, + between: space-between, + around: space-around, + stretch: stretch, + ) + ), + "align-self": ( + responsive: true, + property: align-self, + values: ( + auto: auto, + start: flex-start, + end: flex-end, + center: center, + baseline: baseline, + stretch: stretch, + ) + ), + "order": ( + responsive: true, + property: order, + values: ( + first: -1, + 0: 0, + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + last: 6, + ), + ), + // scss-docs-end utils-flex + // Margin utilities + // scss-docs-start utils-spacing + "margin": ( + responsive: true, + property: margin, + class: m, + values: map-merge($spacers, (auto: auto)) + ), + "margin-x": ( + responsive: true, + property: margin-right margin-left, + class: mx, + values: map-merge($spacers, (auto: auto)) + ), + "margin-y": ( + responsive: true, + property: margin-top margin-bottom, + class: my, + values: map-merge($spacers, (auto: auto)) + ), + "margin-top": ( + responsive: true, + property: margin-top, + class: mt, + values: map-merge($spacers, (auto: auto)) + ), + "margin-end": ( + responsive: true, + property: margin-right, + class: me, + values: map-merge($spacers, (auto: auto)) + ), + "margin-bottom": ( + responsive: true, + property: margin-bottom, + class: mb, + values: map-merge($spacers, (auto: auto)) + ), + "margin-start": ( + responsive: true, + property: margin-left, + class: ms, + values: map-merge($spacers, (auto: auto)) + ), + // Negative margin utilities + "negative-margin": ( + responsive: true, + property: margin, + class: m, + values: $negative-spacers + ), + "negative-margin-x": ( + responsive: true, + property: margin-right margin-left, + class: mx, + values: $negative-spacers + ), + "negative-margin-y": ( + responsive: true, + property: margin-top margin-bottom, + class: my, + values: $negative-spacers + ), + "negative-margin-top": ( + responsive: true, + property: margin-top, + class: mt, + values: $negative-spacers + ), + "negative-margin-end": ( + responsive: true, + property: margin-right, + class: me, + values: $negative-spacers + ), + "negative-margin-bottom": ( + responsive: true, + property: margin-bottom, + class: mb, + values: $negative-spacers + ), + "negative-margin-start": ( + responsive: true, + property: margin-left, + class: ms, + values: $negative-spacers + ), + // Padding utilities + "padding": ( + responsive: true, + property: padding, + class: p, + values: $spacers + ), + "padding-x": ( + responsive: true, + property: padding-right padding-left, + class: px, + values: $spacers + ), + "padding-y": ( + responsive: true, + property: padding-top padding-bottom, + class: py, + values: $spacers + ), + "padding-top": ( + responsive: true, + property: padding-top, + class: pt, + values: $spacers + ), + "padding-end": ( + responsive: true, + property: padding-right, + class: pe, + values: $spacers + ), + "padding-bottom": ( + responsive: true, + property: padding-bottom, + class: pb, + values: $spacers + ), + "padding-start": ( + responsive: true, + property: padding-left, + class: ps, + values: $spacers + ), + // Gap utility + "gap": ( + responsive: true, + property: gap, + class: gap, + values: $spacers + ), + "row-gap": ( + responsive: true, + property: row-gap, + class: row-gap, + values: $spacers + ), + "column-gap": ( + responsive: true, + property: column-gap, + class: column-gap, + values: $spacers + ), + // scss-docs-end utils-spacing + // Text + // scss-docs-start utils-text + "font-family": ( + property: font-family, + class: font, + values: (monospace: var(--#{$prefix}font-monospace)) + ), + "font-size": ( + rfs: true, + property: font-size, + class: fs, + values: $font-sizes + ), + "font-style": ( + property: font-style, + class: fst, + values: italic normal + ), + "font-weight": ( + property: font-weight, + class: fw, + values: ( + lighter: $font-weight-lighter, + light: $font-weight-light, + normal: $font-weight-normal, + medium: $font-weight-medium, + semibold: $font-weight-semibold, + bold: $font-weight-bold, + bolder: $font-weight-bolder + ) + ), + "line-height": ( + property: line-height, + class: lh, + values: ( + 1: 1, + sm: $line-height-sm, + base: $line-height-base, + lg: $line-height-lg, + ) + ), + "text-align": ( + responsive: true, + property: text-align, + class: text, + values: ( + start: left, + end: right, + center: center, + ) + ), + "text-decoration": ( + property: text-decoration, + values: none underline line-through + ), + "text-transform": ( + property: text-transform, + class: text, + values: lowercase uppercase capitalize + ), + "white-space": ( + property: white-space, + class: text, + values: ( + wrap: normal, + nowrap: nowrap, + ) + ), + "word-wrap": ( + property: word-wrap word-break, + class: text, + values: (break: break-word), + rtl: false + ), + // scss-docs-end utils-text + // scss-docs-start utils-color + "color": ( + property: color, + class: text, + local-vars: ( + "text-opacity": 1 + ), + values: map-merge( + $utilities-text-colors, + ( + "muted": var(--#{$prefix}secondary-color), // deprecated + "black-50": rgba($black, .5), // deprecated + "white-50": rgba($white, .5), // deprecated + "body-secondary": var(--#{$prefix}secondary-color), + "body-tertiary": var(--#{$prefix}tertiary-color), + "body-emphasis": var(--#{$prefix}emphasis-color), + "reset": inherit, + ) + ) + ), + "text-opacity": ( + css-var: true, + class: text-opacity, + values: ( + 25: .25, + 50: .5, + 75: .75, + 100: 1 + ) + ), + "text-color": ( + property: color, + class: text, + values: $utilities-text-emphasis-colors + ), + // scss-docs-end utils-color + // scss-docs-start utils-links + "link-opacity": ( + css-var: true, + class: link-opacity, + state: hover, + values: ( + 10: .1, + 25: .25, + 50: .5, + 75: .75, + 100: 1 + ) + ), + "link-offset": ( + property: text-underline-offset, + class: link-offset, + state: hover, + values: ( + 1: .125em, + 2: .25em, + 3: .375em, + ) + ), + "link-underline": ( + property: text-decoration-color, + class: link-underline, + local-vars: ( + "link-underline-opacity": 1 + ), + values: map-merge( + $utilities-links-underline, + ( + null: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-underline-opacity, 1)), + ) + ) + ), + "link-underline-opacity": ( + css-var: true, + class: link-underline-opacity, + state: hover, + values: ( + 0: 0, + 10: .1, + 25: .25, + 50: .5, + 75: .75, + 100: 1 + ), + ), + // scss-docs-end utils-links + // scss-docs-start utils-bg-color + "background-color": ( + property: background-color, + class: bg, + local-vars: ( + "bg-opacity": 1 + ), + values: map-merge( + $utilities-bg-colors, + ( + "transparent": transparent, + "body-secondary": rgba(var(--#{$prefix}secondary-bg-rgb), var(--#{$prefix}bg-opacity)), + "body-tertiary": rgba(var(--#{$prefix}tertiary-bg-rgb), var(--#{$prefix}bg-opacity)), + ) + ) + ), + "bg-opacity": ( + css-var: true, + class: bg-opacity, + values: ( + 10: .1, + 25: .25, + 50: .5, + 75: .75, + 100: 1 + ) + ), + "subtle-background-color": ( + property: background-color, + class: bg, + values: $utilities-bg-subtle + ), + // scss-docs-end utils-bg-color + "gradient": ( + property: background-image, + class: bg, + values: (gradient: var(--#{$prefix}gradient)) + ), + // scss-docs-start utils-interaction + "user-select": ( + property: user-select, + values: all auto none + ), + "pointer-events": ( + property: pointer-events, + class: pe, + values: none auto, + ), + // scss-docs-end utils-interaction + // scss-docs-start utils-border-radius + "rounded": ( + property: border-radius, + class: rounded, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-top": ( + property: border-top-left-radius border-top-right-radius, + class: rounded-top, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-end": ( + property: border-top-right-radius border-bottom-right-radius, + class: rounded-end, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-bottom": ( + property: border-bottom-right-radius border-bottom-left-radius, + class: rounded-bottom, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + "rounded-start": ( + property: border-bottom-left-radius border-top-left-radius, + class: rounded-start, + values: ( + null: var(--#{$prefix}border-radius), + 0: 0, + 1: var(--#{$prefix}border-radius-sm), + 2: var(--#{$prefix}border-radius), + 3: var(--#{$prefix}border-radius-lg), + 4: var(--#{$prefix}border-radius-xl), + 5: var(--#{$prefix}border-radius-xxl), + circle: 50%, + pill: var(--#{$prefix}border-radius-pill) + ) + ), + // scss-docs-end utils-border-radius + // scss-docs-start utils-visibility + "visibility": ( + property: visibility, + class: null, + values: ( + visible: visible, + invisible: hidden, + ) + ), + // scss-docs-end utils-visibility + // scss-docs-start utils-zindex + "z-index": ( + property: z-index, + class: z, + values: $zindex-levels, + ) + // scss-docs-end utils-zindex + ), + $utilities +); diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_variables-dark.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_variables-dark.scss new file mode 100644 index 0000000..260f6dc --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_variables-dark.scss @@ -0,0 +1,102 @@ +// Dark color mode variables +// +// Custom variables for the `[data-bs-theme="dark"]` theme. Use this as a starting point for your own custom color modes by creating a new theme-specific file like `_variables-dark.scss` and adding the variables you need. + +// +// Global colors +// + +// scss-docs-start sass-dark-mode-vars +// scss-docs-start theme-text-dark-variables +$primary-text-emphasis-dark: tint-color($primary, 40%) !default; +$secondary-text-emphasis-dark: tint-color($secondary, 40%) !default; +$success-text-emphasis-dark: tint-color($success, 40%) !default; +$info-text-emphasis-dark: tint-color($info, 40%) !default; +$warning-text-emphasis-dark: tint-color($warning, 40%) !default; +$danger-text-emphasis-dark: tint-color($danger, 40%) !default; +$light-text-emphasis-dark: $gray-100 !default; +$dark-text-emphasis-dark: $gray-300 !default; +// scss-docs-end theme-text-dark-variables + +// scss-docs-start theme-bg-subtle-dark-variables +$primary-bg-subtle-dark: shade-color($primary, 80%) !default; +$secondary-bg-subtle-dark: shade-color($secondary, 80%) !default; +$success-bg-subtle-dark: shade-color($success, 80%) !default; +$info-bg-subtle-dark: shade-color($info, 80%) !default; +$warning-bg-subtle-dark: shade-color($warning, 80%) !default; +$danger-bg-subtle-dark: shade-color($danger, 80%) !default; +$light-bg-subtle-dark: $gray-800 !default; +$dark-bg-subtle-dark: mix($gray-800, $black) !default; +// scss-docs-end theme-bg-subtle-dark-variables + +// scss-docs-start theme-border-subtle-dark-variables +$primary-border-subtle-dark: shade-color($primary, 40%) !default; +$secondary-border-subtle-dark: shade-color($secondary, 40%) !default; +$success-border-subtle-dark: shade-color($success, 40%) !default; +$info-border-subtle-dark: shade-color($info, 40%) !default; +$warning-border-subtle-dark: shade-color($warning, 40%) !default; +$danger-border-subtle-dark: shade-color($danger, 40%) !default; +$light-border-subtle-dark: $gray-700 !default; +$dark-border-subtle-dark: $gray-800 !default; +// scss-docs-end theme-border-subtle-dark-variables + +$body-color-dark: $gray-300 !default; +$body-bg-dark: $gray-900 !default; +$body-secondary-color-dark: rgba($body-color-dark, .75) !default; +$body-secondary-bg-dark: $gray-800 !default; +$body-tertiary-color-dark: rgba($body-color-dark, .5) !default; +$body-tertiary-bg-dark: mix($gray-800, $gray-900, 50%) !default; +$body-emphasis-color-dark: $white !default; +$border-color-dark: $gray-700 !default; +$border-color-translucent-dark: rgba($white, .15) !default; +$headings-color-dark: inherit !default; +$link-color-dark: tint-color($primary, 40%) !default; +$link-hover-color-dark: shift-color($link-color-dark, -$link-shade-percentage) !default; +$code-color-dark: tint-color($code-color, 40%) !default; +$mark-color-dark: $body-color-dark !default; +$mark-bg-dark: $yellow-800 !default; + + +// +// Forms +// + +$form-select-indicator-color-dark: $body-color-dark !default; +$form-select-indicator-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='#{$form-select-indicator-color-dark}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/></svg>") !default; + +$form-switch-color-dark: rgba($white, .25) !default; +$form-switch-bg-image-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-color-dark}'/></svg>") !default; + +// scss-docs-start form-validation-colors-dark +$form-valid-color-dark: $green-300 !default; +$form-valid-border-color-dark: $green-300 !default; +$form-invalid-color-dark: $red-300 !default; +$form-invalid-border-color-dark: $red-300 !default; +// scss-docs-end form-validation-colors-dark + + +// +// Accordion +// + +$accordion-icon-color-dark: $primary-text-emphasis-dark !default; +$accordion-icon-active-color-dark: $primary-text-emphasis-dark !default; + +$accordion-button-icon-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-color-dark}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/></svg>") !default; +$accordion-button-active-icon-dark: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$accordion-icon-active-color-dark}'><path fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708'/></svg>") !default; +// scss-docs-end sass-dark-mode-vars + + +// +// Carousel +// + +$carousel-indicator-active-bg-dark: $carousel-dark-indicator-active-bg !default; +$carousel-caption-color-dark: $carousel-dark-caption-color !default; +$carousel-control-icon-filter-dark: $carousel-dark-control-icon-filter !default; + +// +// Close button +// + +$btn-close-filter-dark: $btn-close-white-filter !default; diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_variables.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_variables.scss new file mode 100644 index 0000000..1ffa7e7 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/_variables.scss @@ -0,0 +1,1753 @@ +// Variables +// +// Variables should follow the `$component-state-property-size` formula for +// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs. + +// Color system + +// scss-docs-start gray-color-variables +$white: #fff !default; +$gray-100: #f8f9fa !default; +$gray-200: #e9ecef !default; +$gray-300: #dee2e6 !default; +$gray-400: #ced4da !default; +$gray-500: #adb5bd !default; +$gray-600: #6c757d !default; +$gray-700: #495057 !default; +$gray-800: #343a40 !default; +$gray-900: #212529 !default; +$black: #000 !default; +// scss-docs-end gray-color-variables + +// fusv-disable +// scss-docs-start gray-colors-map +$grays: ( + "100": $gray-100, + "200": $gray-200, + "300": $gray-300, + "400": $gray-400, + "500": $gray-500, + "600": $gray-600, + "700": $gray-700, + "800": $gray-800, + "900": $gray-900 +) !default; +// scss-docs-end gray-colors-map +// fusv-enable + +// scss-docs-start color-variables +$blue: #0d6efd !default; +$indigo: #6610f2 !default; +$purple: #6f42c1 !default; +$pink: #d63384 !default; +$red: #dc3545 !default; +$orange: #fd7e14 !default; +$yellow: #ffc107 !default; +$green: #198754 !default; +$teal: #20c997 !default; +$cyan: #0dcaf0 !default; +// scss-docs-end color-variables + +// scss-docs-start colors-map +$colors: ( + "blue": $blue, + "indigo": $indigo, + "purple": $purple, + "pink": $pink, + "red": $red, + "orange": $orange, + "yellow": $yellow, + "green": $green, + "teal": $teal, + "cyan": $cyan, + "black": $black, + "white": $white, + "gray": $gray-600, + "gray-dark": $gray-800 +) !default; +// scss-docs-end colors-map + +// The contrast ratio to reach against white, to determine if color changes from "light" to "dark". Acceptable values for WCAG 2.2 are 3, 4.5 and 7. +// See https://www.w3.org/TR/WCAG/#contrast-minimum +$min-contrast-ratio: 4.5 !default; + +// Customize the light and dark text colors for use in our color contrast function. +$color-contrast-dark: $black !default; +$color-contrast-light: $white !default; + +// fusv-disable +$blue-100: tint-color($blue, 80%) !default; +$blue-200: tint-color($blue, 60%) !default; +$blue-300: tint-color($blue, 40%) !default; +$blue-400: tint-color($blue, 20%) !default; +$blue-500: $blue !default; +$blue-600: shade-color($blue, 20%) !default; +$blue-700: shade-color($blue, 40%) !default; +$blue-800: shade-color($blue, 60%) !default; +$blue-900: shade-color($blue, 80%) !default; + +$indigo-100: tint-color($indigo, 80%) !default; +$indigo-200: tint-color($indigo, 60%) !default; +$indigo-300: tint-color($indigo, 40%) !default; +$indigo-400: tint-color($indigo, 20%) !default; +$indigo-500: $indigo !default; +$indigo-600: shade-color($indigo, 20%) !default; +$indigo-700: shade-color($indigo, 40%) !default; +$indigo-800: shade-color($indigo, 60%) !default; +$indigo-900: shade-color($indigo, 80%) !default; + +$purple-100: tint-color($purple, 80%) !default; +$purple-200: tint-color($purple, 60%) !default; +$purple-300: tint-color($purple, 40%) !default; +$purple-400: tint-color($purple, 20%) !default; +$purple-500: $purple !default; +$purple-600: shade-color($purple, 20%) !default; +$purple-700: shade-color($purple, 40%) !default; +$purple-800: shade-color($purple, 60%) !default; +$purple-900: shade-color($purple, 80%) !default; + +$pink-100: tint-color($pink, 80%) !default; +$pink-200: tint-color($pink, 60%) !default; +$pink-300: tint-color($pink, 40%) !default; +$pink-400: tint-color($pink, 20%) !default; +$pink-500: $pink !default; +$pink-600: shade-color($pink, 20%) !default; +$pink-700: shade-color($pink, 40%) !default; +$pink-800: shade-color($pink, 60%) !default; +$pink-900: shade-color($pink, 80%) !default; + +$red-100: tint-color($red, 80%) !default; +$red-200: tint-color($red, 60%) !default; +$red-300: tint-color($red, 40%) !default; +$red-400: tint-color($red, 20%) !default; +$red-500: $red !default; +$red-600: shade-color($red, 20%) !default; +$red-700: shade-color($red, 40%) !default; +$red-800: shade-color($red, 60%) !default; +$red-900: shade-color($red, 80%) !default; + +$orange-100: tint-color($orange, 80%) !default; +$orange-200: tint-color($orange, 60%) !default; +$orange-300: tint-color($orange, 40%) !default; +$orange-400: tint-color($orange, 20%) !default; +$orange-500: $orange !default; +$orange-600: shade-color($orange, 20%) !default; +$orange-700: shade-color($orange, 40%) !default; +$orange-800: shade-color($orange, 60%) !default; +$orange-900: shade-color($orange, 80%) !default; + +$yellow-100: tint-color($yellow, 80%) !default; +$yellow-200: tint-color($yellow, 60%) !default; +$yellow-300: tint-color($yellow, 40%) !default; +$yellow-400: tint-color($yellow, 20%) !default; +$yellow-500: $yellow !default; +$yellow-600: shade-color($yellow, 20%) !default; +$yellow-700: shade-color($yellow, 40%) !default; +$yellow-800: shade-color($yellow, 60%) !default; +$yellow-900: shade-color($yellow, 80%) !default; + +$green-100: tint-color($green, 80%) !default; +$green-200: tint-color($green, 60%) !default; +$green-300: tint-color($green, 40%) !default; +$green-400: tint-color($green, 20%) !default; +$green-500: $green !default; +$green-600: shade-color($green, 20%) !default; +$green-700: shade-color($green, 40%) !default; +$green-800: shade-color($green, 60%) !default; +$green-900: shade-color($green, 80%) !default; + +$teal-100: tint-color($teal, 80%) !default; +$teal-200: tint-color($teal, 60%) !default; +$teal-300: tint-color($teal, 40%) !default; +$teal-400: tint-color($teal, 20%) !default; +$teal-500: $teal !default; +$teal-600: shade-color($teal, 20%) !default; +$teal-700: shade-color($teal, 40%) !default; +$teal-800: shade-color($teal, 60%) !default; +$teal-900: shade-color($teal, 80%) !default; + +$cyan-100: tint-color($cyan, 80%) !default; +$cyan-200: tint-color($cyan, 60%) !default; +$cyan-300: tint-color($cyan, 40%) !default; +$cyan-400: tint-color($cyan, 20%) !default; +$cyan-500: $cyan !default; +$cyan-600: shade-color($cyan, 20%) !default; +$cyan-700: shade-color($cyan, 40%) !default; +$cyan-800: shade-color($cyan, 60%) !default; +$cyan-900: shade-color($cyan, 80%) !default; + +$blues: ( + "blue-100": $blue-100, + "blue-200": $blue-200, + "blue-300": $blue-300, + "blue-400": $blue-400, + "blue-500": $blue-500, + "blue-600": $blue-600, + "blue-700": $blue-700, + "blue-800": $blue-800, + "blue-900": $blue-900 +) !default; + +$indigos: ( + "indigo-100": $indigo-100, + "indigo-200": $indigo-200, + "indigo-300": $indigo-300, + "indigo-400": $indigo-400, + "indigo-500": $indigo-500, + "indigo-600": $indigo-600, + "indigo-700": $indigo-700, + "indigo-800": $indigo-800, + "indigo-900": $indigo-900 +) !default; + +$purples: ( + "purple-100": $purple-100, + "purple-200": $purple-200, + "purple-300": $purple-300, + "purple-400": $purple-400, + "purple-500": $purple-500, + "purple-600": $purple-600, + "purple-700": $purple-700, + "purple-800": $purple-800, + "purple-900": $purple-900 +) !default; + +$pinks: ( + "pink-100": $pink-100, + "pink-200": $pink-200, + "pink-300": $pink-300, + "pink-400": $pink-400, + "pink-500": $pink-500, + "pink-600": $pink-600, + "pink-700": $pink-700, + "pink-800": $pink-800, + "pink-900": $pink-900 +) !default; + +$reds: ( + "red-100": $red-100, + "red-200": $red-200, + "red-300": $red-300, + "red-400": $red-400, + "red-500": $red-500, + "red-600": $red-600, + "red-700": $red-700, + "red-800": $red-800, + "red-900": $red-900 +) !default; + +$oranges: ( + "orange-100": $orange-100, + "orange-200": $orange-200, + "orange-300": $orange-300, + "orange-400": $orange-400, + "orange-500": $orange-500, + "orange-600": $orange-600, + "orange-700": $orange-700, + "orange-800": $orange-800, + "orange-900": $orange-900 +) !default; + +$yellows: ( + "yellow-100": $yellow-100, + "yellow-200": $yellow-200, + "yellow-300": $yellow-300, + "yellow-400": $yellow-400, + "yellow-500": $yellow-500, + "yellow-600": $yellow-600, + "yellow-700": $yellow-700, + "yellow-800": $yellow-800, + "yellow-900": $yellow-900 +) !default; + +$greens: ( + "green-100": $green-100, + "green-200": $green-200, + "green-300": $green-300, + "green-400": $green-400, + "green-500": $green-500, + "green-600": $green-600, + "green-700": $green-700, + "green-800": $green-800, + "green-900": $green-900 +) !default; + +$teals: ( + "teal-100": $teal-100, + "teal-200": $teal-200, + "teal-300": $teal-300, + "teal-400": $teal-400, + "teal-500": $teal-500, + "teal-600": $teal-600, + "teal-700": $teal-700, + "teal-800": $teal-800, + "teal-900": $teal-900 +) !default; + +$cyans: ( + "cyan-100": $cyan-100, + "cyan-200": $cyan-200, + "cyan-300": $cyan-300, + "cyan-400": $cyan-400, + "cyan-500": $cyan-500, + "cyan-600": $cyan-600, + "cyan-700": $cyan-700, + "cyan-800": $cyan-800, + "cyan-900": $cyan-900 +) !default; +// fusv-enable + +// scss-docs-start theme-color-variables +$primary: $blue !default; +$secondary: $gray-600 !default; +$success: $green !default; +$info: $cyan !default; +$warning: $yellow !default; +$danger: $red !default; +$light: $gray-100 !default; +$dark: $gray-900 !default; +// scss-docs-end theme-color-variables + +// scss-docs-start theme-colors-map +$theme-colors: ( + "primary": $primary, + "secondary": $secondary, + "success": $success, + "info": $info, + "warning": $warning, + "danger": $danger, + "light": $light, + "dark": $dark +) !default; +// scss-docs-end theme-colors-map + +// scss-docs-start theme-text-variables +$primary-text-emphasis: shade-color($primary, 60%) !default; +$secondary-text-emphasis: shade-color($secondary, 60%) !default; +$success-text-emphasis: shade-color($success, 60%) !default; +$info-text-emphasis: shade-color($info, 60%) !default; +$warning-text-emphasis: shade-color($warning, 60%) !default; +$danger-text-emphasis: shade-color($danger, 60%) !default; +$light-text-emphasis: $gray-700 !default; +$dark-text-emphasis: $gray-700 !default; +// scss-docs-end theme-text-variables + +// scss-docs-start theme-bg-subtle-variables +$primary-bg-subtle: tint-color($primary, 80%) !default; +$secondary-bg-subtle: tint-color($secondary, 80%) !default; +$success-bg-subtle: tint-color($success, 80%) !default; +$info-bg-subtle: tint-color($info, 80%) !default; +$warning-bg-subtle: tint-color($warning, 80%) !default; +$danger-bg-subtle: tint-color($danger, 80%) !default; +$light-bg-subtle: mix($gray-100, $white) !default; +$dark-bg-subtle: $gray-400 !default; +// scss-docs-end theme-bg-subtle-variables + +// scss-docs-start theme-border-subtle-variables +$primary-border-subtle: tint-color($primary, 60%) !default; +$secondary-border-subtle: tint-color($secondary, 60%) !default; +$success-border-subtle: tint-color($success, 60%) !default; +$info-border-subtle: tint-color($info, 60%) !default; +$warning-border-subtle: tint-color($warning, 60%) !default; +$danger-border-subtle: tint-color($danger, 60%) !default; +$light-border-subtle: $gray-200 !default; +$dark-border-subtle: $gray-500 !default; +// scss-docs-end theme-border-subtle-variables + +// Characters which are escaped by the escape-svg function +$escaped-characters: ( + ("<", "%3c"), + (">", "%3e"), + ("#", "%23"), + ("(", "%28"), + (")", "%29"), +) !default; + +// Options +// +// Quickly modify global styling by enabling or disabling optional features. + +$enable-caret: true !default; +$enable-rounded: true !default; +$enable-shadows: false !default; +$enable-gradients: false !default; +$enable-transitions: true !default; +$enable-reduced-motion: true !default; +$enable-smooth-scroll: true !default; +$enable-grid-classes: true !default; +$enable-container-classes: true !default; +$enable-cssgrid: false !default; +$enable-button-pointers: true !default; +$enable-rfs: true !default; +$enable-validation-icons: true !default; +$enable-negative-margins: false !default; +$enable-deprecation-messages: true !default; +$enable-important-utilities: true !default; + +$enable-dark-mode: true !default; +$color-mode-type: data !default; // `data` or `media-query` + +// Prefix for :root CSS variables + +$variable-prefix: bs- !default; // Deprecated in v5.2.0 for the shorter `$prefix` +$prefix: $variable-prefix !default; + +// Gradient +// +// The gradient which is added to components if `$enable-gradients` is `true` +// This gradient is also added to elements with `.bg-gradient` +// scss-docs-start variable-gradient +$gradient: linear-gradient(180deg, rgba($white, .15), rgba($white, 0)) !default; +// scss-docs-end variable-gradient + +// Spacing +// +// Control the default styling of most Bootstrap elements by modifying these +// variables. Mostly focused on spacing. +// You can add more entries to the $spacers map, should you need more variation. + +// scss-docs-start spacer-variables-maps +$spacer: 1rem !default; +$spacers: ( + 0: 0, + 1: $spacer * .25, + 2: $spacer * .5, + 3: $spacer, + 4: $spacer * 1.5, + 5: $spacer * 3, +) !default; +// scss-docs-end spacer-variables-maps + +// Position +// +// Define the edge positioning anchors of the position utilities. + +// scss-docs-start position-map +$position-values: ( + 0: 0, + 50: 50%, + 100: 100% +) !default; +// scss-docs-end position-map + +// Body +// +// Settings for the `<body>` element. + +$body-text-align: null !default; +$body-color: $gray-900 !default; +$body-bg: $white !default; + +$body-secondary-color: rgba($body-color, .75) !default; +$body-secondary-bg: $gray-200 !default; + +$body-tertiary-color: rgba($body-color, .5) !default; +$body-tertiary-bg: $gray-100 !default; + +$body-emphasis-color: $black !default; + +// Links +// +// Style anchor elements. + +$link-color: $primary !default; +$link-decoration: underline !default; +$link-shade-percentage: 20% !default; +$link-hover-color: shift-color($link-color, $link-shade-percentage) !default; +$link-hover-decoration: null !default; + +$stretched-link-pseudo-element: after !default; +$stretched-link-z-index: 1 !default; + +// Icon links +// scss-docs-start icon-link-variables +$icon-link-gap: .375rem !default; +$icon-link-underline-offset: .25em !default; +$icon-link-icon-size: 1em !default; +$icon-link-icon-transition: .2s ease-in-out transform !default; +$icon-link-icon-transform: translate3d(.25em, 0, 0) !default; +// scss-docs-end icon-link-variables + +// Paragraphs +// +// Style p element. + +$paragraph-margin-bottom: 1rem !default; + + +// Grid breakpoints +// +// Define the minimum dimensions at which your layout will change, +// adapting to different screen sizes, for use in media queries. + +// scss-docs-start grid-breakpoints +$grid-breakpoints: ( + xs: 0, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1200px, + xxl: 1400px +) !default; +// scss-docs-end grid-breakpoints + +@include _assert-ascending($grid-breakpoints, "$grid-breakpoints"); +@include _assert-starts-at-zero($grid-breakpoints, "$grid-breakpoints"); + + +// Grid containers +// +// Define the maximum width of `.container` for different screen sizes. + +// scss-docs-start container-max-widths +$container-max-widths: ( + sm: 540px, + md: 720px, + lg: 960px, + xl: 1140px, + xxl: 1320px +) !default; +// scss-docs-end container-max-widths + +@include _assert-ascending($container-max-widths, "$container-max-widths"); + + +// Grid columns +// +// Set the number of columns and specify the width of the gutters. + +$grid-columns: 12 !default; +$grid-gutter-width: 1.5rem !default; +$grid-row-columns: 6 !default; + +// Container padding + +$container-padding-x: $grid-gutter-width !default; + + +// Components +// +// Define common padding and border radius sizes and more. + +// scss-docs-start border-variables +$border-width: 1px !default; +$border-widths: ( + 1: 1px, + 2: 2px, + 3: 3px, + 4: 4px, + 5: 5px +) !default; +$border-style: solid !default; +$border-color: $gray-300 !default; +$border-color-translucent: rgba($black, .175) !default; +// scss-docs-end border-variables + +// scss-docs-start border-radius-variables +$border-radius: .375rem !default; +$border-radius-sm: .25rem !default; +$border-radius-lg: .5rem !default; +$border-radius-xl: 1rem !default; +$border-radius-xxl: 2rem !default; +$border-radius-pill: 50rem !default; +// scss-docs-end border-radius-variables +// fusv-disable +$border-radius-2xl: $border-radius-xxl !default; // Deprecated in v5.3.0 +// fusv-enable + +// scss-docs-start box-shadow-variables +$box-shadow: 0 .5rem 1rem rgba($black, .15) !default; +$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default; +$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default; +$box-shadow-inset: inset 0 1px 2px rgba($black, .075) !default; +// scss-docs-end box-shadow-variables + +$component-active-color: $white !default; +$component-active-bg: $primary !default; + +// scss-docs-start focus-ring-variables +$focus-ring-width: .25rem !default; +$focus-ring-opacity: .25 !default; +$focus-ring-color: rgba($primary, $focus-ring-opacity) !default; +$focus-ring-blur: 0 !default; +$focus-ring-box-shadow: 0 0 $focus-ring-blur $focus-ring-width $focus-ring-color !default; +// scss-docs-end focus-ring-variables + +// scss-docs-start caret-variables +$caret-width: .3em !default; +$caret-vertical-align: $caret-width * .85 !default; +$caret-spacing: $caret-width * .85 !default; +// scss-docs-end caret-variables + +$transition-base: all .2s ease-in-out !default; +$transition-fade: opacity .15s linear !default; +// scss-docs-start collapse-transition +$transition-collapse: height .35s ease !default; +$transition-collapse-width: width .35s ease !default; +// scss-docs-end collapse-transition + +// stylelint-disable function-disallowed-list +// scss-docs-start aspect-ratios +$aspect-ratios: ( + "1x1": 100%, + "4x3": calc(3 / 4 * 100%), + "16x9": calc(9 / 16 * 100%), + "21x9": calc(9 / 21 * 100%) +) !default; +// scss-docs-end aspect-ratios +// stylelint-enable function-disallowed-list + +// Typography +// +// Font, line-height, and color for body text, headings, and more. + +// scss-docs-start font-variables +// stylelint-disable value-keyword-case +$font-family-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji" !default; +$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default; +// stylelint-enable value-keyword-case +$font-family-base: var(--#{$prefix}font-sans-serif) !default; +$font-family-code: var(--#{$prefix}font-monospace) !default; + +// $font-size-root affects the value of `rem`, which is used for as well font sizes, paddings, and margins +// $font-size-base affects the font size of the body text +$font-size-root: null !default; +$font-size-base: 1rem !default; // Assumes the browser default, typically `16px` +$font-size-sm: $font-size-base * .875 !default; +$font-size-lg: $font-size-base * 1.25 !default; + +$font-weight-lighter: lighter !default; +$font-weight-light: 300 !default; +$font-weight-normal: 400 !default; +$font-weight-medium: 500 !default; +$font-weight-semibold: 600 !default; +$font-weight-bold: 700 !default; +$font-weight-bolder: bolder !default; + +$font-weight-base: $font-weight-normal !default; + +$line-height-base: 1.5 !default; +$line-height-sm: 1.25 !default; +$line-height-lg: 2 !default; + +$h1-font-size: $font-size-base * 2.5 !default; +$h2-font-size: $font-size-base * 2 !default; +$h3-font-size: $font-size-base * 1.75 !default; +$h4-font-size: $font-size-base * 1.5 !default; +$h5-font-size: $font-size-base * 1.25 !default; +$h6-font-size: $font-size-base !default; +// scss-docs-end font-variables + +// scss-docs-start font-sizes +$font-sizes: ( + 1: $h1-font-size, + 2: $h2-font-size, + 3: $h3-font-size, + 4: $h4-font-size, + 5: $h5-font-size, + 6: $h6-font-size +) !default; +// scss-docs-end font-sizes + +// scss-docs-start headings-variables +$headings-margin-bottom: $spacer * .5 !default; +$headings-font-family: null !default; +$headings-font-style: null !default; +$headings-font-weight: 500 !default; +$headings-line-height: 1.2 !default; +$headings-color: inherit !default; +// scss-docs-end headings-variables + +// scss-docs-start display-headings +$display-font-sizes: ( + 1: 5rem, + 2: 4.5rem, + 3: 4rem, + 4: 3.5rem, + 5: 3rem, + 6: 2.5rem +) !default; + +$display-font-family: null !default; +$display-font-style: null !default; +$display-font-weight: 300 !default; +$display-line-height: $headings-line-height !default; +// scss-docs-end display-headings + +// scss-docs-start type-variables +$lead-font-size: $font-size-base * 1.25 !default; +$lead-font-weight: 300 !default; + +$small-font-size: .875em !default; + +$sub-sup-font-size: .75em !default; + +// fusv-disable +$text-muted: var(--#{$prefix}secondary-color) !default; // Deprecated in 5.3.0 +// fusv-enable + +$initialism-font-size: $small-font-size !default; + +$blockquote-margin-y: $spacer !default; +$blockquote-font-size: $font-size-base * 1.25 !default; +$blockquote-footer-color: $gray-600 !default; +$blockquote-footer-font-size: $small-font-size !default; + +$hr-margin-y: $spacer !default; +$hr-color: inherit !default; + +// fusv-disable +$hr-bg-color: null !default; // Deprecated in v5.2.0 +$hr-height: null !default; // Deprecated in v5.2.0 +// fusv-enable + +$hr-border-color: null !default; // Allows for inherited colors +$hr-border-width: var(--#{$prefix}border-width) !default; +$hr-opacity: .25 !default; + +// scss-docs-start vr-variables +$vr-border-width: var(--#{$prefix}border-width) !default; +// scss-docs-end vr-variables + +$legend-margin-bottom: .5rem !default; +$legend-font-size: 1.5rem !default; +$legend-font-weight: null !default; + +$dt-font-weight: $font-weight-bold !default; + +$list-inline-padding: .5rem !default; + +$mark-padding: .1875em !default; +$mark-color: $body-color !default; +$mark-bg: $yellow-100 !default; +// scss-docs-end type-variables + + +// Tables +// +// Customizes the `.table` component with basic values, each used across all table variations. + +// scss-docs-start table-variables +$table-cell-padding-y: .5rem !default; +$table-cell-padding-x: .5rem !default; +$table-cell-padding-y-sm: .25rem !default; +$table-cell-padding-x-sm: .25rem !default; + +$table-cell-vertical-align: top !default; + +$table-color: var(--#{$prefix}emphasis-color) !default; +$table-bg: var(--#{$prefix}body-bg) !default; +$table-accent-bg: transparent !default; + +$table-th-font-weight: null !default; + +$table-striped-color: $table-color !default; +$table-striped-bg-factor: .05 !default; +$table-striped-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-striped-bg-factor) !default; + +$table-active-color: $table-color !default; +$table-active-bg-factor: .1 !default; +$table-active-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-active-bg-factor) !default; + +$table-hover-color: $table-color !default; +$table-hover-bg-factor: .075 !default; +$table-hover-bg: rgba(var(--#{$prefix}emphasis-color-rgb), $table-hover-bg-factor) !default; + +$table-border-factor: .2 !default; +$table-border-width: var(--#{$prefix}border-width) !default; +$table-border-color: var(--#{$prefix}border-color) !default; + +$table-striped-order: odd !default; +$table-striped-columns-order: even !default; + +$table-group-separator-color: currentcolor !default; + +$table-caption-color: var(--#{$prefix}secondary-color) !default; + +$table-bg-scale: -80% !default; +// scss-docs-end table-variables + +// scss-docs-start table-loop +$table-variants: ( + "primary": shift-color($primary, $table-bg-scale), + "secondary": shift-color($secondary, $table-bg-scale), + "success": shift-color($success, $table-bg-scale), + "info": shift-color($info, $table-bg-scale), + "warning": shift-color($warning, $table-bg-scale), + "danger": shift-color($danger, $table-bg-scale), + "light": $light, + "dark": $dark, +) !default; +// scss-docs-end table-loop + + +// Buttons + Forms +// +// Shared variables that are reassigned to `$input-` and `$btn-` specific variables. + +// scss-docs-start input-btn-variables +$input-btn-padding-y: .375rem !default; +$input-btn-padding-x: .75rem !default; +$input-btn-font-family: null !default; +$input-btn-font-size: $font-size-base !default; +$input-btn-line-height: $line-height-base !default; + +$input-btn-focus-width: $focus-ring-width !default; +$input-btn-focus-color-opacity: $focus-ring-opacity !default; +$input-btn-focus-color: $focus-ring-color !default; +$input-btn-focus-blur: $focus-ring-blur !default; +$input-btn-focus-box-shadow: $focus-ring-box-shadow !default; + +$input-btn-padding-y-sm: .25rem !default; +$input-btn-padding-x-sm: .5rem !default; +$input-btn-font-size-sm: $font-size-sm !default; + +$input-btn-padding-y-lg: .5rem !default; +$input-btn-padding-x-lg: 1rem !default; +$input-btn-font-size-lg: $font-size-lg !default; + +$input-btn-border-width: var(--#{$prefix}border-width) !default; +// scss-docs-end input-btn-variables + + +// Buttons +// +// For each of Bootstrap's buttons, define text, background, and border color. + +// scss-docs-start btn-variables +$btn-color: var(--#{$prefix}body-color) !default; +$btn-padding-y: $input-btn-padding-y !default; +$btn-padding-x: $input-btn-padding-x !default; +$btn-font-family: $input-btn-font-family !default; +$btn-font-size: $input-btn-font-size !default; +$btn-line-height: $input-btn-line-height !default; +$btn-white-space: null !default; // Set to `nowrap` to prevent text wrapping + +$btn-padding-y-sm: $input-btn-padding-y-sm !default; +$btn-padding-x-sm: $input-btn-padding-x-sm !default; +$btn-font-size-sm: $input-btn-font-size-sm !default; + +$btn-padding-y-lg: $input-btn-padding-y-lg !default; +$btn-padding-x-lg: $input-btn-padding-x-lg !default; +$btn-font-size-lg: $input-btn-font-size-lg !default; + +$btn-border-width: $input-btn-border-width !default; + +$btn-font-weight: $font-weight-normal !default; +$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default; +$btn-focus-width: $input-btn-focus-width !default; +$btn-focus-box-shadow: $input-btn-focus-box-shadow !default; +$btn-disabled-opacity: .65 !default; +$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default; + +$btn-link-color: var(--#{$prefix}link-color) !default; +$btn-link-hover-color: var(--#{$prefix}link-hover-color) !default; +$btn-link-disabled-color: $gray-600 !default; +$btn-link-focus-shadow-rgb: to-rgb(mix(color-contrast($link-color), $link-color, 15%)) !default; + +// Allows for customizing button radius independently from global border radius +$btn-border-radius: var(--#{$prefix}border-radius) !default; +$btn-border-radius-sm: var(--#{$prefix}border-radius-sm) !default; +$btn-border-radius-lg: var(--#{$prefix}border-radius-lg) !default; + +$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$btn-hover-bg-shade-amount: 15% !default; +$btn-hover-bg-tint-amount: 15% !default; +$btn-hover-border-shade-amount: 20% !default; +$btn-hover-border-tint-amount: 10% !default; +$btn-active-bg-shade-amount: 20% !default; +$btn-active-bg-tint-amount: 20% !default; +$btn-active-border-shade-amount: 25% !default; +$btn-active-border-tint-amount: 10% !default; +// scss-docs-end btn-variables + + +// Forms + +// scss-docs-start form-text-variables +$form-text-margin-top: .25rem !default; +$form-text-font-size: $small-font-size !default; +$form-text-font-style: null !default; +$form-text-font-weight: null !default; +$form-text-color: var(--#{$prefix}secondary-color) !default; +// scss-docs-end form-text-variables + +// scss-docs-start form-label-variables +$form-label-margin-bottom: .5rem !default; +$form-label-font-size: null !default; +$form-label-font-style: null !default; +$form-label-font-weight: null !default; +$form-label-color: null !default; +// scss-docs-end form-label-variables + +// scss-docs-start form-input-variables +$input-padding-y: $input-btn-padding-y !default; +$input-padding-x: $input-btn-padding-x !default; +$input-font-family: $input-btn-font-family !default; +$input-font-size: $input-btn-font-size !default; +$input-font-weight: $font-weight-base !default; +$input-line-height: $input-btn-line-height !default; + +$input-padding-y-sm: $input-btn-padding-y-sm !default; +$input-padding-x-sm: $input-btn-padding-x-sm !default; +$input-font-size-sm: $input-btn-font-size-sm !default; + +$input-padding-y-lg: $input-btn-padding-y-lg !default; +$input-padding-x-lg: $input-btn-padding-x-lg !default; +$input-font-size-lg: $input-btn-font-size-lg !default; + +$input-bg: var(--#{$prefix}body-bg) !default; +$input-disabled-color: null !default; +$input-disabled-bg: var(--#{$prefix}secondary-bg) !default; +$input-disabled-border-color: null !default; + +$input-color: var(--#{$prefix}body-color) !default; +$input-border-color: var(--#{$prefix}border-color) !default; +$input-border-width: $input-btn-border-width !default; +$input-box-shadow: var(--#{$prefix}box-shadow-inset) !default; + +$input-border-radius: var(--#{$prefix}border-radius) !default; +$input-border-radius-sm: var(--#{$prefix}border-radius-sm) !default; +$input-border-radius-lg: var(--#{$prefix}border-radius-lg) !default; + +$input-focus-bg: $input-bg !default; +$input-focus-border-color: tint-color($component-active-bg, 50%) !default; +$input-focus-color: $input-color !default; +$input-focus-width: $input-btn-focus-width !default; +$input-focus-box-shadow: $input-btn-focus-box-shadow !default; + +$input-placeholder-color: var(--#{$prefix}secondary-color) !default; +$input-plaintext-color: var(--#{$prefix}body-color) !default; + +$input-height-border: calc(#{$input-border-width} * 2) !default; // stylelint-disable-line function-disallowed-list + +$input-height-inner: add($input-line-height * 1em, $input-padding-y * 2) !default; +$input-height-inner-half: add($input-line-height * .5em, $input-padding-y) !default; +$input-height-inner-quarter: add($input-line-height * .25em, $input-padding-y * .5) !default; + +$input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-height-border, false)) !default; +$input-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2, $input-height-border, false)) !default; +$input-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2, $input-height-border, false)) !default; + +$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$form-color-width: 3rem !default; +// scss-docs-end form-input-variables + +// scss-docs-start form-check-variables +$form-check-input-width: 1em !default; +$form-check-min-height: $font-size-base * $line-height-base !default; +$form-check-padding-start: $form-check-input-width + .5em !default; +$form-check-margin-bottom: .125rem !default; +$form-check-label-color: null !default; +$form-check-label-cursor: null !default; +$form-check-transition: null !default; + +$form-check-input-active-filter: brightness(90%) !default; + +$form-check-input-bg: $input-bg !default; +$form-check-input-border: var(--#{$prefix}border-width) solid var(--#{$prefix}border-color) !default; +$form-check-input-border-radius: .25em !default; +$form-check-radio-border-radius: 50% !default; +$form-check-input-focus-border: $input-focus-border-color !default; +$form-check-input-focus-box-shadow: $focus-ring-box-shadow !default; + +$form-check-input-checked-color: $component-active-color !default; +$form-check-input-checked-bg-color: $component-active-bg !default; +$form-check-input-checked-border-color: $form-check-input-checked-bg-color !default; +$form-check-input-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#{$form-check-input-checked-color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='m6 10 3 3 6-6'/></svg>") !default; +$form-check-radio-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='2' fill='#{$form-check-input-checked-color}'/></svg>") !default; + +$form-check-input-indeterminate-color: $component-active-color !default; +$form-check-input-indeterminate-bg-color: $component-active-bg !default; +$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color !default; +$form-check-input-indeterminate-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'><path fill='none' stroke='#{$form-check-input-indeterminate-color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/></svg>") !default; + +$form-check-input-disabled-opacity: .5 !default; +$form-check-label-disabled-opacity: $form-check-input-disabled-opacity !default; +$form-check-btn-check-disabled-opacity: $btn-disabled-opacity !default; + +$form-check-inline-margin-end: 1rem !default; +// scss-docs-end form-check-variables + +// scss-docs-start form-switch-variables +$form-switch-color: rgba($black, .25) !default; +$form-switch-width: 2em !default; +$form-switch-padding-start: $form-switch-width + .5em !default; +$form-switch-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-color}'/></svg>") !default; +$form-switch-border-radius: $form-switch-width !default; +$form-switch-transition: background-position .15s ease-in-out !default; + +$form-switch-focus-color: $input-focus-border-color !default; +$form-switch-focus-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-focus-color}'/></svg>") !default; + +$form-switch-checked-color: $component-active-color !default; +$form-switch-checked-bg-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'><circle r='3' fill='#{$form-switch-checked-color}'/></svg>") !default; +$form-switch-checked-bg-position: right center !default; +// scss-docs-end form-switch-variables + +// scss-docs-start input-group-variables +$input-group-addon-padding-y: $input-padding-y !default; +$input-group-addon-padding-x: $input-padding-x !default; +$input-group-addon-font-weight: $input-font-weight !default; +$input-group-addon-color: $input-color !default; +$input-group-addon-bg: var(--#{$prefix}tertiary-bg) !default; +$input-group-addon-border-color: $input-border-color !default; +// scss-docs-end input-group-variables + +// scss-docs-start form-select-variables +$form-select-padding-y: $input-padding-y !default; +$form-select-padding-x: $input-padding-x !default; +$form-select-font-family: $input-font-family !default; +$form-select-font-size: $input-font-size !default; +$form-select-indicator-padding: $form-select-padding-x * 3 !default; // Extra padding for background-image +$form-select-font-weight: $input-font-weight !default; +$form-select-line-height: $input-line-height !default; +$form-select-color: $input-color !default; +$form-select-bg: $input-bg !default; +$form-select-disabled-color: null !default; +$form-select-disabled-bg: $input-disabled-bg !default; +$form-select-disabled-border-color: $input-disabled-border-color !default; +$form-select-bg-position: right $form-select-padding-x center !default; +$form-select-bg-size: 16px 12px !default; // In pixels because image dimensions +$form-select-indicator-color: $gray-800 !default; +$form-select-indicator: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path fill='none' stroke='#{$form-select-indicator-color}' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/></svg>") !default; + +$form-select-feedback-icon-padding-end: $form-select-padding-x * 2.5 + $form-select-indicator-padding !default; +$form-select-feedback-icon-position: center right $form-select-indicator-padding !default; +$form-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default; + +$form-select-border-width: $input-border-width !default; +$form-select-border-color: $input-border-color !default; +$form-select-border-radius: $input-border-radius !default; +$form-select-box-shadow: var(--#{$prefix}box-shadow-inset) !default; + +$form-select-focus-border-color: $input-focus-border-color !default; +$form-select-focus-width: $input-focus-width !default; +$form-select-focus-box-shadow: 0 0 0 $form-select-focus-width $input-btn-focus-color !default; + +$form-select-padding-y-sm: $input-padding-y-sm !default; +$form-select-padding-x-sm: $input-padding-x-sm !default; +$form-select-font-size-sm: $input-font-size-sm !default; +$form-select-border-radius-sm: $input-border-radius-sm !default; + +$form-select-padding-y-lg: $input-padding-y-lg !default; +$form-select-padding-x-lg: $input-padding-x-lg !default; +$form-select-font-size-lg: $input-font-size-lg !default; +$form-select-border-radius-lg: $input-border-radius-lg !default; + +$form-select-transition: $input-transition !default; +// scss-docs-end form-select-variables + +// scss-docs-start form-range-variables +$form-range-track-width: 100% !default; +$form-range-track-height: .5rem !default; +$form-range-track-cursor: pointer !default; +$form-range-track-bg: var(--#{$prefix}secondary-bg) !default; +$form-range-track-border-radius: 1rem !default; +$form-range-track-box-shadow: var(--#{$prefix}box-shadow-inset) !default; + +$form-range-thumb-width: 1rem !default; +$form-range-thumb-height: $form-range-thumb-width !default; +$form-range-thumb-bg: $component-active-bg !default; +$form-range-thumb-border: 0 !default; +$form-range-thumb-border-radius: 1rem !default; +$form-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default; +$form-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default; +$form-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in Edge +$form-range-thumb-active-bg: tint-color($component-active-bg, 70%) !default; +$form-range-thumb-disabled-bg: var(--#{$prefix}secondary-color) !default; +$form-range-thumb-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; +// scss-docs-end form-range-variables + +// scss-docs-start form-file-variables +$form-file-button-color: $input-color !default; +$form-file-button-bg: var(--#{$prefix}tertiary-bg) !default; +$form-file-button-hover-bg: var(--#{$prefix}secondary-bg) !default; +// scss-docs-end form-file-variables + +// scss-docs-start form-floating-variables +$form-floating-height: add(3.5rem, $input-height-border) !default; +$form-floating-line-height: 1.25 !default; +$form-floating-padding-x: $input-padding-x !default; +$form-floating-padding-y: 1rem !default; +$form-floating-input-padding-t: 1.625rem !default; +$form-floating-input-padding-b: .625rem !default; +$form-floating-label-height: 1.5em !default; +$form-floating-label-opacity: .65 !default; +$form-floating-label-transform: scale(.85) translateY(-.5rem) translateX(.15rem) !default; +$form-floating-label-disabled-color: $gray-600 !default; +$form-floating-transition: opacity .1s ease-in-out, transform .1s ease-in-out !default; +// scss-docs-end form-floating-variables + +// Form validation + +// scss-docs-start form-feedback-variables +$form-feedback-margin-top: $form-text-margin-top !default; +$form-feedback-font-size: $form-text-font-size !default; +$form-feedback-font-style: $form-text-font-style !default; +$form-feedback-valid-color: $success !default; +$form-feedback-invalid-color: $danger !default; + +$form-feedback-icon-valid-color: $form-feedback-valid-color !default; +$form-feedback-icon-valid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path fill='#{$form-feedback-icon-valid-color}' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1'/></svg>") !default; +$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default; +$form-feedback-icon-invalid: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='#{$form-feedback-icon-invalid-color}'><circle cx='6' cy='6' r='4.5'/><path stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/><circle cx='6' cy='8.2' r='.6' fill='#{$form-feedback-icon-invalid-color}' stroke='none'/></svg>") !default; +// scss-docs-end form-feedback-variables + +// scss-docs-start form-validation-colors +$form-valid-color: $form-feedback-valid-color !default; +$form-valid-border-color: $form-feedback-valid-color !default; +$form-invalid-color: $form-feedback-invalid-color !default; +$form-invalid-border-color: $form-feedback-invalid-color !default; +// scss-docs-end form-validation-colors + +// scss-docs-start form-validation-states +$form-validation-states: ( + "valid": ( + "color": var(--#{$prefix}form-valid-color), + "icon": $form-feedback-icon-valid, + "tooltip-color": #fff, + "tooltip-bg-color": var(--#{$prefix}success), + "focus-box-shadow": 0 0 $input-btn-focus-blur $input-focus-width rgba(var(--#{$prefix}success-rgb), $input-btn-focus-color-opacity), + "border-color": var(--#{$prefix}form-valid-border-color), + ), + "invalid": ( + "color": var(--#{$prefix}form-invalid-color), + "icon": $form-feedback-icon-invalid, + "tooltip-color": #fff, + "tooltip-bg-color": var(--#{$prefix}danger), + "focus-box-shadow": 0 0 $input-btn-focus-blur $input-focus-width rgba(var(--#{$prefix}danger-rgb), $input-btn-focus-color-opacity), + "border-color": var(--#{$prefix}form-invalid-border-color), + ) +) !default; +// scss-docs-end form-validation-states + +// Z-index master list +// +// Warning: Avoid customizing these values. They're used for a bird's eye view +// of components dependent on the z-axis and are designed to all work together. + +// scss-docs-start zindex-stack +$zindex-dropdown: 1000 !default; +$zindex-sticky: 1020 !default; +$zindex-fixed: 1030 !default; +$zindex-offcanvas-backdrop: 1040 !default; +$zindex-offcanvas: 1045 !default; +$zindex-modal-backdrop: 1050 !default; +$zindex-modal: 1055 !default; +$zindex-popover: 1070 !default; +$zindex-tooltip: 1080 !default; +$zindex-toast: 1090 !default; +// scss-docs-end zindex-stack + +// scss-docs-start zindex-levels-map +$zindex-levels: ( + n1: -1, + 0: 0, + 1: 1, + 2: 2, + 3: 3 +) !default; +// scss-docs-end zindex-levels-map + + +// Navs + +// scss-docs-start nav-variables +$nav-link-padding-y: .5rem !default; +$nav-link-padding-x: 1rem !default; +$nav-link-font-size: null !default; +$nav-link-font-weight: null !default; +$nav-link-color: var(--#{$prefix}link-color) !default; +$nav-link-hover-color: var(--#{$prefix}link-hover-color) !default; +$nav-link-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out !default; +$nav-link-disabled-color: var(--#{$prefix}secondary-color) !default; +$nav-link-focus-box-shadow: $focus-ring-box-shadow !default; + +$nav-tabs-border-color: var(--#{$prefix}border-color) !default; +$nav-tabs-border-width: var(--#{$prefix}border-width) !default; +$nav-tabs-border-radius: var(--#{$prefix}border-radius) !default; +$nav-tabs-link-hover-border-color: var(--#{$prefix}secondary-bg) var(--#{$prefix}secondary-bg) $nav-tabs-border-color !default; +$nav-tabs-link-active-color: var(--#{$prefix}emphasis-color) !default; +$nav-tabs-link-active-bg: var(--#{$prefix}body-bg) !default; +$nav-tabs-link-active-border-color: var(--#{$prefix}border-color) var(--#{$prefix}border-color) $nav-tabs-link-active-bg !default; + +$nav-pills-border-radius: var(--#{$prefix}border-radius) !default; +$nav-pills-link-active-color: $component-active-color !default; +$nav-pills-link-active-bg: $component-active-bg !default; + +$nav-underline-gap: 1rem !default; +$nav-underline-border-width: .125rem !default; +$nav-underline-link-active-color: var(--#{$prefix}emphasis-color) !default; +// scss-docs-end nav-variables + + +// Navbar + +// scss-docs-start navbar-variables +$navbar-padding-y: $spacer * .5 !default; +$navbar-padding-x: null !default; + +$navbar-nav-link-padding-x: .5rem !default; + +$navbar-brand-font-size: $font-size-lg !default; +// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link +$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default; +$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default; +$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) * .5 !default; +$navbar-brand-margin-end: 1rem !default; + +$navbar-toggler-padding-y: .25rem !default; +$navbar-toggler-padding-x: .75rem !default; +$navbar-toggler-font-size: $font-size-lg !default; +$navbar-toggler-border-radius: $btn-border-radius !default; +$navbar-toggler-focus-width: $btn-focus-width !default; +$navbar-toggler-transition: box-shadow .15s ease-in-out !default; + +$navbar-light-color: rgba(var(--#{$prefix}emphasis-color-rgb), .65) !default; +$navbar-light-hover-color: rgba(var(--#{$prefix}emphasis-color-rgb), .8) !default; +$navbar-light-active-color: rgba(var(--#{$prefix}emphasis-color-rgb), 1) !default; +$navbar-light-disabled-color: rgba(var(--#{$prefix}emphasis-color-rgb), .3) !default; +$navbar-light-icon-color: rgba($body-color, .75) !default; +$navbar-light-toggler-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke='#{$navbar-light-icon-color}' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg>") !default; +$navbar-light-toggler-border-color: rgba(var(--#{$prefix}emphasis-color-rgb), .15) !default; +$navbar-light-brand-color: $navbar-light-active-color !default; +$navbar-light-brand-hover-color: $navbar-light-active-color !default; +// scss-docs-end navbar-variables + +// scss-docs-start navbar-dark-variables +$navbar-dark-color: rgba($white, .55) !default; +$navbar-dark-hover-color: rgba($white, .75) !default; +$navbar-dark-active-color: $white !default; +$navbar-dark-disabled-color: rgba($white, .25) !default; +$navbar-dark-icon-color: $navbar-dark-color !default; +$navbar-dark-toggler-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'><path stroke='#{$navbar-dark-icon-color}' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/></svg>") !default; +$navbar-dark-toggler-border-color: rgba($white, .1) !default; +$navbar-dark-brand-color: $navbar-dark-active-color !default; +$navbar-dark-brand-hover-color: $navbar-dark-active-color !default; +// scss-docs-end navbar-dark-variables + + +// Dropdowns +// +// Dropdown menu container and contents. + +// scss-docs-start dropdown-variables +$dropdown-min-width: 10rem !default; +$dropdown-padding-x: 0 !default; +$dropdown-padding-y: .5rem !default; +$dropdown-spacer: .125rem !default; +$dropdown-font-size: $font-size-base !default; +$dropdown-color: var(--#{$prefix}body-color) !default; +$dropdown-bg: var(--#{$prefix}body-bg) !default; +$dropdown-border-color: var(--#{$prefix}border-color-translucent) !default; +$dropdown-border-radius: var(--#{$prefix}border-radius) !default; +$dropdown-border-width: var(--#{$prefix}border-width) !default; +$dropdown-inner-border-radius: calc(#{$dropdown-border-radius} - #{$dropdown-border-width}) !default; // stylelint-disable-line function-disallowed-list +$dropdown-divider-bg: $dropdown-border-color !default; +$dropdown-divider-margin-y: $spacer * .5 !default; +$dropdown-box-shadow: var(--#{$prefix}box-shadow) !default; + +$dropdown-link-color: var(--#{$prefix}body-color) !default; +$dropdown-link-hover-color: $dropdown-link-color !default; +$dropdown-link-hover-bg: var(--#{$prefix}tertiary-bg) !default; + +$dropdown-link-active-color: $component-active-color !default; +$dropdown-link-active-bg: $component-active-bg !default; + +$dropdown-link-disabled-color: var(--#{$prefix}tertiary-color) !default; + +$dropdown-item-padding-y: $spacer * .25 !default; +$dropdown-item-padding-x: $spacer !default; + +$dropdown-header-color: $gray-600 !default; +$dropdown-header-padding-x: $dropdown-item-padding-x !default; +$dropdown-header-padding-y: $dropdown-padding-y !default; +// fusv-disable +$dropdown-header-padding: $dropdown-header-padding-y $dropdown-header-padding-x !default; // Deprecated in v5.2.0 +// fusv-enable +// scss-docs-end dropdown-variables + +// scss-docs-start dropdown-dark-variables +$dropdown-dark-color: $gray-300 !default; +$dropdown-dark-bg: $gray-800 !default; +$dropdown-dark-border-color: $dropdown-border-color !default; +$dropdown-dark-divider-bg: $dropdown-divider-bg !default; +$dropdown-dark-box-shadow: null !default; +$dropdown-dark-link-color: $dropdown-dark-color !default; +$dropdown-dark-link-hover-color: $white !default; +$dropdown-dark-link-hover-bg: rgba($white, .15) !default; +$dropdown-dark-link-active-color: $dropdown-link-active-color !default; +$dropdown-dark-link-active-bg: $dropdown-link-active-bg !default; +$dropdown-dark-link-disabled-color: $gray-500 !default; +$dropdown-dark-header-color: $gray-500 !default; +// scss-docs-end dropdown-dark-variables + + +// Pagination + +// scss-docs-start pagination-variables +$pagination-padding-y: .375rem !default; +$pagination-padding-x: .75rem !default; +$pagination-padding-y-sm: .25rem !default; +$pagination-padding-x-sm: .5rem !default; +$pagination-padding-y-lg: .75rem !default; +$pagination-padding-x-lg: 1.5rem !default; + +$pagination-font-size: $font-size-base !default; + +$pagination-color: var(--#{$prefix}link-color) !default; +$pagination-bg: var(--#{$prefix}body-bg) !default; +$pagination-border-radius: var(--#{$prefix}border-radius) !default; +$pagination-border-width: var(--#{$prefix}border-width) !default; +$pagination-margin-start: calc(-1 * #{$pagination-border-width}) !default; // stylelint-disable-line function-disallowed-list +$pagination-border-color: var(--#{$prefix}border-color) !default; + +$pagination-focus-color: var(--#{$prefix}link-hover-color) !default; +$pagination-focus-bg: var(--#{$prefix}secondary-bg) !default; +$pagination-focus-box-shadow: $focus-ring-box-shadow !default; +$pagination-focus-outline: 0 !default; + +$pagination-hover-color: var(--#{$prefix}link-hover-color) !default; +$pagination-hover-bg: var(--#{$prefix}tertiary-bg) !default; +$pagination-hover-border-color: var(--#{$prefix}border-color) !default; // Todo in v6: remove this? + +$pagination-active-color: $component-active-color !default; +$pagination-active-bg: $component-active-bg !default; +$pagination-active-border-color: $component-active-bg !default; + +$pagination-disabled-color: var(--#{$prefix}secondary-color) !default; +$pagination-disabled-bg: var(--#{$prefix}secondary-bg) !default; +$pagination-disabled-border-color: var(--#{$prefix}border-color) !default; + +$pagination-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default; + +$pagination-border-radius-sm: var(--#{$prefix}border-radius-sm) !default; +$pagination-border-radius-lg: var(--#{$prefix}border-radius-lg) !default; +// scss-docs-end pagination-variables + + +// Placeholders + +// scss-docs-start placeholders +$placeholder-opacity-max: .5 !default; +$placeholder-opacity-min: .2 !default; +// scss-docs-end placeholders + +// Cards + +// scss-docs-start card-variables +$card-spacer-y: $spacer !default; +$card-spacer-x: $spacer !default; +$card-title-spacer-y: $spacer * .5 !default; +$card-title-color: null !default; +$card-subtitle-color: null !default; +$card-border-width: var(--#{$prefix}border-width) !default; +$card-border-color: var(--#{$prefix}border-color-translucent) !default; +$card-border-radius: var(--#{$prefix}border-radius) !default; +$card-box-shadow: null !default; +$card-inner-border-radius: subtract($card-border-radius, $card-border-width) !default; +$card-cap-padding-y: $card-spacer-y * .5 !default; +$card-cap-padding-x: $card-spacer-x !default; +$card-cap-bg: rgba(var(--#{$prefix}body-color-rgb), .03) !default; +$card-cap-color: null !default; +$card-height: null !default; +$card-color: null !default; +$card-bg: var(--#{$prefix}body-bg) !default; +$card-img-overlay-padding: $spacer !default; +$card-group-margin: $grid-gutter-width * .5 !default; +// scss-docs-end card-variables + +// Accordion + +// scss-docs-start accordion-variables +$accordion-padding-y: 1rem !default; +$accordion-padding-x: 1.25rem !default; +$accordion-color: var(--#{$prefix}body-color) !default; +$accordion-bg: var(--#{$prefix}body-bg) !default; +$accordion-border-width: var(--#{$prefix}border-width) !default; +$accordion-border-color: var(--#{$prefix}border-color) !default; +$accordion-border-radius: var(--#{$prefix}border-radius) !default; +$accordion-inner-border-radius: subtract($accordion-border-radius, $accordion-border-width) !default; + +$accordion-body-padding-y: $accordion-padding-y !default; +$accordion-body-padding-x: $accordion-padding-x !default; + +$accordion-button-padding-y: $accordion-padding-y !default; +$accordion-button-padding-x: $accordion-padding-x !default; +$accordion-button-color: var(--#{$prefix}body-color) !default; +$accordion-button-bg: var(--#{$prefix}accordion-bg) !default; +$accordion-transition: $btn-transition, border-radius .15s ease !default; +$accordion-button-active-bg: var(--#{$prefix}primary-bg-subtle) !default; +$accordion-button-active-color: var(--#{$prefix}primary-text-emphasis) !default; + +// fusv-disable +$accordion-button-focus-border-color: $input-focus-border-color !default; // Deprecated in v5.3.3 +// fusv-enable +$accordion-button-focus-box-shadow: $btn-focus-box-shadow !default; + +$accordion-icon-width: 1.25rem !default; +$accordion-icon-color: $body-color !default; +$accordion-icon-active-color: $primary-text-emphasis !default; +$accordion-icon-transition: transform .2s ease-in-out !default; +$accordion-icon-transform: rotate(-180deg) !default; + +$accordion-button-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='#{$accordion-icon-color}' stroke-linecap='round' stroke-linejoin='round'><path d='m2 5 6 6 6-6'/></svg>") !default; +$accordion-button-active-icon: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='#{$accordion-icon-active-color}' stroke-linecap='round' stroke-linejoin='round'><path d='m2 5 6 6 6-6'/></svg>") !default; +// scss-docs-end accordion-variables + +// Tooltips + +// scss-docs-start tooltip-variables +$tooltip-font-size: $font-size-sm !default; +$tooltip-max-width: 200px !default; +$tooltip-color: var(--#{$prefix}body-bg) !default; +$tooltip-bg: var(--#{$prefix}emphasis-color) !default; +$tooltip-border-radius: var(--#{$prefix}border-radius) !default; +$tooltip-opacity: .9 !default; +$tooltip-padding-y: $spacer * .25 !default; +$tooltip-padding-x: $spacer * .5 !default; +$tooltip-margin: null !default; // TODO: remove this in v6 + +$tooltip-arrow-width: .8rem !default; +$tooltip-arrow-height: .4rem !default; +// fusv-disable +$tooltip-arrow-color: null !default; // Deprecated in Bootstrap 5.2.0 for CSS variables +// fusv-enable +// scss-docs-end tooltip-variables + +// Form tooltips must come after regular tooltips +// scss-docs-start tooltip-feedback-variables +$form-feedback-tooltip-padding-y: $tooltip-padding-y !default; +$form-feedback-tooltip-padding-x: $tooltip-padding-x !default; +$form-feedback-tooltip-font-size: $tooltip-font-size !default; +$form-feedback-tooltip-line-height: null !default; +$form-feedback-tooltip-opacity: $tooltip-opacity !default; +$form-feedback-tooltip-border-radius: $tooltip-border-radius !default; +// scss-docs-end tooltip-feedback-variables + + +// Popovers + +// scss-docs-start popover-variables +$popover-font-size: $font-size-sm !default; +$popover-bg: var(--#{$prefix}body-bg) !default; +$popover-max-width: 276px !default; +$popover-border-width: var(--#{$prefix}border-width) !default; +$popover-border-color: var(--#{$prefix}border-color-translucent) !default; +$popover-border-radius: var(--#{$prefix}border-radius-lg) !default; +$popover-inner-border-radius: calc(#{$popover-border-radius} - #{$popover-border-width}) !default; // stylelint-disable-line function-disallowed-list +$popover-box-shadow: var(--#{$prefix}box-shadow) !default; + +$popover-header-font-size: $font-size-base !default; +$popover-header-bg: var(--#{$prefix}secondary-bg) !default; +$popover-header-color: $headings-color !default; +$popover-header-padding-y: .5rem !default; +$popover-header-padding-x: $spacer !default; + +$popover-body-color: var(--#{$prefix}body-color) !default; +$popover-body-padding-y: $spacer !default; +$popover-body-padding-x: $spacer !default; + +$popover-arrow-width: 1rem !default; +$popover-arrow-height: .5rem !default; +// scss-docs-end popover-variables + +// fusv-disable +// Deprecated in Bootstrap 5.2.0 for CSS variables +$popover-arrow-color: $popover-bg !default; +$popover-arrow-outer-color: var(--#{$prefix}border-color-translucent) !default; +// fusv-enable + + +// Toasts + +// scss-docs-start toast-variables +$toast-max-width: 350px !default; +$toast-padding-x: .75rem !default; +$toast-padding-y: .5rem !default; +$toast-font-size: .875rem !default; +$toast-color: null !default; +$toast-background-color: rgba(var(--#{$prefix}body-bg-rgb), .85) !default; +$toast-border-width: var(--#{$prefix}border-width) !default; +$toast-border-color: var(--#{$prefix}border-color-translucent) !default; +$toast-border-radius: var(--#{$prefix}border-radius) !default; +$toast-box-shadow: var(--#{$prefix}box-shadow) !default; +$toast-spacing: $container-padding-x !default; + +$toast-header-color: var(--#{$prefix}secondary-color) !default; +$toast-header-background-color: rgba(var(--#{$prefix}body-bg-rgb), .85) !default; +$toast-header-border-color: $toast-border-color !default; +// scss-docs-end toast-variables + + +// Badges + +// scss-docs-start badge-variables +$badge-font-size: .75em !default; +$badge-font-weight: $font-weight-bold !default; +$badge-color: $white !default; +$badge-padding-y: .35em !default; +$badge-padding-x: .65em !default; +$badge-border-radius: var(--#{$prefix}border-radius) !default; +// scss-docs-end badge-variables + + +// Modals + +// scss-docs-start modal-variables +$modal-inner-padding: $spacer !default; + +$modal-footer-margin-between: .5rem !default; + +$modal-dialog-margin: .5rem !default; +$modal-dialog-margin-y-sm-up: 1.75rem !default; + +$modal-title-line-height: $line-height-base !default; + +$modal-content-color: var(--#{$prefix}body-color) !default; +$modal-content-bg: var(--#{$prefix}body-bg) !default; +$modal-content-border-color: var(--#{$prefix}border-color-translucent) !default; +$modal-content-border-width: var(--#{$prefix}border-width) !default; +$modal-content-border-radius: var(--#{$prefix}border-radius-lg) !default; +$modal-content-inner-border-radius: subtract($modal-content-border-radius, $modal-content-border-width) !default; +$modal-content-box-shadow-xs: var(--#{$prefix}box-shadow-sm) !default; +$modal-content-box-shadow-sm-up: var(--#{$prefix}box-shadow) !default; + +$modal-backdrop-bg: $black !default; +$modal-backdrop-opacity: .5 !default; + +$modal-header-border-color: var(--#{$prefix}border-color) !default; +$modal-header-border-width: $modal-content-border-width !default; +$modal-header-padding-y: $modal-inner-padding !default; +$modal-header-padding-x: $modal-inner-padding !default; +$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility + +$modal-footer-bg: null !default; +$modal-footer-border-color: $modal-header-border-color !default; +$modal-footer-border-width: $modal-header-border-width !default; + +$modal-sm: 300px !default; +$modal-md: 500px !default; +$modal-lg: 800px !default; +$modal-xl: 1140px !default; + +$modal-fade-transform: translate(0, -50px) !default; +$modal-show-transform: none !default; +$modal-transition: transform .3s ease-out !default; +$modal-scale-transform: scale(1.02) !default; +// scss-docs-end modal-variables + + +// Alerts +// +// Define alert colors, border radius, and padding. + +// scss-docs-start alert-variables +$alert-padding-y: $spacer !default; +$alert-padding-x: $spacer !default; +$alert-margin-bottom: 1rem !default; +$alert-border-radius: var(--#{$prefix}border-radius) !default; +$alert-link-font-weight: $font-weight-bold !default; +$alert-border-width: var(--#{$prefix}border-width) !default; +$alert-dismissible-padding-r: $alert-padding-x * 3 !default; // 3x covers width of x plus default padding on either side +// scss-docs-end alert-variables + +// fusv-disable +$alert-bg-scale: -80% !default; // Deprecated in v5.2.0, to be removed in v6 +$alert-border-scale: -70% !default; // Deprecated in v5.2.0, to be removed in v6 +$alert-color-scale: 40% !default; // Deprecated in v5.2.0, to be removed in v6 +// fusv-enable + +// Progress bars + +// scss-docs-start progress-variables +$progress-height: 1rem !default; +$progress-font-size: $font-size-base * .75 !default; +$progress-bg: var(--#{$prefix}secondary-bg) !default; +$progress-border-radius: var(--#{$prefix}border-radius) !default; +$progress-box-shadow: var(--#{$prefix}box-shadow-inset) !default; +$progress-bar-color: $white !default; +$progress-bar-bg: $primary !default; +$progress-bar-animation-timing: 1s linear infinite !default; +$progress-bar-transition: width .6s ease !default; +// scss-docs-end progress-variables + + +// List group + +// scss-docs-start list-group-variables +$list-group-color: var(--#{$prefix}body-color) !default; +$list-group-bg: var(--#{$prefix}body-bg) !default; +$list-group-border-color: var(--#{$prefix}border-color) !default; +$list-group-border-width: var(--#{$prefix}border-width) !default; +$list-group-border-radius: var(--#{$prefix}border-radius) !default; + +$list-group-item-padding-y: $spacer * .5 !default; +$list-group-item-padding-x: $spacer !default; +// fusv-disable +$list-group-item-bg-scale: -80% !default; // Deprecated in v5.3.0 +$list-group-item-color-scale: 40% !default; // Deprecated in v5.3.0 +// fusv-enable + +$list-group-hover-bg: var(--#{$prefix}tertiary-bg) !default; +$list-group-active-color: $component-active-color !default; +$list-group-active-bg: $component-active-bg !default; +$list-group-active-border-color: $list-group-active-bg !default; + +$list-group-disabled-color: var(--#{$prefix}secondary-color) !default; +$list-group-disabled-bg: $list-group-bg !default; + +$list-group-action-color: var(--#{$prefix}secondary-color) !default; +$list-group-action-hover-color: var(--#{$prefix}emphasis-color) !default; + +$list-group-action-active-color: var(--#{$prefix}body-color) !default; +$list-group-action-active-bg: var(--#{$prefix}secondary-bg) !default; +// scss-docs-end list-group-variables + + +// Image thumbnails + +// scss-docs-start thumbnail-variables +$thumbnail-padding: .25rem !default; +$thumbnail-bg: var(--#{$prefix}body-bg) !default; +$thumbnail-border-width: var(--#{$prefix}border-width) !default; +$thumbnail-border-color: var(--#{$prefix}border-color) !default; +$thumbnail-border-radius: var(--#{$prefix}border-radius) !default; +$thumbnail-box-shadow: var(--#{$prefix}box-shadow-sm) !default; +// scss-docs-end thumbnail-variables + + +// Figures + +// scss-docs-start figure-variables +$figure-caption-font-size: $small-font-size !default; +$figure-caption-color: var(--#{$prefix}secondary-color) !default; +// scss-docs-end figure-variables + + +// Breadcrumbs + +// scss-docs-start breadcrumb-variables +$breadcrumb-font-size: null !default; +$breadcrumb-padding-y: 0 !default; +$breadcrumb-padding-x: 0 !default; +$breadcrumb-item-padding-x: .5rem !default; +$breadcrumb-margin-bottom: 1rem !default; +$breadcrumb-bg: null !default; +$breadcrumb-divider-color: var(--#{$prefix}secondary-color) !default; +$breadcrumb-active-color: var(--#{$prefix}secondary-color) !default; +$breadcrumb-divider: quote("/") !default; +$breadcrumb-divider-flipped: $breadcrumb-divider !default; +$breadcrumb-border-radius: null !default; +// scss-docs-end breadcrumb-variables + +// Carousel + +// scss-docs-start carousel-variables +$carousel-control-color: $white !default; +$carousel-control-width: 15% !default; +$carousel-control-opacity: .5 !default; +$carousel-control-hover-opacity: .9 !default; +$carousel-control-transition: opacity .15s ease !default; +$carousel-control-icon-filter: null !default; + +$carousel-indicator-width: 30px !default; +$carousel-indicator-height: 3px !default; +$carousel-indicator-hit-area-height: 10px !default; +$carousel-indicator-spacer: 3px !default; +$carousel-indicator-opacity: .5 !default; +$carousel-indicator-active-bg: $white !default; +$carousel-indicator-active-opacity: 1 !default; +$carousel-indicator-transition: opacity .6s ease !default; + +$carousel-caption-width: 70% !default; +$carousel-caption-color: $white !default; +$carousel-caption-padding-y: 1.25rem !default; +$carousel-caption-spacer: 1.25rem !default; + +$carousel-control-icon-width: 2rem !default; + +$carousel-control-prev-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0'/></svg>") !default; +$carousel-control-next-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$carousel-control-color}'><path d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708'/></svg>") !default; + +$carousel-transition-duration: .6s !default; +$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`) +// scss-docs-end carousel-variables + +// scss-docs-start carousel-dark-variables +$carousel-dark-indicator-active-bg: $black !default; // Deprecated in v5.3.4 +$carousel-dark-caption-color: $black !default; // Deprecated in v5.3.4 +$carousel-dark-control-icon-filter: invert(1) grayscale(100) !default; // Deprecated in v5.3.4 +// scss-docs-end carousel-dark-variables + + +// Spinners + +// scss-docs-start spinner-variables +$spinner-width: 2rem !default; +$spinner-height: $spinner-width !default; +$spinner-vertical-align: -.125em !default; +$spinner-border-width: .25em !default; +$spinner-animation-speed: .75s !default; + +$spinner-width-sm: 1rem !default; +$spinner-height-sm: $spinner-width-sm !default; +$spinner-border-width-sm: .2em !default; +// scss-docs-end spinner-variables + + +// Close + +// scss-docs-start close-variables +$btn-close-width: 1em !default; +$btn-close-height: $btn-close-width !default; +$btn-close-padding-x: .25em !default; +$btn-close-padding-y: $btn-close-padding-x !default; +$btn-close-color: $black !default; +$btn-close-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='#{$btn-close-color}'><path d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414'/></svg>") !default; +$btn-close-focus-shadow: $focus-ring-box-shadow !default; +$btn-close-opacity: .5 !default; +$btn-close-hover-opacity: .75 !default; +$btn-close-focus-opacity: 1 !default; +$btn-close-disabled-opacity: .25 !default; +$btn-close-filter: null !default; +$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%) !default; // Deprecated in v5.3.4 +// scss-docs-end close-variables + + +// Offcanvas + +// scss-docs-start offcanvas-variables +$offcanvas-padding-y: $modal-inner-padding !default; +$offcanvas-padding-x: $modal-inner-padding !default; +$offcanvas-horizontal-width: 400px !default; +$offcanvas-vertical-height: 30vh !default; +$offcanvas-transition-duration: .3s !default; +$offcanvas-border-color: $modal-content-border-color !default; +$offcanvas-border-width: $modal-content-border-width !default; +$offcanvas-title-line-height: $modal-title-line-height !default; +$offcanvas-bg-color: var(--#{$prefix}body-bg) !default; +$offcanvas-color: var(--#{$prefix}body-color) !default; +$offcanvas-box-shadow: $modal-content-box-shadow-xs !default; +$offcanvas-backdrop-bg: $modal-backdrop-bg !default; +$offcanvas-backdrop-opacity: $modal-backdrop-opacity !default; +// scss-docs-end offcanvas-variables + +// Code + +$code-font-size: $small-font-size !default; +$code-color: $pink !default; + +$kbd-padding-y: .1875rem !default; +$kbd-padding-x: .375rem !default; +$kbd-font-size: $code-font-size !default; +$kbd-color: var(--#{$prefix}body-bg) !default; +$kbd-bg: var(--#{$prefix}body-color) !default; +$nested-kbd-font-weight: null !default; // Deprecated in v5.2.0, removing in v6 + +$pre-color: null !default; + +@import "variables-dark"; // TODO: can be removed safely in v6, only here to avoid breaking changes in v5.3 diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-grid.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-grid.scss new file mode 100644 index 0000000..52bd577 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-grid.scss @@ -0,0 +1,62 @@ +@import "mixins/banner"; +@include bsBanner(Grid); + +$include-column-box-sizing: true !default; + +@import "functions"; +@import "variables"; +@import "variables-dark"; +@import "maps"; + +@import "mixins/breakpoints"; +@import "mixins/container"; +@import "mixins/grid"; +@import "mixins/utilities"; + +@import "vendor/rfs"; + +@import "containers"; +@import "grid"; + +@import "utilities"; +// Only use the utilities we need +// stylelint-disable-next-line scss/dollar-variable-default +$utilities: map-get-multiple( + $utilities, + ( + "display", + "order", + "flex", + "flex-direction", + "flex-grow", + "flex-shrink", + "flex-wrap", + "justify-content", + "align-items", + "align-content", + "align-self", + "margin", + "margin-x", + "margin-y", + "margin-top", + "margin-end", + "margin-bottom", + "margin-start", + "negative-margin", + "negative-margin-x", + "negative-margin-y", + "negative-margin-top", + "negative-margin-end", + "negative-margin-bottom", + "negative-margin-start", + "padding", + "padding-x", + "padding-y", + "padding-top", + "padding-end", + "padding-bottom", + "padding-start", + ) +); + +@import "utilities/api"; diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-reboot.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-reboot.scss new file mode 100644 index 0000000..5b69b95 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-reboot.scss @@ -0,0 +1,10 @@ +@import "mixins/banner"; +@include bsBanner(Reboot); + +@import "functions"; +@import "variables"; +@import "variables-dark"; +@import "maps"; +@import "mixins"; +@import "root"; +@import "reboot"; diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-utilities.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-utilities.scss new file mode 100644 index 0000000..99c4a35 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap-utilities.scss @@ -0,0 +1,19 @@ +@import "mixins/banner"; +@include bsBanner(Utilities); + +// Configuration +@import "functions"; +@import "variables"; +@import "variables-dark"; +@import "maps"; +@import "mixins"; +@import "utilities"; + +// Layout & components +@import "root"; + +// Helpers +@import "helpers"; + +// Utilities +@import "utilities/api"; diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap.scss new file mode 100644 index 0000000..449d704 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/bootstrap.scss @@ -0,0 +1,52 @@ +@import "mixins/banner"; +@include bsBanner(""); + + +// scss-docs-start import-stack +// Configuration +@import "functions"; +@import "variables"; +@import "variables-dark"; +@import "maps"; +@import "mixins"; +@import "utilities"; + +// Layout & components +@import "root"; +@import "reboot"; +@import "type"; +@import "images"; +@import "containers"; +@import "grid"; +@import "tables"; +@import "forms"; +@import "buttons"; +@import "transitions"; +@import "dropdown"; +@import "button-group"; +@import "nav"; +@import "navbar"; +@import "card"; +@import "accordion"; +@import "breadcrumb"; +@import "pagination"; +@import "badge"; +@import "alert"; +@import "progress"; +@import "list-group"; +@import "close"; +@import "toasts"; +@import "modal"; +@import "tooltip"; +@import "popover"; +@import "carousel"; +@import "spinners"; +@import "offcanvas"; +@import "placeholders"; + +// Helpers +@import "helpers"; + +// Utilities +@import "utilities/api"; +// scss-docs-end import-stack diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_floating-labels.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_floating-labels.scss new file mode 100644 index 0000000..38df115 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_floating-labels.scss @@ -0,0 +1,97 @@ +.form-floating { + position: relative; + + > .form-control, + > .form-control-plaintext, + > .form-select { + height: $form-floating-height; + min-height: $form-floating-height; + line-height: $form-floating-line-height; + } + + > label { + position: absolute; + top: 0; + left: 0; + z-index: 2; + max-width: 100%; + height: 100%; // allow textareas + padding: $form-floating-padding-y $form-floating-padding-x; + overflow: hidden; + color: rgba(var(--#{$prefix}body-color-rgb), #{$form-floating-label-opacity}); + text-align: start; + text-overflow: ellipsis; + white-space: nowrap; + pointer-events: none; + border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model + transform-origin: 0 0; + @include transition($form-floating-transition); + } + + > .form-control, + > .form-control-plaintext { + padding: $form-floating-padding-y $form-floating-padding-x; + + &::placeholder { + color: transparent; + } + + &:focus, + &:not(:placeholder-shown) { + padding-top: $form-floating-input-padding-t; + padding-bottom: $form-floating-input-padding-b; + } + // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped + &:-webkit-autofill { + padding-top: $form-floating-input-padding-t; + padding-bottom: $form-floating-input-padding-b; + } + } + + > .form-select { + padding-top: $form-floating-input-padding-t; + padding-bottom: $form-floating-input-padding-b; + padding-left: $form-floating-padding-x; + } + + > .form-control:focus, + > .form-control:not(:placeholder-shown), + > .form-control-plaintext, + > .form-select { + ~ label { + transform: $form-floating-label-transform; + } + } + // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped + > .form-control:-webkit-autofill { + ~ label { + transform: $form-floating-label-transform; + } + } + > textarea:focus, + > textarea:not(:placeholder-shown) { + ~ label::after { + position: absolute; + inset: $form-floating-padding-y ($form-floating-padding-x * .5); + z-index: -1; + height: $form-floating-label-height; + content: ""; + background-color: $input-bg; + @include border-radius($input-border-radius); + } + } + > textarea:disabled ~ label::after { + background-color: $input-disabled-bg; + } + + > .form-control-plaintext { + ~ label { + border-width: $input-border-width 0; // Required to properly position label text - as explained above + } + } + + > :disabled ~ label, + > .form-control:disabled ~ label { // Required for `.form-control`s because of specificity + color: $form-floating-label-disabled-color; + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-check.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-check.scss new file mode 100644 index 0000000..8a1b639 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-check.scss @@ -0,0 +1,189 @@ +// +// Check/radio +// + +.form-check { + display: block; + min-height: $form-check-min-height; + padding-left: $form-check-padding-start; + margin-bottom: $form-check-margin-bottom; + + .form-check-input { + float: left; + margin-left: $form-check-padding-start * -1; + } +} + +.form-check-reverse { + padding-right: $form-check-padding-start; + padding-left: 0; + text-align: right; + + .form-check-input { + float: right; + margin-right: $form-check-padding-start * -1; + margin-left: 0; + } +} + +.form-check-input { + --#{$prefix}form-check-bg: #{$form-check-input-bg}; + + flex-shrink: 0; + width: $form-check-input-width; + height: $form-check-input-width; + margin-top: ($line-height-base - $form-check-input-width) * .5; // line-height minus check height + vertical-align: top; + appearance: none; + background-color: var(--#{$prefix}form-check-bg); + background-image: var(--#{$prefix}form-check-bg-image); + background-repeat: no-repeat; + background-position: center; + background-size: contain; + border: $form-check-input-border; + print-color-adjust: exact; // Keep themed appearance for print + @include transition($form-check-transition); + + &[type="checkbox"] { + @include border-radius($form-check-input-border-radius); + } + + &[type="radio"] { + // stylelint-disable-next-line property-disallowed-list + border-radius: $form-check-radio-border-radius; + } + + &:active { + filter: $form-check-input-active-filter; + } + + &:focus { + border-color: $form-check-input-focus-border; + outline: 0; + box-shadow: $form-check-input-focus-box-shadow; + } + + &:checked { + background-color: $form-check-input-checked-bg-color; + border-color: $form-check-input-checked-border-color; + + &[type="checkbox"] { + @if $enable-gradients { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-checked-bg-image)}, var(--#{$prefix}gradient); + } @else { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-checked-bg-image)}; + } + } + + &[type="radio"] { + @if $enable-gradients { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-radio-checked-bg-image)}, var(--#{$prefix}gradient); + } @else { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-radio-checked-bg-image)}; + } + } + } + + &[type="checkbox"]:indeterminate { + background-color: $form-check-input-indeterminate-bg-color; + border-color: $form-check-input-indeterminate-border-color; + + @if $enable-gradients { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-indeterminate-bg-image)}, var(--#{$prefix}gradient); + } @else { + --#{$prefix}form-check-bg-image: #{escape-svg($form-check-input-indeterminate-bg-image)}; + } + } + + &:disabled { + pointer-events: none; + filter: none; + opacity: $form-check-input-disabled-opacity; + } + + // Use disabled attribute in addition of :disabled pseudo-class + // See: https://github.com/twbs/bootstrap/issues/28247 + &[disabled], + &:disabled { + ~ .form-check-label { + cursor: default; + opacity: $form-check-label-disabled-opacity; + } + } +} + +.form-check-label { + color: $form-check-label-color; + cursor: $form-check-label-cursor; +} + +// +// Switch +// + +.form-switch { + padding-left: $form-switch-padding-start; + + .form-check-input { + --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image)}; + + width: $form-switch-width; + margin-left: $form-switch-padding-start * -1; + background-image: var(--#{$prefix}form-switch-bg); + background-position: left center; + @include border-radius($form-switch-border-radius, 0); + @include transition($form-switch-transition); + + &:focus { + --#{$prefix}form-switch-bg: #{escape-svg($form-switch-focus-bg-image)}; + } + + &:checked { + background-position: $form-switch-checked-bg-position; + + @if $enable-gradients { + --#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)}, var(--#{$prefix}gradient); + } @else { + --#{$prefix}form-switch-bg: #{escape-svg($form-switch-checked-bg-image)}; + } + } + } + + &.form-check-reverse { + padding-right: $form-switch-padding-start; + padding-left: 0; + + .form-check-input { + margin-right: $form-switch-padding-start * -1; + margin-left: 0; + } + } +} + +.form-check-inline { + display: inline-block; + margin-right: $form-check-inline-margin-end; +} + +.btn-check { + position: absolute; + clip: rect(0, 0, 0, 0); + pointer-events: none; + + &[disabled], + &:disabled { + + .btn { + pointer-events: none; + filter: none; + opacity: $form-check-btn-check-disabled-opacity; + } + } +} + +@if $enable-dark-mode { + @include color-mode(dark) { + .form-switch .form-check-input:not(:checked):not(:focus) { + --#{$prefix}form-switch-bg: #{escape-svg($form-switch-bg-image-dark)}; + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-control.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-control.scss new file mode 100644 index 0000000..67ae5f4 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-control.scss @@ -0,0 +1,214 @@ +// +// General form controls (plus a few specific high-level interventions) +// + +.form-control { + display: block; + width: 100%; + padding: $input-padding-y $input-padding-x; + font-family: $input-font-family; + @include font-size($input-font-size); + font-weight: $input-font-weight; + line-height: $input-line-height; + color: $input-color; + appearance: none; // Fix appearance for date inputs in Safari + background-color: $input-bg; + background-clip: padding-box; + border: $input-border-width solid $input-border-color; + + // Note: This has no effect on <select>s in some browsers, due to the limited stylability of `<select>`s in CSS. + @include border-radius($input-border-radius, 0); + + @include box-shadow($input-box-shadow); + @include transition($input-transition); + + &[type="file"] { + overflow: hidden; // prevent pseudo element button overlap + + &:not(:disabled):not([readonly]) { + cursor: pointer; + } + } + + // Customize the `:focus` state to imitate native WebKit styles. + &:focus { + color: $input-focus-color; + background-color: $input-focus-bg; + border-color: $input-focus-border-color; + outline: 0; + @if $enable-shadows { + @include box-shadow($input-box-shadow, $input-focus-box-shadow); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: $input-focus-box-shadow; + } + } + + &::-webkit-date-and-time-value { + // On Android Chrome, form-control's "width: 100%" makes the input width too small + // Tested under Android 11 / Chrome 89, Android 12 / Chrome 100, Android 13 / Chrome 109 + // + // On iOS Safari, form-control's "appearance: none" + "width: 100%" makes the input width too small + // Tested under iOS 16.2 / Safari 16.2 + min-width: 85px; // Seems to be a good minimum safe width + + // Add some height to date inputs on iOS + // https://github.com/twbs/bootstrap/issues/23307 + // TODO: we can remove this workaround once https://bugs.webkit.org/show_bug.cgi?id=198959 is resolved + // Multiply line-height by 1em if it has no unit + height: if(unit($input-line-height) == "", $input-line-height * 1em, $input-line-height); + + // Android Chrome type="date" is taller than the other inputs + // because of "margin: 1px 24px 1px 4px" inside the shadow DOM + // Tested under Android 11 / Chrome 89, Android 12 / Chrome 100, Android 13 / Chrome 109 + margin: 0; + } + + // Prevent excessive date input height in Webkit + // https://github.com/twbs/bootstrap/issues/34433 + &::-webkit-datetime-edit { + display: block; + padding: 0; + } + + // Placeholder + &::placeholder { + color: $input-placeholder-color; + // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526. + opacity: 1; + } + + // Disabled inputs + // + // HTML5 says that controls under a fieldset > legend:first-child won't be + // disabled if the fieldset is disabled. Due to implementation difficulty, we + // don't honor that edge case; we style them as disabled anyway. + &:disabled { + color: $input-disabled-color; + background-color: $input-disabled-bg; + border-color: $input-disabled-border-color; + // iOS fix for unreadable disabled content; see https://github.com/twbs/bootstrap/issues/11655. + opacity: 1; + } + + // File input buttons theming + &::file-selector-button { + padding: $input-padding-y $input-padding-x; + margin: (-$input-padding-y) (-$input-padding-x); + margin-inline-end: $input-padding-x; + color: $form-file-button-color; + @include gradient-bg($form-file-button-bg); + pointer-events: none; + border-color: inherit; + border-style: solid; + border-width: 0; + border-inline-end-width: $input-border-width; + border-radius: 0; // stylelint-disable-line property-disallowed-list + @include transition($btn-transition); + } + + &:hover:not(:disabled):not([readonly])::file-selector-button { + background-color: $form-file-button-hover-bg; + } +} + +// Readonly controls as plain text +// +// Apply class to a readonly input to make it appear like regular plain +// text (without any border, background color, focus indicator) + +.form-control-plaintext { + display: block; + width: 100%; + padding: $input-padding-y 0; + margin-bottom: 0; // match inputs if this class comes on inputs with default margins + line-height: $input-line-height; + color: $input-plaintext-color; + background-color: transparent; + border: solid transparent; + border-width: $input-border-width 0; + + &:focus { + outline: 0; + } + + &.form-control-sm, + &.form-control-lg { + padding-right: 0; + padding-left: 0; + } +} + +// Form control sizing +// +// Build on `.form-control` with modifier classes to decrease or increase the +// height and font-size of form controls. +// +// Repeated in `_input_group.scss` to avoid Sass extend issues. + +.form-control-sm { + min-height: $input-height-sm; + padding: $input-padding-y-sm $input-padding-x-sm; + @include font-size($input-font-size-sm); + @include border-radius($input-border-radius-sm); + + &::file-selector-button { + padding: $input-padding-y-sm $input-padding-x-sm; + margin: (-$input-padding-y-sm) (-$input-padding-x-sm); + margin-inline-end: $input-padding-x-sm; + } +} + +.form-control-lg { + min-height: $input-height-lg; + padding: $input-padding-y-lg $input-padding-x-lg; + @include font-size($input-font-size-lg); + @include border-radius($input-border-radius-lg); + + &::file-selector-button { + padding: $input-padding-y-lg $input-padding-x-lg; + margin: (-$input-padding-y-lg) (-$input-padding-x-lg); + margin-inline-end: $input-padding-x-lg; + } +} + +// Make sure textareas don't shrink too much when resized +// https://github.com/twbs/bootstrap/pull/29124 +// stylelint-disable selector-no-qualifying-type +textarea { + &.form-control { + min-height: $input-height; + } + + &.form-control-sm { + min-height: $input-height-sm; + } + + &.form-control-lg { + min-height: $input-height-lg; + } +} +// stylelint-enable selector-no-qualifying-type + +.form-control-color { + width: $form-color-width; + height: $input-height; + padding: $input-padding-y; + + &:not(:disabled):not([readonly]) { + cursor: pointer; + } + + &::-moz-color-swatch { + border: 0 !important; // stylelint-disable-line declaration-no-important + @include border-radius($input-border-radius); + } + + &::-webkit-color-swatch { + border: 0 !important; // stylelint-disable-line declaration-no-important + @include border-radius($input-border-radius); + } + + &.form-control-sm { height: $input-height-sm; } + &.form-control-lg { height: $input-height-lg; } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-range.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-range.scss new file mode 100644 index 0000000..4732213 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-range.scss @@ -0,0 +1,91 @@ +// Range +// +// Style range inputs the same across browsers. Vendor-specific rules for pseudo +// elements cannot be mixed. As such, there are no shared styles for focus or +// active states on prefixed selectors. + +.form-range { + width: 100%; + height: add($form-range-thumb-height, $form-range-thumb-focus-box-shadow-width * 2); + padding: 0; // Need to reset padding + appearance: none; + background-color: transparent; + + &:focus { + outline: 0; + + // Pseudo-elements must be split across multiple rulesets to have an effect. + // No box-shadow() mixin for focus accessibility. + &::-webkit-slider-thumb { box-shadow: $form-range-thumb-focus-box-shadow; } + &::-moz-range-thumb { box-shadow: $form-range-thumb-focus-box-shadow; } + } + + &::-moz-focus-outer { + border: 0; + } + + &::-webkit-slider-thumb { + width: $form-range-thumb-width; + height: $form-range-thumb-height; + margin-top: ($form-range-track-height - $form-range-thumb-height) * .5; // Webkit specific + appearance: none; + @include gradient-bg($form-range-thumb-bg); + border: $form-range-thumb-border; + @include border-radius($form-range-thumb-border-radius); + @include box-shadow($form-range-thumb-box-shadow); + @include transition($form-range-thumb-transition); + + &:active { + @include gradient-bg($form-range-thumb-active-bg); + } + } + + &::-webkit-slider-runnable-track { + width: $form-range-track-width; + height: $form-range-track-height; + color: transparent; // Why? + cursor: $form-range-track-cursor; + background-color: $form-range-track-bg; + border-color: transparent; + @include border-radius($form-range-track-border-radius); + @include box-shadow($form-range-track-box-shadow); + } + + &::-moz-range-thumb { + width: $form-range-thumb-width; + height: $form-range-thumb-height; + appearance: none; + @include gradient-bg($form-range-thumb-bg); + border: $form-range-thumb-border; + @include border-radius($form-range-thumb-border-radius); + @include box-shadow($form-range-thumb-box-shadow); + @include transition($form-range-thumb-transition); + + &:active { + @include gradient-bg($form-range-thumb-active-bg); + } + } + + &::-moz-range-track { + width: $form-range-track-width; + height: $form-range-track-height; + color: transparent; + cursor: $form-range-track-cursor; + background-color: $form-range-track-bg; + border-color: transparent; // Firefox specific? + @include border-radius($form-range-track-border-radius); + @include box-shadow($form-range-track-box-shadow); + } + + &:disabled { + pointer-events: none; + + &::-webkit-slider-thumb { + background-color: $form-range-thumb-disabled-bg; + } + + &::-moz-range-thumb { + background-color: $form-range-thumb-disabled-bg; + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-select.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-select.scss new file mode 100644 index 0000000..69ace52 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-select.scss @@ -0,0 +1,80 @@ +// Select +// +// Replaces the browser default select with a custom one, mostly pulled from +// https://primer.github.io/. + +.form-select { + --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator)}; + + display: block; + width: 100%; + padding: $form-select-padding-y $form-select-indicator-padding $form-select-padding-y $form-select-padding-x; + font-family: $form-select-font-family; + @include font-size($form-select-font-size); + font-weight: $form-select-font-weight; + line-height: $form-select-line-height; + color: $form-select-color; + appearance: none; + background-color: $form-select-bg; + background-image: var(--#{$prefix}form-select-bg-img), var(--#{$prefix}form-select-bg-icon, none); + background-repeat: no-repeat; + background-position: $form-select-bg-position; + background-size: $form-select-bg-size; + border: $form-select-border-width solid $form-select-border-color; + @include border-radius($form-select-border-radius, 0); + @include box-shadow($form-select-box-shadow); + @include transition($form-select-transition); + + &:focus { + border-color: $form-select-focus-border-color; + outline: 0; + @if $enable-shadows { + @include box-shadow($form-select-box-shadow, $form-select-focus-box-shadow); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: $form-select-focus-box-shadow; + } + } + + &[multiple], + &[size]:not([size="1"]) { + padding-right: $form-select-padding-x; + background-image: none; + } + + &:disabled { + color: $form-select-disabled-color; + background-color: $form-select-disabled-bg; + border-color: $form-select-disabled-border-color; + } + + // Remove outline from select box in FF + &:-moz-focusring { + color: transparent; + text-shadow: 0 0 0 $form-select-color; + } +} + +.form-select-sm { + padding-top: $form-select-padding-y-sm; + padding-bottom: $form-select-padding-y-sm; + padding-left: $form-select-padding-x-sm; + @include font-size($form-select-font-size-sm); + @include border-radius($form-select-border-radius-sm); +} + +.form-select-lg { + padding-top: $form-select-padding-y-lg; + padding-bottom: $form-select-padding-y-lg; + padding-left: $form-select-padding-x-lg; + @include font-size($form-select-font-size-lg); + @include border-radius($form-select-border-radius-lg); +} + +@if $enable-dark-mode { + @include color-mode(dark) { + .form-select { + --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator-dark)}; + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-text.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-text.scss new file mode 100644 index 0000000..f080d1a --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_form-text.scss @@ -0,0 +1,11 @@ +// +// Form text +// + +.form-text { + margin-top: $form-text-margin-top; + @include font-size($form-text-font-size); + font-style: $form-text-font-style; + font-weight: $form-text-font-weight; + color: $form-text-color; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_input-group.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_input-group.scss new file mode 100644 index 0000000..8078ebb --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_input-group.scss @@ -0,0 +1,132 @@ +// +// Base styles +// + +.input-group { + position: relative; + display: flex; + flex-wrap: wrap; // For form validation feedback + align-items: stretch; + width: 100%; + + > .form-control, + > .form-select, + > .form-floating { + position: relative; // For focus state's z-index + flex: 1 1 auto; + width: 1%; + min-width: 0; // https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size + } + + // Bring the "active" form control to the top of surrounding elements + > .form-control:focus, + > .form-select:focus, + > .form-floating:focus-within { + z-index: 5; + } + + // Ensure buttons are always above inputs for more visually pleasing borders. + // This isn't needed for `.input-group-text` since it shares the same border-color + // as our inputs. + .btn { + position: relative; + z-index: 2; + + &:focus { + z-index: 5; + } + } +} + + +// Textual addons +// +// Serves as a catch-all element for any text or radio/checkbox input you wish +// to prepend or append to an input. + +.input-group-text { + display: flex; + align-items: center; + padding: $input-group-addon-padding-y $input-group-addon-padding-x; + @include font-size($input-font-size); // Match inputs + font-weight: $input-group-addon-font-weight; + line-height: $input-line-height; + color: $input-group-addon-color; + text-align: center; + white-space: nowrap; + background-color: $input-group-addon-bg; + border: $input-border-width solid $input-group-addon-border-color; + @include border-radius($input-border-radius); +} + + +// Sizing +// +// Remix the default form control sizing classes into new ones for easier +// manipulation. + +.input-group-lg > .form-control, +.input-group-lg > .form-select, +.input-group-lg > .input-group-text, +.input-group-lg > .btn { + padding: $input-padding-y-lg $input-padding-x-lg; + @include font-size($input-font-size-lg); + @include border-radius($input-border-radius-lg); +} + +.input-group-sm > .form-control, +.input-group-sm > .form-select, +.input-group-sm > .input-group-text, +.input-group-sm > .btn { + padding: $input-padding-y-sm $input-padding-x-sm; + @include font-size($input-font-size-sm); + @include border-radius($input-border-radius-sm); +} + +.input-group-lg > .form-select, +.input-group-sm > .form-select { + padding-right: $form-select-padding-x + $form-select-indicator-padding; +} + + +// Rounded corners +// +// These rulesets must come after the sizing ones to properly override sm and lg +// border-radius values when extending. They're more specific than we'd like +// with the `.input-group >` part, but without it, we cannot override the sizing. + +// stylelint-disable-next-line no-duplicate-selectors +.input-group { + &:not(.has-validation) { + > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), + > .dropdown-toggle:nth-last-child(n + 3), + > .form-floating:not(:last-child) > .form-control, + > .form-floating:not(:last-child) > .form-select { + @include border-end-radius(0); + } + } + + &.has-validation { + > :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating), + > .dropdown-toggle:nth-last-child(n + 4), + > .form-floating:nth-last-child(n + 3) > .form-control, + > .form-floating:nth-last-child(n + 3) > .form-select { + @include border-end-radius(0); + } + } + + $validation-messages: ""; + @each $state in map-keys($form-validation-states) { + $validation-messages: $validation-messages + ":not(." + unquote($state) + "-tooltip)" + ":not(." + unquote($state) + "-feedback)"; + } + + > :not(:first-child):not(.dropdown-menu)#{$validation-messages} { + margin-left: calc(-1 * #{$input-border-width}); // stylelint-disable-line function-disallowed-list + @include border-start-radius(0); + } + + > .form-floating:not(:first-child) > .form-control, + > .form-floating:not(:first-child) > .form-select { + @include border-start-radius(0); + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_labels.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_labels.scss new file mode 100644 index 0000000..39ecafc --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_labels.scss @@ -0,0 +1,36 @@ +// +// Labels +// + +.form-label { + margin-bottom: $form-label-margin-bottom; + @include font-size($form-label-font-size); + font-style: $form-label-font-style; + font-weight: $form-label-font-weight; + color: $form-label-color; +} + +// For use with horizontal and inline forms, when you need the label (or legend) +// text to align with the form controls. +.col-form-label { + padding-top: add($input-padding-y, $input-border-width); + padding-bottom: add($input-padding-y, $input-border-width); + margin-bottom: 0; // Override the `<legend>` default + @include font-size(inherit); // Override the `<legend>` default + font-style: $form-label-font-style; + font-weight: $form-label-font-weight; + line-height: $input-line-height; + color: $form-label-color; +} + +.col-form-label-lg { + padding-top: add($input-padding-y-lg, $input-border-width); + padding-bottom: add($input-padding-y-lg, $input-border-width); + @include font-size($input-font-size-lg); +} + +.col-form-label-sm { + padding-top: add($input-padding-y-sm, $input-border-width); + padding-bottom: add($input-padding-y-sm, $input-border-width); + @include font-size($input-font-size-sm); +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_validation.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_validation.scss new file mode 100644 index 0000000..c48123a --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/forms/_validation.scss @@ -0,0 +1,12 @@ +// Form validation +// +// Provide feedback to users when form field values are valid or invalid. Works +// primarily for client-side validation via scoped `:invalid` and `:valid` +// pseudo-classes but also includes `.is-invalid` and `.is-valid` classes for +// server-side validation. + +// scss-docs-start form-validation-states-loop +@each $state, $data in $form-validation-states { + @include form-validation-state($state, $data...); +} +// scss-docs-end form-validation-states-loop diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_clearfix.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_clearfix.scss new file mode 100644 index 0000000..e92522a --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_clearfix.scss @@ -0,0 +1,3 @@ +.clearfix { + @include clearfix(); +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_color-bg.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_color-bg.scss new file mode 100644 index 0000000..1a3a4cf --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_color-bg.scss @@ -0,0 +1,7 @@ +// All-caps `RGBA()` function used because of this Sass bug: https://github.com/sass/node-sass/issues/2251 +@each $color, $value in $theme-colors { + .text-bg-#{$color} { + color: color-contrast($value) if($enable-important-utilities, !important, null); + background-color: RGBA(var(--#{$prefix}#{$color}-rgb), var(--#{$prefix}bg-opacity, 1)) if($enable-important-utilities, !important, null); + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_colored-links.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_colored-links.scss new file mode 100644 index 0000000..5f86857 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_colored-links.scss @@ -0,0 +1,30 @@ +// All-caps `RGBA()` function used because of this Sass bug: https://github.com/sass/node-sass/issues/2251 +@each $color, $value in $theme-colors { + .link-#{$color} { + color: RGBA(var(--#{$prefix}#{$color}-rgb), var(--#{$prefix}link-opacity, 1)) if($enable-important-utilities, !important, null); + text-decoration-color: RGBA(var(--#{$prefix}#{$color}-rgb), var(--#{$prefix}link-underline-opacity, 1)) if($enable-important-utilities, !important, null); + + @if $link-shade-percentage != 0 { + &:hover, + &:focus { + $hover-color: if(color-contrast($value) == $color-contrast-light, shade-color($value, $link-shade-percentage), tint-color($value, $link-shade-percentage)); + color: RGBA(#{to-rgb($hover-color)}, var(--#{$prefix}link-opacity, 1)) if($enable-important-utilities, !important, null); + text-decoration-color: RGBA(to-rgb($hover-color), var(--#{$prefix}link-underline-opacity, 1)) if($enable-important-utilities, !important, null); + } + } + } +} + +// One-off special link helper as a bridge until v6 +.link-body-emphasis { + color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-opacity, 1)) if($enable-important-utilities, !important, null); + text-decoration-color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-underline-opacity, 1)) if($enable-important-utilities, !important, null); + + @if $link-shade-percentage != 0 { + &:hover, + &:focus { + color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-opacity, .75)) if($enable-important-utilities, !important, null); + text-decoration-color: RGBA(var(--#{$prefix}emphasis-color-rgb), var(--#{$prefix}link-underline-opacity, .75)) if($enable-important-utilities, !important, null); + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_focus-ring.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_focus-ring.scss new file mode 100644 index 0000000..26508a8 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_focus-ring.scss @@ -0,0 +1,5 @@ +.focus-ring:focus { + outline: 0; + // By default, there is no `--bs-focus-ring-x`, `--bs-focus-ring-y`, or `--bs-focus-ring-blur`, but we provide CSS variables with fallbacks to initial `0` values + box-shadow: var(--#{$prefix}focus-ring-x, 0) var(--#{$prefix}focus-ring-y, 0) var(--#{$prefix}focus-ring-blur, 0) var(--#{$prefix}focus-ring-width) var(--#{$prefix}focus-ring-color); +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_icon-link.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_icon-link.scss new file mode 100644 index 0000000..3f8bcb3 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_icon-link.scss @@ -0,0 +1,25 @@ +.icon-link { + display: inline-flex; + gap: $icon-link-gap; + align-items: center; + text-decoration-color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, .5)); + text-underline-offset: $icon-link-underline-offset; + backface-visibility: hidden; + + > .bi { + flex-shrink: 0; + width: $icon-link-icon-size; + height: $icon-link-icon-size; + fill: currentcolor; + @include transition($icon-link-icon-transition); + } +} + +.icon-link-hover { + &:hover, + &:focus-visible { + > .bi { + transform: var(--#{$prefix}icon-link-transform, $icon-link-icon-transform); + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_position.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_position.scss new file mode 100644 index 0000000..59103d9 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_position.scss @@ -0,0 +1,36 @@ +// Shorthand + +.fixed-top { + position: fixed; + top: 0; + right: 0; + left: 0; + z-index: $zindex-fixed; +} + +.fixed-bottom { + position: fixed; + right: 0; + bottom: 0; + left: 0; + z-index: $zindex-fixed; +} + +// Responsive sticky top and bottom +@each $breakpoint in map-keys($grid-breakpoints) { + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + .sticky#{$infix}-top { + position: sticky; + top: 0; + z-index: $zindex-sticky; + } + + .sticky#{$infix}-bottom { + position: sticky; + bottom: 0; + z-index: $zindex-sticky; + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_ratio.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_ratio.scss new file mode 100644 index 0000000..b6a7654 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_ratio.scss @@ -0,0 +1,26 @@ +// Credit: Nicolas Gallagher and SUIT CSS. + +.ratio { + position: relative; + width: 100%; + + &::before { + display: block; + padding-top: var(--#{$prefix}aspect-ratio); + content: ""; + } + + > * { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } +} + +@each $key, $ratio in $aspect-ratios { + .ratio-#{$key} { + --#{$prefix}aspect-ratio: #{$ratio}; + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_stacks.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_stacks.scss new file mode 100644 index 0000000..6cd237a --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_stacks.scss @@ -0,0 +1,15 @@ +// scss-docs-start stacks +.hstack { + display: flex; + flex-direction: row; + align-items: center; + align-self: stretch; +} + +.vstack { + display: flex; + flex: 1 1 auto; + flex-direction: column; + align-self: stretch; +} +// scss-docs-end stacks diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_stretched-link.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_stretched-link.scss new file mode 100644 index 0000000..71a1c75 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_stretched-link.scss @@ -0,0 +1,15 @@ +// +// Stretched link +// + +.stretched-link { + &::#{$stretched-link-pseudo-element} { + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: $stretched-link-z-index; + content: ""; + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_text-truncation.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_text-truncation.scss new file mode 100644 index 0000000..6421dac --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_text-truncation.scss @@ -0,0 +1,7 @@ +// +// Text truncation +// + +.text-truncate { + @include text-truncate(); +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_visually-hidden.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_visually-hidden.scss new file mode 100644 index 0000000..4760ff0 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_visually-hidden.scss @@ -0,0 +1,8 @@ +// +// Visually hidden +// + +.visually-hidden, +.visually-hidden-focusable:not(:focus):not(:focus-within) { + @include visually-hidden(); +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_vr.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_vr.scss new file mode 100644 index 0000000..b6f9d42 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/helpers/_vr.scss @@ -0,0 +1,8 @@ +.vr { + display: inline-block; + align-self: stretch; + width: $vr-border-width; + min-height: 1em; + background-color: currentcolor; + opacity: $hr-opacity; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_alert.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_alert.scss new file mode 100644 index 0000000..fb524af --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_alert.scss @@ -0,0 +1,18 @@ +@include deprecate("`alert-variant()`", "v5.3.0", "v6.0.0"); + +// scss-docs-start alert-variant-mixin +@mixin alert-variant($background, $border, $color) { + --#{$prefix}alert-color: #{$color}; + --#{$prefix}alert-bg: #{$background}; + --#{$prefix}alert-border-color: #{$border}; + --#{$prefix}alert-link-color: #{shade-color($color, 20%)}; + + @if $enable-gradients { + background-image: var(--#{$prefix}gradient); + } + + .alert-link { + color: var(--#{$prefix}alert-link-color); + } +} +// scss-docs-end alert-variant-mixin diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_backdrop.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_backdrop.scss new file mode 100644 index 0000000..9705ae9 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_backdrop.scss @@ -0,0 +1,14 @@ +// Shared between modals and offcanvases +@mixin overlay-backdrop($zindex, $backdrop-bg, $backdrop-opacity) { + position: fixed; + top: 0; + left: 0; + z-index: $zindex; + width: 100vw; + height: 100vh; + background-color: $backdrop-bg; + + // Fade for backdrop + &.fade { opacity: 0; } + &.show { opacity: $backdrop-opacity; } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_banner.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_banner.scss new file mode 100644 index 0000000..dd8a510 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_banner.scss @@ -0,0 +1,7 @@ +@mixin bsBanner($file) { + /*! + * Bootstrap #{$file} v5.3.8 (https://getbootstrap.com/) + * Copyright 2011-2025 The Bootstrap Authors + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_border-radius.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_border-radius.scss new file mode 100644 index 0000000..616decb --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_border-radius.scss @@ -0,0 +1,78 @@ +// stylelint-disable property-disallowed-list +// Single side border-radius + +// Helper function to replace negative values with 0 +@function valid-radius($radius) { + $return: (); + @each $value in $radius { + @if type-of($value) == number { + $return: append($return, max($value, 0)); + } @else { + $return: append($return, $value); + } + } + @return $return; +} + +// scss-docs-start border-radius-mixins +@mixin border-radius($radius: $border-radius, $fallback-border-radius: false) { + @if $enable-rounded { + border-radius: valid-radius($radius); + } + @else if $fallback-border-radius != false { + border-radius: $fallback-border-radius; + } +} + +@mixin border-top-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + border-top-right-radius: valid-radius($radius); + } +} + +@mixin border-end-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-right-radius: valid-radius($radius); + border-bottom-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-radius($radius: $border-radius) { + @if $enable-rounded { + border-bottom-right-radius: valid-radius($radius); + border-bottom-left-radius: valid-radius($radius); + } +} + +@mixin border-start-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + border-bottom-left-radius: valid-radius($radius); + } +} + +@mixin border-top-start-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-left-radius: valid-radius($radius); + } +} + +@mixin border-top-end-radius($radius: $border-radius) { + @if $enable-rounded { + border-top-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-end-radius($radius: $border-radius) { + @if $enable-rounded { + border-bottom-right-radius: valid-radius($radius); + } +} + +@mixin border-bottom-start-radius($radius: $border-radius) { + @if $enable-rounded { + border-bottom-left-radius: valid-radius($radius); + } +} +// scss-docs-end border-radius-mixins diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_box-shadow.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_box-shadow.scss new file mode 100644 index 0000000..0bb6bf7 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_box-shadow.scss @@ -0,0 +1,24 @@ +@mixin box-shadow($shadow...) { + @if $enable-shadows { + $result: (); + $has-single-value: false; + $single-value: null; + + @each $value in $shadow { + @if $value != null { + @if $value == none or $value == initial or $value == inherit or $value == unset { + $has-single-value: true; + $single-value: $value; + } @else { + $result: append($result, $value, "comma"); + } + } + } + + @if $has-single-value { + box-shadow: $single-value; + } @else if (length($result) > 0) { + box-shadow: $result; + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_breakpoints.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_breakpoints.scss new file mode 100644 index 0000000..286be89 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_breakpoints.scss @@ -0,0 +1,127 @@ +// Breakpoint viewport sizes and media queries. +// +// Breakpoints are defined as a map of (name: minimum width), order from small to large: +// +// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px) +// +// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default. + +// Name of the next breakpoint, or null for the last breakpoint. +// +// >> breakpoint-next(sm) +// md +// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// md +// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl xxl)) +// md +@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) { + $n: index($breakpoint-names, $name); + @if not $n { + @error "breakpoint `#{$name}` not found in `#{$breakpoints}`"; + } + @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null); +} + +// Minimum breakpoint width. Null for the smallest (first) breakpoint. +// +// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// 576px +@function breakpoint-min($name, $breakpoints: $grid-breakpoints) { + $min: map-get($breakpoints, $name); + @return if($min != 0, $min, null); +} + +// Maximum breakpoint width. +// The maximum value is reduced by 0.02px to work around the limitations of +// `min-` and `max-` prefixes and viewports with fractional widths. +// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max +// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari. +// See https://bugs.webkit.org/show_bug.cgi?id=178261 +// +// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// 767.98px +@function breakpoint-max($name, $breakpoints: $grid-breakpoints) { + $max: map-get($breakpoints, $name); + @return if($max and $max > 0, $max - .02, null); +} + +// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front. +// Useful for making responsive utilities. +// +// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// "" (Returns a blank string) +// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px, xxl: 1400px)) +// "-sm" +@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) { + @return if(breakpoint-min($name, $breakpoints) == null, "", "-#{$name}"); +} + +// Media of at least the minimum breakpoint width. No query for the smallest breakpoint. +// Makes the @content apply to the given breakpoint and wider. +@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + @if $min { + @media (min-width: $min) { + @content; + } + } @else { + @content; + } +} + +// Media of at most the maximum breakpoint width. No query for the largest breakpoint. +// Makes the @content apply to the given breakpoint and narrower. +@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) { + $max: breakpoint-max($name, $breakpoints); + @if $max { + @media (max-width: $max) { + @content; + } + } @else { + @content; + } +} + +// Media that spans multiple breakpoint widths. +// Makes the @content apply between the min and max breakpoints +@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($lower, $breakpoints); + $max: breakpoint-max($upper, $breakpoints); + + @if $min != null and $max != null { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else if $max == null { + @include media-breakpoint-up($lower, $breakpoints) { + @content; + } + } @else if $min == null { + @include media-breakpoint-down($upper, $breakpoints) { + @content; + } + } +} + +// Media between the breakpoint's minimum and maximum widths. +// No minimum for the smallest breakpoint, and no maximum for the largest one. +// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower. +@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) { + $min: breakpoint-min($name, $breakpoints); + $next: breakpoint-next($name, $breakpoints); + $max: breakpoint-max($next, $breakpoints); + + @if $min != null and $max != null { + @media (min-width: $min) and (max-width: $max) { + @content; + } + } @else if $max == null { + @include media-breakpoint-up($name, $breakpoints) { + @content; + } + } @else if $min == null { + @include media-breakpoint-down($next, $breakpoints) { + @content; + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_buttons.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_buttons.scss new file mode 100644 index 0000000..cf087fd --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_buttons.scss @@ -0,0 +1,70 @@ +// Button variants +// +// Easily pump out default styles, as well as :hover, :focus, :active, +// and disabled options for all buttons + +// scss-docs-start btn-variant-mixin +@mixin button-variant( + $background, + $border, + $color: color-contrast($background), + $hover-background: if($color == $color-contrast-light, shade-color($background, $btn-hover-bg-shade-amount), tint-color($background, $btn-hover-bg-tint-amount)), + $hover-border: if($color == $color-contrast-light, shade-color($border, $btn-hover-border-shade-amount), tint-color($border, $btn-hover-border-tint-amount)), + $hover-color: color-contrast($hover-background), + $active-background: if($color == $color-contrast-light, shade-color($background, $btn-active-bg-shade-amount), tint-color($background, $btn-active-bg-tint-amount)), + $active-border: if($color == $color-contrast-light, shade-color($border, $btn-active-border-shade-amount), tint-color($border, $btn-active-border-tint-amount)), + $active-color: color-contrast($active-background), + $disabled-background: $background, + $disabled-border: $border, + $disabled-color: color-contrast($disabled-background) +) { + --#{$prefix}btn-color: #{$color}; + --#{$prefix}btn-bg: #{$background}; + --#{$prefix}btn-border-color: #{$border}; + --#{$prefix}btn-hover-color: #{$hover-color}; + --#{$prefix}btn-hover-bg: #{$hover-background}; + --#{$prefix}btn-hover-border-color: #{$hover-border}; + --#{$prefix}btn-focus-shadow-rgb: #{to-rgb(mix($color, $border, 15%))}; + --#{$prefix}btn-active-color: #{$active-color}; + --#{$prefix}btn-active-bg: #{$active-background}; + --#{$prefix}btn-active-border-color: #{$active-border}; + --#{$prefix}btn-active-shadow: #{$btn-active-box-shadow}; + --#{$prefix}btn-disabled-color: #{$disabled-color}; + --#{$prefix}btn-disabled-bg: #{$disabled-background}; + --#{$prefix}btn-disabled-border-color: #{$disabled-border}; +} +// scss-docs-end btn-variant-mixin + +// scss-docs-start btn-outline-variant-mixin +@mixin button-outline-variant( + $color, + $color-hover: color-contrast($color), + $active-background: $color, + $active-border: $color, + $active-color: color-contrast($active-background) +) { + --#{$prefix}btn-color: #{$color}; + --#{$prefix}btn-border-color: #{$color}; + --#{$prefix}btn-hover-color: #{$color-hover}; + --#{$prefix}btn-hover-bg: #{$active-background}; + --#{$prefix}btn-hover-border-color: #{$active-border}; + --#{$prefix}btn-focus-shadow-rgb: #{to-rgb($color)}; + --#{$prefix}btn-active-color: #{$active-color}; + --#{$prefix}btn-active-bg: #{$active-background}; + --#{$prefix}btn-active-border-color: #{$active-border}; + --#{$prefix}btn-active-shadow: #{$btn-active-box-shadow}; + --#{$prefix}btn-disabled-color: #{$color}; + --#{$prefix}btn-disabled-bg: transparent; + --#{$prefix}btn-disabled-border-color: #{$color}; + --#{$prefix}gradient: none; +} +// scss-docs-end btn-outline-variant-mixin + +// scss-docs-start btn-size-mixin +@mixin button-size($padding-y, $padding-x, $font-size, $border-radius) { + --#{$prefix}btn-padding-y: #{$padding-y}; + --#{$prefix}btn-padding-x: #{$padding-x}; + @include rfs($font-size, --#{$prefix}btn-font-size); + --#{$prefix}btn-border-radius: #{$border-radius}; +} +// scss-docs-end btn-size-mixin diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_caret.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_caret.scss new file mode 100644 index 0000000..be73116 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_caret.scss @@ -0,0 +1,69 @@ +// scss-docs-start caret-mixins +@mixin caret-down($width: $caret-width) { + border-top: $width solid; + border-right: $width solid transparent; + border-bottom: 0; + border-left: $width solid transparent; +} + +@mixin caret-up($width: $caret-width) { + border-top: 0; + border-right: $width solid transparent; + border-bottom: $width solid; + border-left: $width solid transparent; +} + +@mixin caret-end($width: $caret-width) { + border-top: $width solid transparent; + border-right: 0; + border-bottom: $width solid transparent; + border-left: $width solid; +} + +@mixin caret-start($width: $caret-width) { + border-top: $width solid transparent; + border-right: $width solid; + border-bottom: $width solid transparent; +} + +@mixin caret( + $direction: down, + $width: $caret-width, + $spacing: $caret-spacing, + $vertical-align: $caret-vertical-align +) { + @if $enable-caret { + &::after { + display: inline-block; + margin-left: $spacing; + vertical-align: $vertical-align; + content: ""; + @if $direction == down { + @include caret-down($width); + } @else if $direction == up { + @include caret-up($width); + } @else if $direction == end { + @include caret-end($width); + } + } + + @if $direction == start { + &::after { + display: none; + } + + &::before { + display: inline-block; + margin-right: $spacing; + vertical-align: $vertical-align; + content: ""; + @include caret-start($width); + } + } + + &:empty::after { + margin-left: 0; + } + } +} +// scss-docs-end caret-mixins diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_clearfix.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_clearfix.scss new file mode 100644 index 0000000..ffc62bb --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_clearfix.scss @@ -0,0 +1,9 @@ +// scss-docs-start clearfix +@mixin clearfix() { + &::after { + display: block; + clear: both; + content: ""; + } +} +// scss-docs-end clearfix diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_color-mode.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_color-mode.scss new file mode 100644 index 0000000..03338b0 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_color-mode.scss @@ -0,0 +1,21 @@ +// scss-docs-start color-mode-mixin +@mixin color-mode($mode: light, $root: false) { + @if $color-mode-type == "media-query" { + @if $root == true { + @media (prefers-color-scheme: $mode) { + :root { + @content; + } + } + } @else { + @media (prefers-color-scheme: $mode) { + @content; + } + } + } @else { + [data-bs-theme="#{$mode}"] { + @content; + } + } +} +// scss-docs-end color-mode-mixin diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_color-scheme.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_color-scheme.scss new file mode 100644 index 0000000..90497aa --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_color-scheme.scss @@ -0,0 +1,7 @@ +// scss-docs-start mixin-color-scheme +@mixin color-scheme($name) { + @media (prefers-color-scheme: #{$name}) { + @content; + } +} +// scss-docs-end mixin-color-scheme diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_container.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_container.scss new file mode 100644 index 0000000..b9f3351 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_container.scss @@ -0,0 +1,11 @@ +// Container mixins + +@mixin make-container($gutter: $container-padding-x) { + --#{$prefix}gutter-x: #{$gutter}; + --#{$prefix}gutter-y: 0; + width: 100%; + padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + margin-right: auto; + margin-left: auto; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_deprecate.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_deprecate.scss new file mode 100644 index 0000000..df070bc --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_deprecate.scss @@ -0,0 +1,10 @@ +// Deprecate mixin +// +// This mixin can be used to deprecate mixins or functions. +// `$enable-deprecation-messages` is a global variable, `$ignore-warning` is a variable that can be passed to +// some deprecated mixins to suppress the warning (for example if the mixin is still be used in the current version of Bootstrap) +@mixin deprecate($name, $deprecate-version, $remove-version, $ignore-warning: false) { + @if ($enable-deprecation-messages != false and $ignore-warning != true) { + @warn "#{$name} has been deprecated as of #{$deprecate-version}. It will be removed entirely in #{$remove-version}."; + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_forms.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_forms.scss new file mode 100644 index 0000000..00b4764 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_forms.scss @@ -0,0 +1,163 @@ +// This mixin uses an `if()` technique to be compatible with Dart Sass +// See https://github.com/sass/sass/issues/1873#issuecomment-152293725 for more details + +// scss-docs-start form-validation-mixins +@mixin form-validation-state-selector($state) { + @if ($state == "valid" or $state == "invalid") { + .was-validated #{if(&, "&", "")}:#{$state}, + #{if(&, "&", "")}.is-#{$state} { + @content; + } + } @else { + #{if(&, "&", "")}.is-#{$state} { + @content; + } + } +} + +@mixin form-validation-state( + $state, + $color, + $icon, + $tooltip-color: color-contrast($color), + $tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity), + $focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity), + $border-color: $color +) { + .#{$state}-feedback { + display: none; + width: 100%; + margin-top: $form-feedback-margin-top; + @include font-size($form-feedback-font-size); + font-style: $form-feedback-font-style; + color: $color; + } + + .#{$state}-tooltip { + position: absolute; + top: 100%; + z-index: 5; + display: none; + max-width: 100%; // Contain to parent when possible + padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x; + margin-top: .1rem; + @include font-size($form-feedback-tooltip-font-size); + line-height: $form-feedback-tooltip-line-height; + color: $tooltip-color; + background-color: $tooltip-bg-color; + @include border-radius($form-feedback-tooltip-border-radius); + } + + @include form-validation-state-selector($state) { + ~ .#{$state}-feedback, + ~ .#{$state}-tooltip { + display: block; + } + } + + .form-control { + @include form-validation-state-selector($state) { + border-color: $border-color; + + @if $enable-validation-icons { + padding-right: $input-height-inner; + background-image: escape-svg($icon); + background-repeat: no-repeat; + background-position: right $input-height-inner-quarter center; + background-size: $input-height-inner-half $input-height-inner-half; + } + + &:focus { + border-color: $border-color; + @if $enable-shadows { + @include box-shadow($input-box-shadow, $focus-box-shadow); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: $focus-box-shadow; + } + } + } + } + + // stylelint-disable-next-line selector-no-qualifying-type + textarea.form-control { + @include form-validation-state-selector($state) { + @if $enable-validation-icons { + padding-right: $input-height-inner; + background-position: top $input-height-inner-quarter right $input-height-inner-quarter; + } + } + } + + .form-select { + @include form-validation-state-selector($state) { + border-color: $border-color; + + @if $enable-validation-icons { + &:not([multiple]):not([size]), + &:not([multiple])[size="1"] { + --#{$prefix}form-select-bg-icon: #{escape-svg($icon)}; + padding-right: $form-select-feedback-icon-padding-end; + background-position: $form-select-bg-position, $form-select-feedback-icon-position; + background-size: $form-select-bg-size, $form-select-feedback-icon-size; + } + } + + &:focus { + border-color: $border-color; + @if $enable-shadows { + @include box-shadow($form-select-box-shadow, $focus-box-shadow); + } @else { + // Avoid using mixin so we can pass custom focus shadow properly + box-shadow: $focus-box-shadow; + } + } + } + } + + .form-control-color { + @include form-validation-state-selector($state) { + @if $enable-validation-icons { + width: add($form-color-width, $input-height-inner); + } + } + } + + .form-check-input { + @include form-validation-state-selector($state) { + border-color: $border-color; + + &:checked { + background-color: $color; + } + + &:focus { + box-shadow: $focus-box-shadow; + } + + ~ .form-check-label { + color: $color; + } + } + } + .form-check-inline .form-check-input { + ~ .#{$state}-feedback { + margin-left: .5em; + } + } + + .input-group { + > .form-control:not(:focus), + > .form-select:not(:focus), + > .form-floating:not(:focus-within) { + @include form-validation-state-selector($state) { + @if $state == "valid" { + z-index: 3; + } @else if $state == "invalid" { + z-index: 4; + } + } + } + } +} +// scss-docs-end form-validation-mixins diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_gradients.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_gradients.scss new file mode 100644 index 0000000..608e18d --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_gradients.scss @@ -0,0 +1,47 @@ +// Gradients + +// scss-docs-start gradient-bg-mixin +@mixin gradient-bg($color: null) { + background-color: $color; + + @if $enable-gradients { + background-image: var(--#{$prefix}gradient); + } +} +// scss-docs-end gradient-bg-mixin + +// scss-docs-start gradient-mixins +// Horizontal gradient, from left to right +// +// Creates two color stops, start and end, by specifying a color and position for each color stop. +@mixin gradient-x($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) { + background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent); +} + +// Vertical gradient, from top to bottom +// +// Creates two color stops, start and end, by specifying a color and position for each color stop. +@mixin gradient-y($start-color: $gray-700, $end-color: $gray-800, $start-percent: null, $end-percent: null) { + background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent); +} + +@mixin gradient-directional($start-color: $gray-700, $end-color: $gray-800, $deg: 45deg) { + background-image: linear-gradient($deg, $start-color, $end-color); +} + +@mixin gradient-x-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { + background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color); +} + +@mixin gradient-y-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) { + background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color); +} + +@mixin gradient-radial($inner-color: $gray-700, $outer-color: $gray-800) { + background-image: radial-gradient(circle, $inner-color, $outer-color); +} + +@mixin gradient-striped($color: rgba($white, .15), $angle: 45deg) { + background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent); +} +// scss-docs-end gradient-mixins diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_grid.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_grid.scss new file mode 100644 index 0000000..db77e07 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_grid.scss @@ -0,0 +1,151 @@ +// Grid system +// +// Generate semantic grid columns with these mixins. + +@mixin make-row($gutter: $grid-gutter-width) { + --#{$prefix}gutter-x: #{$gutter}; + --#{$prefix}gutter-y: 0; + display: flex; + flex-wrap: wrap; + // TODO: Revisit calc order after https://github.com/react-bootstrap/react-bootstrap/issues/6039 is fixed + margin-top: calc(-1 * var(--#{$prefix}gutter-y)); // stylelint-disable-line function-disallowed-list + margin-right: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list + margin-left: calc(-.5 * var(--#{$prefix}gutter-x)); // stylelint-disable-line function-disallowed-list +} + +@mixin make-col-ready() { + // Add box sizing if only the grid is loaded + box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null); + // Prevent columns from becoming too narrow when at smaller grid tiers by + // always setting `width: 100%;`. This works because we set the width + // later on to override this initial width. + flex-shrink: 0; + width: 100%; + max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid + padding-right: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + padding-left: calc(var(--#{$prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list + margin-top: var(--#{$prefix}gutter-y); +} + +@mixin make-col($size: false, $columns: $grid-columns) { + @if $size { + flex: 0 0 auto; + width: percentage(divide($size, $columns)); + + } @else { + flex: 1 1 0; + max-width: 100%; + } +} + +@mixin make-col-auto() { + flex: 0 0 auto; + width: auto; +} + +@mixin make-col-offset($size, $columns: $grid-columns) { + $num: divide($size, $columns); + margin-left: if($num == 0, 0, percentage($num)); +} + +// Row columns +// +// Specify on a parent element(e.g., .row) to force immediate children into NN +// number of columns. Supports wrapping to new lines, but does not do a Masonry +// style grid. +@mixin row-cols($count) { + > * { + flex: 0 0 auto; + width: percentage(divide(1, $count)); + } +} + +// Framework grid generation +// +// Used only by Bootstrap to generate the correct number of grid classes given +// any value of `$grid-columns`. + +@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) { + @each $breakpoint in map-keys($breakpoints) { + $infix: breakpoint-infix($breakpoint, $breakpoints); + + @include media-breakpoint-up($breakpoint, $breakpoints) { + // Provide basic `.col-{bp}` classes for equal-width flexbox columns + .col#{$infix} { + flex: 1 0 0; + } + + .row-cols#{$infix}-auto > * { + @include make-col-auto(); + } + + @if $grid-row-columns > 0 { + @for $i from 1 through $grid-row-columns { + .row-cols#{$infix}-#{$i} { + @include row-cols($i); + } + } + } + + .col#{$infix}-auto { + @include make-col-auto(); + } + + @if $columns > 0 { + @for $i from 1 through $columns { + .col#{$infix}-#{$i} { + @include make-col($i, $columns); + } + } + + // `$columns - 1` because offsetting by the width of an entire row isn't possible + @for $i from 0 through ($columns - 1) { + @if not ($infix == "" and $i == 0) { // Avoid emitting useless .offset-0 + .offset#{$infix}-#{$i} { + @include make-col-offset($i, $columns); + } + } + } + } + + // Gutters + // + // Make use of `.g-*`, `.gx-*` or `.gy-*` utilities to change spacing between the columns. + @each $key, $value in $gutters { + .g#{$infix}-#{$key}, + .gx#{$infix}-#{$key} { + --#{$prefix}gutter-x: #{$value}; + } + + .g#{$infix}-#{$key}, + .gy#{$infix}-#{$key} { + --#{$prefix}gutter-y: #{$value}; + } + } + } + } +} + +@mixin make-cssgrid($columns: $grid-columns, $breakpoints: $grid-breakpoints) { + @each $breakpoint in map-keys($breakpoints) { + $infix: breakpoint-infix($breakpoint, $breakpoints); + + @include media-breakpoint-up($breakpoint, $breakpoints) { + @if $columns > 0 { + @for $i from 1 through $columns { + .g-col#{$infix}-#{$i} { + grid-column: auto / span $i; + } + } + + // Start with `1` because `0` is an invalid value. + // Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible. + @for $i from 1 through ($columns - 1) { + .g-start#{$infix}-#{$i} { + grid-column-start: $i; + } + } + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_image.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_image.scss new file mode 100644 index 0000000..e1df779 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_image.scss @@ -0,0 +1,16 @@ +// Image Mixins +// - Responsive image +// - Retina image + + +// Responsive image +// +// Keep images from scaling beyond the width of their parents. + +@mixin img-fluid { + // Part 1: Set a maximum relative to the parent + max-width: 100%; + // Part 2: Override the height to auto, otherwise images will be stretched + // when setting a width and height attribute on the img element. + height: auto; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_list-group.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_list-group.scss new file mode 100644 index 0000000..6274f34 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_list-group.scss @@ -0,0 +1,26 @@ +@include deprecate("`list-group-item-variant()`", "v5.3.0", "v6.0.0"); + +// List Groups + +// scss-docs-start list-group-mixin +@mixin list-group-item-variant($state, $background, $color) { + .list-group-item-#{$state} { + color: $color; + background-color: $background; + + &.list-group-item-action { + &:hover, + &:focus { + color: $color; + background-color: shade-color($background, 10%); + } + + &.active { + color: $white; + background-color: $color; + border-color: $color; + } + } + } +} +// scss-docs-end list-group-mixin diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_lists.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_lists.scss new file mode 100644 index 0000000..2518562 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_lists.scss @@ -0,0 +1,7 @@ +// Lists + +// Unstyled keeps list items block level, just removes default browser padding and list-style +@mixin list-unstyled { + padding-left: 0; + list-style: none; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_pagination.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_pagination.scss new file mode 100644 index 0000000..0d65796 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_pagination.scss @@ -0,0 +1,10 @@ +// Pagination + +// scss-docs-start pagination-mixin +@mixin pagination-size($padding-y, $padding-x, $font-size, $border-radius) { + --#{$prefix}pagination-padding-x: #{$padding-x}; + --#{$prefix}pagination-padding-y: #{$padding-y}; + @include rfs($font-size, --#{$prefix}pagination-font-size); + --#{$prefix}pagination-border-radius: #{$border-radius}; +} +// scss-docs-end pagination-mixin diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_reset-text.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_reset-text.scss new file mode 100644 index 0000000..f5bd1af --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_reset-text.scss @@ -0,0 +1,17 @@ +@mixin reset-text { + font-family: $font-family-base; + // We deliberately do NOT reset font-size or overflow-wrap / word-wrap. + font-style: normal; + font-weight: $font-weight-normal; + line-height: $line-height-base; + text-align: left; // Fallback for where `start` is not supported + text-align: start; + text-decoration: none; + text-shadow: none; + text-transform: none; + letter-spacing: normal; + word-break: normal; + white-space: normal; + word-spacing: normal; + line-break: auto; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_resize.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_resize.scss new file mode 100644 index 0000000..66f233a --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_resize.scss @@ -0,0 +1,6 @@ +// Resize anything + +@mixin resizable($direction) { + overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible` + resize: $direction; // Options: horizontal, vertical, both +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_table-variants.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_table-variants.scss new file mode 100644 index 0000000..5fe1b9b --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_table-variants.scss @@ -0,0 +1,24 @@ +// scss-docs-start table-variant +@mixin table-variant($state, $background) { + .table-#{$state} { + $color: color-contrast(opaque($body-bg, $background)); + $hover-bg: mix($color, $background, percentage($table-hover-bg-factor)); + $striped-bg: mix($color, $background, percentage($table-striped-bg-factor)); + $active-bg: mix($color, $background, percentage($table-active-bg-factor)); + $table-border-color: mix($color, $background, percentage($table-border-factor)); + + --#{$prefix}table-color: #{$color}; + --#{$prefix}table-bg: #{$background}; + --#{$prefix}table-border-color: #{$table-border-color}; + --#{$prefix}table-striped-bg: #{$striped-bg}; + --#{$prefix}table-striped-color: #{color-contrast($striped-bg)}; + --#{$prefix}table-active-bg: #{$active-bg}; + --#{$prefix}table-active-color: #{color-contrast($active-bg)}; + --#{$prefix}table-hover-bg: #{$hover-bg}; + --#{$prefix}table-hover-color: #{color-contrast($hover-bg)}; + + color: var(--#{$prefix}table-color); + border-color: var(--#{$prefix}table-border-color); + } +} +// scss-docs-end table-variant diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_text-truncate.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_text-truncate.scss new file mode 100644 index 0000000..3504bb1 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_text-truncate.scss @@ -0,0 +1,8 @@ +// Text truncate +// Requires inline-block or block for proper styling + +@mixin text-truncate() { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_transition.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_transition.scss new file mode 100644 index 0000000..d437f6d --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_transition.scss @@ -0,0 +1,26 @@ +// stylelint-disable property-disallowed-list +@mixin transition($transition...) { + @if length($transition) == 0 { + $transition: $transition-base; + } + + @if length($transition) > 1 { + @each $value in $transition { + @if $value == null or $value == none { + @warn "The keyword 'none' or 'null' must be used as a single argument."; + } + } + } + + @if $enable-transitions { + @if nth($transition, 1) != null { + transition: $transition; + } + + @if $enable-reduced-motion and nth($transition, 1) != null and nth($transition, 1) != none { + @media (prefers-reduced-motion: reduce) { + transition: none; + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_utilities.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_utilities.scss new file mode 100644 index 0000000..4795e89 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_utilities.scss @@ -0,0 +1,97 @@ +// Utility generator +// Used to generate utilities & print utilities +@mixin generate-utility($utility, $infix: "", $is-rfs-media-query: false) { + $values: map-get($utility, values); + + // If the values are a list or string, convert it into a map + @if type-of($values) == "string" or type-of(nth($values, 1)) != "list" { + $values: zip($values, $values); + } + + @each $key, $value in $values { + $properties: map-get($utility, property); + + // Multiple properties are possible, for example with vertical or horizontal margins or paddings + @if type-of($properties) == "string" { + $properties: append((), $properties); + } + + // Use custom class if present + $property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1)); + $property-class: if($property-class == null, "", $property-class); + + // Use custom CSS variable name if present, otherwise default to `class` + $css-variable-name: if(map-has-key($utility, css-variable-name), map-get($utility, css-variable-name), map-get($utility, class)); + + // State params to generate pseudo-classes + $state: if(map-has-key($utility, state), map-get($utility, state), ()); + + $infix: if($property-class == "" and str-slice($infix, 1, 1) == "-", str-slice($infix, 2), $infix); + + // Don't prefix if value key is null (e.g. with shadow class) + $property-class-modifier: if($key, if($property-class == "" and $infix == "", "", "-") + $key, ""); + + @if map-get($utility, rfs) { + // Inside the media query + @if $is-rfs-media-query { + $val: rfs-value($value); + + // Do not render anything if fluid and non fluid values are the same + $value: if($val == rfs-fluid-value($value), null, $val); + } + @else { + $value: rfs-fluid-value($value); + } + } + + $is-css-var: map-get($utility, css-var); + $is-local-vars: map-get($utility, local-vars); + $is-rtl: map-get($utility, rtl); + + @if $value != null { + @if $is-rtl == false { + /* rtl:begin:remove */ + } + + @if $is-css-var { + .#{$property-class + $infix + $property-class-modifier} { + --#{$prefix}#{$css-variable-name}: #{$value}; + } + + @each $pseudo in $state { + .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} { + --#{$prefix}#{$css-variable-name}: #{$value}; + } + } + } @else { + .#{$property-class + $infix + $property-class-modifier} { + @each $property in $properties { + @if $is-local-vars { + @each $local-var, $variable in $is-local-vars { + --#{$prefix}#{$local-var}: #{$variable}; + } + } + #{$property}: $value if($enable-important-utilities, !important, null); + } + } + + @each $pseudo in $state { + .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} { + @each $property in $properties { + @if $is-local-vars { + @each $local-var, $variable in $is-local-vars { + --#{$prefix}#{$local-var}: #{$variable}; + } + } + #{$property}: $value if($enable-important-utilities, !important, null); + } + } + } + } + + @if $is-rtl == false { + /* rtl:end:remove */ + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_visually-hidden.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_visually-hidden.scss new file mode 100644 index 0000000..9dd0ad3 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/mixins/_visually-hidden.scss @@ -0,0 +1,38 @@ +// stylelint-disable declaration-no-important + +// Hide content visually while keeping it accessible to assistive technologies +// +// See: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/ +// See: https://kittygiraudel.com/2016/10/13/css-hide-and-seek/ + +@mixin visually-hidden() { + width: 1px !important; + height: 1px !important; + padding: 0 !important; + margin: -1px !important; // Fix for https://github.com/twbs/bootstrap/issues/25686 + overflow: hidden !important; + clip: rect(0, 0, 0, 0) !important; + white-space: nowrap !important; + border: 0 !important; + + // Fix for positioned table caption that could become anonymous cells + &:not(caption) { + position: absolute !important; + } + + // Fix to prevent overflowing children to become focusable + * { + overflow: hidden !important; + } +} + +// Use to only display content when it's focused, or one of its child elements is focused +// (i.e. when focus is within the element/container that the class was applied to) +// +// Useful for "Skip to main content" links; see https://www.w3.org/WAI/WCAG22/Techniques/general/G1.html + +@mixin visually-hidden-focusable() { + &:not(:focus):not(:focus-within) { + @include visually-hidden(); + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/jasmine.js b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/jasmine.js new file mode 100644 index 0000000..25d838c --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/jasmine.js @@ -0,0 +1,16 @@ +/* eslint-disable camelcase */ + +'use strict' + +const path = require('node:path') + +module.exports = { + spec_dir: 'scss', + // Make Jasmine look for `.test.scss` files + spec_files: ['**/*.{test,spec}.scss'], + // Compile them into JS scripts running `sass-true` + requires: [path.join(__dirname, 'sass-true/register')], + // Ensure we use `require` so that the require.extensions works + // as `import` completely bypasses it + jsLoader: 'require' +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_auto-import-of-variables-dark.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_auto-import-of-variables-dark.test.scss new file mode 100644 index 0000000..f08ae58 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_auto-import-of-variables-dark.test.scss @@ -0,0 +1,7 @@ +// TODO: this file can be removed safely in v6 when `@import "variables-dark"` will be removed at the end of _variables.scss + +@import "../../functions"; +@import "../../variables"; +// Voluntarily not importing _variables-dark.scss +@import "../../maps"; +@import "../../mixins"; diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_box-shadow.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_box-shadow.test.scss new file mode 100644 index 0000000..f5a0748 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_box-shadow.test.scss @@ -0,0 +1,188 @@ +@import "../../functions"; +@import "../../variables"; +@import "../../mixins"; + +// Store original value +$original-enable-shadows: $enable-shadows; + +// Enable shadows for all tests +$enable-shadows: true !global; + +@include describe("box-shadow mixin") { + @include it("handles single none value") { + @include assert() { + @include output() { + .test { + @include box-shadow(none); + } + } + + @include expect() { + .test { + box-shadow: none; + } + } + } + } + + @include it("handles multiple none values by consolidating them") { + @include assert() { + @include output() { + .test { + @include box-shadow(none, none, none); + } + } + + @include expect() { + .test { + box-shadow: none; + } + } + } + } + + @include it("handles other single-value keywords (initial, inherit, unset)") { + @include assert() { + @include output() { + .test-initial { + @include box-shadow(initial); + } + .test-inherit { + @include box-shadow(inherit); + } + .test-unset { + @include box-shadow(unset); + } + } + + @include expect() { + .test-initial { + box-shadow: initial; + } + .test-inherit { + box-shadow: inherit; + } + .test-unset { + box-shadow: unset; + } + } + } + } + + @include it("handles multiple single-value keywords by using the last one") { + @include assert() { + @include output() { + .test { + @include box-shadow(initial, inherit, unset); + } + } + + @include expect() { + .test { + box-shadow: unset; + } + } + } + } + + @include it("handles regular box-shadow values") { + @include assert() { + @include output() { + .test { + @include box-shadow(0 0 10px rgba(0, 0, 0, .5)); + } + } + + @include expect() { + .test { + box-shadow: 0 0 10px rgba(0, 0, 0, .5); + } + } + } + } + + @include it("handles multiple regular box-shadow values") { + @include assert() { + @include output() { + .test { + @include box-shadow(0 0 10px rgba(0, 0, 0, .5), 0 0 20px rgba(0, 0, 0, .3)); + } + } + + @include expect() { + .test { + box-shadow: 0 0 10px rgba(0, 0, 0, .5), 0 0 20px rgba(0, 0, 0, .3); + } + } + } + } + + @include it("handles null values by ignoring them") { + @include assert() { + @include output() { + .test { + @include box-shadow(null, 0 0 10px rgba(0, 0, 0, .5), null); + } + } + + @include expect() { + .test { + box-shadow: 0 0 10px rgba(0, 0, 0, .5); + } + } + } + } + + @include it("handles mixed values with keywords and regular shadows") { + @include assert() { + @include output() { + .test { + @include box-shadow(none, 0 0 10px rgba(0, 0, 0, .5)); + } + } + + @include expect() { + .test { + box-shadow: none; + } + } + } + } + + @include it("handles empty input") { + @include assert() { + @include output() { + .test { + @include box-shadow(); + } + } + + @include expect() { + .test { // stylelint-disable-line block-no-empty + } + } + } + } + + @include it("respects $enable-shadows variable") { + $enable-shadows: false !global; + + @include assert() { + @include output() { + .test { + @include box-shadow(0 0 10px rgba(0, 0, 0, .5)); + } + } + + @include expect() { + .test { // stylelint-disable-line block-no-empty + } + } + } + + $enable-shadows: true !global; + } +} + +// Restore original value +$enable-shadows: $original-enable-shadows !global; diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_color-contrast.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_color-contrast.test.scss new file mode 100644 index 0000000..5b94ac5 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_color-contrast.test.scss @@ -0,0 +1,139 @@ +@import "../../functions"; +@import "../../variables"; +@import "../../variables-dark"; +@import "../../maps"; +@import "../../mixins"; + +@include describe("color-contrast function") { + @include it("should return a color when contrast ratio equals minimum requirement (WCAG 2.1 compliance)") { + // Test case: Background color that produces contrast ratio close to 4.5:1 + // This tests the WCAG 2.1 requirement that contrast should be "at least 4.5:1" (>= 4.5) + // rather than "strictly greater than 4.5:1" (> 4.5) + + // #777777 produces 4.4776:1 contrast ratio with white text + // Since this is below the 4.5:1 threshold, it should return the highest available contrast color + $test-background: #777; + $result: color-contrast($test-background); + + @include assert-equal($result, $black, "Should return black (highest available contrast) for background with 4.4776:1 contrast ratio (below threshold)"); + } + + @include it("should return a color when contrast ratio is above minimum requirement") { + // Test case: Background color that produces contrast ratio above 4.5:1 + // #767676 produces 4.5415:1 contrast ratio with white text + $test-background: #767676; + $result: color-contrast($test-background); + + @include assert-equal($result, $white, "Should return white for background with 4.5415:1 contrast ratio (above threshold)"); + } + + @include it("should return a color when contrast ratio is below minimum requirement") { + // Test case: Background color that produces contrast ratio below 4.5:1 + // #787878 produces 4.4155:1 contrast ratio with white text + $test-background: #787878; + $result: color-contrast($test-background); + + // Should return the color with the highest available contrast ratio + @include assert-equal($result, $black, "Should return black (highest available contrast) for background with 4.4155:1 contrast ratio (below threshold)"); + } + + @include it("should handle edge case with very light background") { + // Test case: Very light background that should return dark text + $test-background: #f8f9fa; // Very light gray + $result: color-contrast($test-background); + + @include assert-equal($result, $color-contrast-dark, "Should return dark text for very light background"); + } + + @include it("should handle edge case with very dark background") { + // Test case: Very dark background that should return light text + $test-background: #212529; // Very dark gray + $result: color-contrast($test-background); + + @include assert-equal($result, $color-contrast-light, "Should return light text for very dark background"); + } + + @include it("should work with custom minimum contrast ratio") { + // Test case: Using a custom minimum contrast ratio + $test-background: #666; + $result: color-contrast($test-background, $color-contrast-dark, $color-contrast-light, 3); + + @include assert-equal($result, $white, "Should return white when using custom minimum contrast ratio of 3.0"); + } + + @include it("should test contrast ratio calculation accuracy") { + // Test case: Verify that contrast-ratio function works correctly + $background: #767676; + $foreground: $white; + $ratio: contrast-ratio($background, $foreground); + // Bootstrap's implementation calculates this as ~4.5415, not exactly 4.5, due to its luminance math. + // We use 4.54 as the threshold for this test to match the actual implementation. + @include assert-true($ratio >= 4.54 and $ratio <= 4.55, "Contrast ratio should be approximately 4.54:1 (Bootstrap's math)"); + } + + @include it("should test luminance calculation") { + // Test case: Verify luminance function works correctly + $white-luminance: luminance($white); + $black-luminance: luminance($black); + + @include assert-equal($white-luminance, 1, "White should have luminance of 1"); + @include assert-equal($black-luminance, 0, "Black should have luminance of 0"); + } + + @include it("should handle rgba colors correctly") { + // Test case: Test with rgba colors + $test-background: rgba(118, 118, 118, 1); // Same as #767676 + $result: color-contrast($test-background); + + @include assert-equal($result, $white, "Should handle rgba colors correctly"); + } + + @include it("should test the WCAG 2.1 boundary condition with color below threshold") { + // Test case: Background color that produces contrast ratio below 4.5:1 + // #787878 produces 4.4155:1 contrast ratio with white + $test-background: #787878; // Produces 4.4155:1 contrast ratio + $contrast-ratio: contrast-ratio($test-background, $white); + + // Verify the contrast ratio is below 4.5:1 + @include assert-true($contrast-ratio < 4.5, "Contrast ratio should be below 4.5:1 threshold"); + + // The color-contrast function should return the color with highest available contrast + $result: color-contrast($test-background); + @include assert-equal($result, $black, "color-contrast should return black (highest available contrast) for below-threshold ratio"); + } + + @include it("should test the WCAG 2.1 boundary condition with color at threshold") { + // Test case: Background color that produces contrast ratio close to 4.5:1 + // #777777 produces 4.4776:1 contrast ratio with white + $test-background: #777; // Produces 4.4776:1 contrast ratio + $contrast-ratio: contrast-ratio($test-background, $white); + + // Verify the contrast ratio is below 4.5:1 threshold + @include assert-true($contrast-ratio < 4.5, "Contrast ratio is below threshold, function should handle gracefully"); + } + + @include it("should demonstrate the difference between > and >= operators") { + // Test case: Demonstrates the difference between > and >= operators + // Uses #767676 with a custom minimum contrast ratio that matches its actual ratio (4.5415) + // With > 4.5415: should return black (fallback to highest available) + // With >= 4.5415: should return white (meets threshold) + + $test-background: #767676; // Produces 4.5415:1 contrast ratio + $actual-ratio: contrast-ratio($test-background, $white); + + // Test with a custom minimum that matches the actual ratio + $result: color-contrast($test-background, $color-contrast-dark, $color-contrast-light, $actual-ratio); + + // Should return white when using >= implementation + @include assert-equal($result, $white, "color-contrast should return white when using exact ratio as threshold (>= implementation)"); + } + + @include it("should test additional working colors above threshold") { + // Test case: Background color that produces contrast ratio well above 4.5:1 + // #757575 produces 4.6047:1 contrast ratio with white text + $test-background: #757575; // Produces 4.6047:1 contrast ratio + $result: color-contrast($test-background); + + @include assert-equal($result, $white, "Should return white for background with 4.6047:1 contrast ratio (well above threshold)"); + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_color-modes.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_color-modes.test.scss new file mode 100644 index 0000000..9ecc628 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_color-modes.test.scss @@ -0,0 +1,69 @@ +// stylelint-disable selector-attribute-quotes + +@import "../../functions"; +@import "../../variables"; +@import "../../variables-dark"; +@import "../../maps"; +@import "../../mixins"; + +@include describe("global $color-mode-type: data") { + @include it("generates data attribute selectors for dark mode") { + @include assert() { + @include output() { + @include color-mode(dark) { + .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); + } + } + @include color-mode(dark, true) { + --custom-color: #{mix($indigo, $blue, 50%)}; + } + } + @include expect() { + [data-bs-theme=dark] .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); + } + [data-bs-theme=dark] { + --custom-color: #3a3ff8; + } + } + } + } +} + +@include describe("global $color-mode-type: media-query") { + @include it("generates media queries for dark mode") { + $color-mode-type: media-query !global; + + @include assert() { + @include output() { + @include color-mode(dark) { + .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); + } + } + @include color-mode(dark, true) { + --custom-color: #{mix($indigo, $blue, 50%)}; + } + } + @include expect() { + @media (prefers-color-scheme: dark) { + .element { + color: var(--bs-primary-text-emphasis); + background-color: var(--bs-primary-bg-subtle); + } + } + @media (prefers-color-scheme: dark) { + :root { + --custom-color: #3a3ff8; + } + } + } + } + + $color-mode-type: data !global; + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_media-query-color-mode-full.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_media-query-color-mode-full.test.scss new file mode 100644 index 0000000..00ed82d --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_media-query-color-mode-full.test.scss @@ -0,0 +1,8 @@ +$color-mode-type: media-query; + +@import "../../bootstrap"; + +@include describe("global $color-mode-type: media-query") { + @include it("compiles entirely Bootstrap CSS with media-query color mode") { // stylelint-disable-line block-no-empty + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_utilities.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_utilities.test.scss new file mode 100644 index 0000000..8140ac4 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/mixins/_utilities.test.scss @@ -0,0 +1,393 @@ +$prefix: bs-; +$enable-important-utilities: false; + +// Important: Do not import rfs to check that the mixin just calls the appropriate functions from it +@import "../../mixins/utilities"; + +@mixin test-generate-utility($params...) { + @include assert() { + @include output() { + @include generate-utility($params...); + } + + @include expect() { + @content; + } + } +} + +@include describe(generate-utility) { + @include it("generates a utility class for each value") { + @include test-generate-utility( + ( + property: "padding", + values: (small: .5rem, large: 2rem) + ) + ) { + .padding-small { + padding: .5rem; + } + + .padding-large { + padding: 2rem; + } + } + } + + @include describe("global $enable-important-utilities: true") { + @include it("sets !important") { + $enable-important-utilities: true !global; + + @include test-generate-utility( + ( + property: "padding", + values: (small: .5rem, large: 2rem) + ) + ) { + .padding-small { + padding: .5rem !important; + } + + .padding-large { + padding: 2rem !important; + } + } + + $enable-important-utilities: false !global; + } + } + + @include describe("$utility") { + @include describe("values") { + @include it("supports null keys") { + @include test-generate-utility( + ( + property: "padding", + values: (null: 1rem, small: .5rem, large: 2rem) + ), + ) { + .padding { + padding: 1rem; + } + + .padding-small { + padding: .5rem; + } + + .padding-large { + padding: 2rem; + } + } + } + + @include it("ignores null values") { + @include test-generate-utility( + ( + property: "padding", + values: (small: null, large: 2rem) + ) + ) { + .padding-large { + padding: 2rem; + } + } + } + + @include it("supports lists") { + @include test-generate-utility( + ( + property: "padding", + values: 1rem 2rem + ) + ) { + .padding-1rem { + padding: 1rem; + } + + .padding-2rem { + padding: 2rem; + } + } + } + + @include it("supports single values") { + @include test-generate-utility( + ( + property: padding, + values: 1rem + ) + ) { + .padding-1rem { + padding: 1rem; + } + } + } + } + + @include describe("class & property") { + @include it("adds each property to the declaration") { + @include test-generate-utility( + ( + class: padding-x, + property: padding-inline-start padding-inline-end, + values: 1rem + ) + ) { + .padding-x-1rem { + padding-inline-start: 1rem; + padding-inline-end: 1rem; + } + } + } + + @include it("uses the first property as class name") { + @include test-generate-utility( + ( + property: padding-inline-start padding-inline-end, + values: 1rem + ) + ) { + .padding-inline-start-1rem { + padding-inline-start: 1rem; + padding-inline-end: 1rem; + } + } + } + + @include it("supports a null class to create classes straight from the values") { + @include test-generate-utility( + ( + property: visibility, + class: null, + values: ( + visible: visible, + invisible: hidden, + ) + ) + ) { + .visible { + visibility: visible; + } + + .invisible { + visibility: hidden; + } + } + } + } + + @include describe("state") { + @include it("Generates selectors for each states") { + @include test-generate-utility( + ( + property: padding, + values: 1rem, + state: hover focus, + ) + ) { + .padding-1rem { + padding: 1rem; + } + + .padding-1rem-hover:hover { + padding: 1rem; + } + + .padding-1rem-focus:focus { + padding: 1rem; + } + } + } + } + + @include describe("css-var"){ + @include it("sets a CSS variable instead of the property") { + @include test-generate-utility( + ( + property: padding, + css-variable-name: padding, + css-var: true, + values: 1rem 2rem + ) + ) { + .padding-1rem { + --bs-padding: 1rem; + } + + .padding-2rem { + --bs-padding: 2rem; + } + } + } + + @include it("defaults to class") { + @include test-generate-utility( + ( + property: padding, + class: padding, + css-var: true, + values: 1rem 2rem + ) + ) { + .padding-1rem { + --bs-padding: 1rem; + } + + .padding-2rem { + --bs-padding: 2rem; + } + } + } + } + + @include describe("local-vars") { + @include it("generates the listed variables") { + @include test-generate-utility( + ( + property: color, + class: desaturated-color, + local-vars: ( + color-opacity: 1, + color-saturation: .25 + ), + values: ( + blue: hsla(192deg, var(--bs-color-saturation), 0, var(--bs-color-opacity)) + ) + ) + ) { + .desaturated-color-blue { + --bs-color-opacity: 1; + // Sass compilation will put a leading zero so we want to keep that one + // stylelint-disable-next-line @stylistic/number-leading-zero + --bs-color-saturation: 0.25; + color: hsla(192deg, var(--bs-color-saturation), 0, var(--bs-color-opacity)); + } + } + } + } + + @include describe("css-var & state") { + @include it("Generates a rule with for each state with a CSS variable") { + @include test-generate-utility( + ( + property: padding, + css-var: true, + css-variable-name: padding, + values: 1rem, + state: hover focus, + ) + ) { + .padding-1rem { + --bs-padding: 1rem; + } + + .padding-1rem-hover:hover { + --bs-padding: 1rem; + } + + .padding-1rem-focus:focus { + --bs-padding: 1rem; + } + } + } + } + + @include describe("rtl") { + @include it("sets up RTLCSS for removal when false") { + @include test-generate-utility( + ( + property: padding, + values: 1rem, + rtl: false + ) + ) { + /* rtl:begin:remove */ + + .padding-1rem { + padding: 1rem; + } + + /* rtl:end:remove */ + + } + } + } + + @include describe("rfs") { + @include it("sets the fluid value when not inside media query") { + @include test-generate-utility( + ( + property: padding, + values: 1rem, + rfs: true + ) + ) { + .padding-1rem { + padding: rfs-fluid-value(1rem); + } + } + } + + @include it("sets the value when inside the media query") { + @include test-generate-utility( + ( + property: padding, + values: 1rem, + rfs: true + ), + $is-rfs-media-query: true + ) { + .padding-1rem { + padding: rfs-value(1rem); + } + } + } + } + } + + @include describe("$infix") { + @include it("inserts the given infix") { + @include test-generate-utility( + ( + property: "padding", + values: (null: 1rem, small: .5rem, large: 2rem) + ), + $infix: -sm + ) { + .padding-sm { + padding: 1rem; + } + + .padding-sm-small { + padding: .5rem; + } + + .padding-sm-large { + padding: 2rem; + } + } + } + + @include it("strips leading - if class is null") { + @include test-generate-utility( + ( + property: visibility, + class: null, + values: ( + visible: visible, + invisible: hidden, + ) + ), + -sm + ) { + .sm-visible { + visibility: visible; + } + + .sm-invisible { + visibility: hidden; + } + } + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/sass-true/register.js b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/sass-true/register.js new file mode 100644 index 0000000..d93e414 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/sass-true/register.js @@ -0,0 +1,14 @@ +'use strict' + +const path = require('node:path') + +const runnerPath = path.join(__dirname, 'runner').replace(/\\/g, '/') + +require.extensions['.scss'] = (module, filename) => { + const normalizedFilename = filename.replace(/\\/g, '/') + + return module._compile(` + const runner = require('${runnerPath}') + runner('${normalizedFilename}', { describe, it }) + `, filename) +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/sass-true/runner.js b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/sass-true/runner.js new file mode 100644 index 0000000..bef870a --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/sass-true/runner.js @@ -0,0 +1,17 @@ +'use strict' + +const fs = require('node:fs') +const path = require('node:path') +const { runSass } = require('sass-true') + +module.exports = (filename, { describe, it }) => { + const data = fs.readFileSync(filename, 'utf8') + const TRUE_SETUP = '$true-terminal-output: false; @import "true";' + const sassString = TRUE_SETUP + data + + runSass( + { describe, it, sourceType: 'string' }, + sassString, + { loadPaths: [path.dirname(filename)] } + ) +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/utilities/_api.test.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/utilities/_api.test.scss new file mode 100644 index 0000000..304d8d1 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/tests/utilities/_api.test.scss @@ -0,0 +1,75 @@ +@import "../../functions"; +@import "../../variables"; +@import "../../variables-dark"; +@import "../../maps"; +@import "../../mixins"; + +$utilities: (); + +@include describe("utilities/api") { + @include it("generates utilities for each breakpoints") { + $utilities: ( + margin: ( + property: margin, + values: auto + ), + padding: ( + property: padding, + responsive: true, + values: 1rem + ), + font-size: ( + property: font-size, + values: (large: 1.25rem), + print: true + ) + ) !global; + + $grid-breakpoints: ( + xs: 0, + sm: 333px, + md: 666px + ) !global; + + @include assert() { + @include output() { + @import "../../utilities/api"; + } + + @include expect() { + // margin is not set to responsive + .margin-auto { + margin: auto !important; + } + + // padding is, though + .padding-1rem { + padding: 1rem !important; + } + + .font-size-large { + font-size: 1.25rem !important; + } + + @media (min-width: 333px) { + .padding-sm-1rem { + padding: 1rem !important; + } + } + + @media (min-width: 666px) { + .padding-md-1rem { + padding: 1rem !important; + } + } + + @media print { + .font-size-print-large { + font-size: 1.25rem !important; + } + } + } + + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/utilities/_api.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/utilities/_api.scss new file mode 100644 index 0000000..62e1d39 --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/utilities/_api.scss @@ -0,0 +1,47 @@ +// Loop over each breakpoint +@each $breakpoint in map-keys($grid-breakpoints) { + + // Generate media query if needed + @include media-breakpoint-up($breakpoint) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + // Loop over each utility property + @each $key, $utility in $utilities { + // The utility can be disabled with `false`, thus check if the utility is a map first + // Only proceed if responsive media queries are enabled or if it's the base media query + @if type-of($utility) == "map" and (map-get($utility, responsive) or $infix == "") { + @include generate-utility($utility, $infix); + } + } + } +} + +// RFS rescaling +@media (min-width: $rfs-mq-value) { + @each $breakpoint in map-keys($grid-breakpoints) { + $infix: breakpoint-infix($breakpoint, $grid-breakpoints); + + @if (map-get($grid-breakpoints, $breakpoint) < $rfs-breakpoint) { + // Loop over each utility property + @each $key, $utility in $utilities { + // The utility can be disabled with `false`, thus check if the utility is a map first + // Only proceed if responsive media queries are enabled or if it's the base media query + @if type-of($utility) == "map" and map-get($utility, rfs) and (map-get($utility, responsive) or $infix == "") { + @include generate-utility($utility, $infix, true); + } + } + } + } +} + + +// Print utilities +@media print { + @each $key, $utility in $utilities { + // The utility can be disabled with `false`, thus check if the utility is a map first + // Then check if the utility needs print styles + @if type-of($utility) == "map" and map-get($utility, print) == true { + @include generate-utility($utility, "-print"); + } + } +} diff --git a/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/vendor/_rfs.scss b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/vendor/_rfs.scss new file mode 100644 index 0000000..aa1f82b --- /dev/null +++ b/extensions/pagetop-bootsier/static/scss/bootstrap-5.3.8/vendor/_rfs.scss @@ -0,0 +1,348 @@ +// stylelint-disable scss/dimension-no-non-numeric-values + +// SCSS RFS mixin +// +// Automated responsive values for font sizes, paddings, margins and much more +// +// Licensed under MIT (https://github.com/twbs/rfs/blob/main/LICENSE) + +// Configuration + +// Base value +$rfs-base-value: 1.25rem !default; +$rfs-unit: rem !default; + +@if $rfs-unit != rem and $rfs-unit != px { + @error "`#{$rfs-unit}` is not a valid unit for $rfs-unit. Use `px` or `rem`."; +} + +// Breakpoint at where values start decreasing if screen width is smaller +$rfs-breakpoint: 1200px !default; +$rfs-breakpoint-unit: px !default; + +@if $rfs-breakpoint-unit != px and $rfs-breakpoint-unit != em and $rfs-breakpoint-unit != rem { + @error "`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`."; +} + +// Resize values based on screen height and width +$rfs-two-dimensional: false !default; + +// Factor of decrease +$rfs-factor: 10 !default; + +@if type-of($rfs-factor) != number or $rfs-factor <= 1 { + @error "`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1."; +} + +// Mode. Possibilities: "min-media-query", "max-media-query" +$rfs-mode: min-media-query !default; + +// Generate enable or disable classes. Possibilities: false, "enable" or "disable" +$rfs-class: false !default; + +// 1 rem = $rfs-rem-value px +$rfs-rem-value: 16 !default; + +// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14 +$rfs-safari-iframe-resize-bug-fix: false !default; + +// Disable RFS by setting $enable-rfs to false +$enable-rfs: true !default; + +// Cache $rfs-base-value unit +$rfs-base-value-unit: unit($rfs-base-value); + +@function divide($dividend, $divisor, $precision: 10) { + $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1); + $dividend: abs($dividend); + $divisor: abs($divisor); + @if $dividend == 0 { + @return 0; + } + @if $divisor == 0 { + @error "Cannot divide by 0"; + } + $remainder: $dividend; + $result: 0; + $factor: 10; + @while ($remainder > 0 and $precision >= 0) { + $quotient: 0; + @while ($remainder >= $divisor) { + $remainder: $remainder - $divisor; + $quotient: $quotient + 1; + } + $result: $result * 10 + $quotient; + $factor: $factor * .1; + $remainder: $remainder * 10; + $precision: $precision - 1; + @if ($precision < 0 and $remainder >= $divisor * 5) { + $result: $result + 1; + } + } + $result: $result * $factor * $sign; + $dividend-unit: unit($dividend); + $divisor-unit: unit($divisor); + $unit-map: ( + "px": 1px, + "rem": 1rem, + "em": 1em, + "%": 1% + ); + @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) { + $result: $result * map-get($unit-map, $dividend-unit); + } + @return $result; +} + +// Remove px-unit from $rfs-base-value for calculations +@if $rfs-base-value-unit == px { + $rfs-base-value: divide($rfs-base-value, $rfs-base-value * 0 + 1); +} +@else if $rfs-base-value-unit == rem { + $rfs-base-value: divide($rfs-base-value, divide($rfs-base-value * 0 + 1, $rfs-rem-value)); +} + +// Cache $rfs-breakpoint unit to prevent multiple calls +$rfs-breakpoint-unit-cache: unit($rfs-breakpoint); + +// Remove unit from $rfs-breakpoint for calculations +@if $rfs-breakpoint-unit-cache == px { + $rfs-breakpoint: divide($rfs-breakpoint, $rfs-breakpoint * 0 + 1); +} +@else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == "em" { + $rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value)); +} + +// Calculate the media query value +$rfs-mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{divide($rfs-breakpoint, $rfs-rem-value)}#{$rfs-breakpoint-unit}); +$rfs-mq-property-width: if($rfs-mode == max-media-query, max-width, min-width); +$rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height); + +// Internal mixin used to determine which media query needs to be used +@mixin _rfs-media-query { + @if $rfs-two-dimensional { + @if $rfs-mode == max-media-query { + @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) { + @content; + } + } + @else { + @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) and (#{$rfs-mq-property-height}: #{$rfs-mq-value}) { + @content; + } + } + } + @else { + @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) { + @content; + } + } +} + +// Internal mixin that adds disable classes to the selector if needed. +@mixin _rfs-rule { + @if $rfs-class == disable and $rfs-mode == max-media-query { + // Adding an extra class increases specificity, which prevents the media query to override the property + &, + .disable-rfs &, + &.disable-rfs { + @content; + } + } + @else if $rfs-class == enable and $rfs-mode == min-media-query { + .enable-rfs &, + &.enable-rfs { + @content; + } + } @else { + @content; + } +} + +// Internal mixin that adds enable classes to the selector if needed. +@mixin _rfs-media-query-rule { + + @if $rfs-class == enable { + @if $rfs-mode == min-media-query { + @content; + } + + @include _rfs-media-query () { + .enable-rfs &, + &.enable-rfs { + @content; + } + } + } + @else { + @if $rfs-class == disable and $rfs-mode == min-media-query { + .disable-rfs &, + &.disable-rfs { + @content; + } + } + @include _rfs-media-query () { + @content; + } + } +} + +// Helper function to get the formatted non-responsive value +@function rfs-value($values) { + // Convert to list + $values: if(type-of($values) != list, ($values,), $values); + + $val: ""; + + // Loop over each value and calculate value + @each $value in $values { + @if $value == 0 { + $val: $val + " 0"; + } + @else { + // Cache $value unit + $unit: if(type-of($value) == "number", unit($value), false); + + @if $unit == px { + // Convert to rem if needed + $val: $val + " " + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value); + } + @else if $unit == rem { + // Convert to px if needed + $val: $val + " " + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $value); + } @else { + // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value + $val: $val + " " + $value; + } + } + } + + // Remove first space + @return unquote(str-slice($val, 2)); +} + +// Helper function to get the responsive value calculated by RFS +@function rfs-fluid-value($values) { + // Convert to list + $values: if(type-of($values) != list, ($values,), $values); + + $val: ""; + + // Loop over each value and calculate value + @each $value in $values { + @if $value == 0 { + $val: $val + " 0"; + } @else { + // Cache $value unit + $unit: if(type-of($value) == "number", unit($value), false); + + // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value + @if not $unit or $unit != px and $unit != rem { + $val: $val + " " + $value; + } @else { + // Remove unit from $value for calculations + $value: divide($value, $value * 0 + if($unit == px, 1, divide(1, $rfs-rem-value))); + + // Only add the media query if the value is greater than the minimum value + @if abs($value) <= $rfs-base-value or not $enable-rfs { + $val: $val + " " + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px); + } + @else { + // Calculate the minimum value + $value-min: $rfs-base-value + divide(abs($value) - $rfs-base-value, $rfs-factor); + + // Calculate difference between $value and the minimum value + $value-diff: abs($value) - $value-min; + + // Base value formatting + $min-width: if($rfs-unit == rem, #{divide($value-min, $rfs-rem-value)}rem, #{$value-min}px); + + // Use negative value if needed + $min-width: if($value < 0, -$min-width, $min-width); + + // Use `vmin` if two-dimensional is enabled + $variable-unit: if($rfs-two-dimensional, vmin, vw); + + // Calculate the variable width between 0 and $rfs-breakpoint + $variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit}; + + // Return the calculated value + $val: $val + " calc(" + $min-width + if($value < 0, " - ", " + ") + $variable-width + ")"; + } + } + } + } + + // Remove first space + @return unquote(str-slice($val, 2)); +} + +// RFS mixin +@mixin rfs($values, $property: font-size) { + @if $values != null { + $val: rfs-value($values); + $fluid-val: rfs-fluid-value($values); + + // Do not print the media query if responsive & non-responsive values are the same + @if $val == $fluid-val { + #{$property}: $val; + } + @else { + @include _rfs-rule () { + #{$property}: if($rfs-mode == max-media-query, $val, $fluid-val); + + // Include safari iframe resize fix if needed + min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null); + } + + @include _rfs-media-query-rule () { + #{$property}: if($rfs-mode == max-media-query, $fluid-val, $val); + } + } + } +} + +// Shorthand helper mixins +@mixin font-size($value) { + @include rfs($value); +} + +@mixin padding($value) { + @include rfs($value, padding); +} + +@mixin padding-top($value) { + @include rfs($value, padding-top); +} + +@mixin padding-right($value) { + @include rfs($value, padding-right); +} + +@mixin padding-bottom($value) { + @include rfs($value, padding-bottom); +} + +@mixin padding-left($value) { + @include rfs($value, padding-left); +} + +@mixin margin($value) { + @include rfs($value, margin); +} + +@mixin margin-top($value) { + @include rfs($value, margin-top); +} + +@mixin margin-right($value) { + @include rfs($value, margin-right); +} + +@mixin margin-bottom($value) { + @include rfs($value, margin-bottom); +} + +@mixin margin-left($value) { + @include rfs($value, margin-left); +} diff --git a/helpers/pagetop-build/README.md b/helpers/pagetop-build/README.md index 57273e8..875acbd 100644 --- a/helpers/pagetop-build/README.md +++ b/helpers/pagetop-build/README.md @@ -4,10 +4,10 @@ <p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) [![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) [![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-build#licencia) </div> diff --git a/helpers/pagetop-build/src/lib.rs b/helpers/pagetop-build/src/lib.rs index c6e7236..9088ec9 100644 --- a/helpers/pagetop-build/src/lib.rs +++ b/helpers/pagetop-build/src/lib.rs @@ -5,10 +5,10 @@ <p>Prepara un conjunto de archivos estáticos o archivos SCSS compilados para ser incluidos en el binario de un proyecto <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-build?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-build) [![Crates.io](https://img.shields.io/crates/v/pagetop-build.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-build) [![Descargas](https://img.shields.io/crates/d/pagetop-build.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-build) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-build#licencia) </div> diff --git a/helpers/pagetop-macros/README.md b/helpers/pagetop-macros/README.md index 7c9c2e8..66fdc1f 100644 --- a/helpers/pagetop-macros/README.md +++ b/helpers/pagetop-macros/README.md @@ -4,10 +4,10 @@ <p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) [![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) [![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-macros#licencia) </div> diff --git a/helpers/pagetop-macros/src/lib.rs b/helpers/pagetop-macros/src/lib.rs index 5af5f9c..732bbad 100644 --- a/helpers/pagetop-macros/src/lib.rs +++ b/helpers/pagetop-macros/src/lib.rs @@ -5,10 +5,10 @@ <p>Una colección de macros que mejoran la experiencia de desarrollo con <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop-macros?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-macros) [![Crates.io](https://img.shields.io/crates/v/pagetop-macros.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-macros) [![Descargas](https://img.shields.io/crates/d/pagetop-macros.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-macros) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-macros#licencia) </div> @@ -266,16 +266,18 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { v }; - // Extrae atributos descartando la documentación para incluir en `alter_...()`. - let non_doc_attrs: Vec<_> = attrs + // Filtra los atributos descartando `#[doc]` y `#[inline]` para el método `alter_...()`. + let non_doc_or_inline_attrs: Vec<_> = attrs .iter() - .filter(|&a| !a.path().is_ident("doc")) + .filter(|a| { + let p = a.path(); + !p.is_ident("doc") && !p.is_ident("inline") + }) .cloned() .collect(); // Documentación del método alter_...(). - let alter_doc = - format!("Equivalente a [`Self::{with_name_str}()`], pero fuera del patrón *builder*."); + let doc = format!("Equivale a [`Self::{with_name_str}()`], pero fuera del patrón *builder*."); // Genera el código final. let expanded = match body_opt { @@ -284,14 +286,21 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { #(#attrs)* fn #with_name #generics (self, #(#args),*) -> Self #where_clause; - #(#non_doc_attrs)* - #[doc = #alter_doc] + #(#non_doc_or_inline_attrs)* + #[doc = #doc] fn #alter_ident #generics (&mut self, #(#args),*) -> &mut Self #where_clause; } } Some(body) => { + // Si no se indicó ninguna forma de `inline`, fuerza `#[inline]` para `with_...()`. + let force_inline = if attrs.iter().any(|a| a.path().is_ident("inline")) { + quote! {} + } else { + quote! { #[inline] } + }; let with_fn = if is_trait { quote! { + #force_inline #vis_pub fn #with_name #generics (self, #(#args),*) -> Self #where_clause { let mut s = self; s.#alter_ident(#(#call_idents),*); @@ -300,6 +309,7 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { } } else { quote! { + #force_inline #vis_pub fn #with_name #generics (mut self, #(#args),*) -> Self #where_clause { self.#alter_ident(#(#call_idents),*); self @@ -310,8 +320,8 @@ pub fn builder_fn(_: TokenStream, item: TokenStream) -> TokenStream { #(#attrs)* #with_fn - #(#non_doc_attrs)* - #[doc = #alter_doc] + #(#non_doc_or_inline_attrs)* + #[doc = #doc] #vis_pub fn #alter_ident #generics (&mut self, #(#args),*) -> &mut Self #where_clause { #body } diff --git a/helpers/pagetop-statics/README.md b/helpers/pagetop-statics/README.md index 4168cd4..cd1da6a 100644 --- a/helpers/pagetop-statics/README.md +++ b/helpers/pagetop-statics/README.md @@ -4,7 +4,10 @@ <p>Librería para automatizar la recopilación de recursos estáticos en <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +[![Doc API](https://img.shields.io/docsrs/pagetop-statics?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-statics) +[![Crates.io](https://img.shields.io/crates/v/pagetop-statics.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-statics) +[![Descargas](https://img.shields.io/crates/d/pagetop-statics.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-statics) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-statics#licencia) </div> diff --git a/helpers/pagetop-statics/src/lib.rs b/helpers/pagetop-statics/src/lib.rs index 201d90e..6f04bd2 100644 --- a/helpers/pagetop-statics/src/lib.rs +++ b/helpers/pagetop-statics/src/lib.rs @@ -5,7 +5,10 @@ <p>Librería para automatizar la recopilación de recursos estáticos en <strong>PageTop</strong>.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) +[![Doc API](https://img.shields.io/docsrs/pagetop-statics?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop-statics) +[![Crates.io](https://img.shields.io/crates/v/pagetop-statics.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop-statics) +[![Descargas](https://img.shields.io/crates/d/pagetop-statics.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop-statics) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop/src/branch/main/helpers/pagetop-statics#licencia) </div> diff --git a/src/base/action/component.rs b/src/base/action/component.rs index aaef1ce..30c7ba4 100644 --- a/src/base/action/component.rs +++ b/src/base/action/component.rs @@ -1,8 +1,5 @@ //! Acciones que operan sobre componentes. -mod is_renderable; -pub use is_renderable::*; - mod before_render_component; pub use before_render_component::*; diff --git a/src/base/action/component/is_renderable.rs b/src/base/action/component/is_renderable.rs deleted file mode 100644 index 5a0e244..0000000 --- a/src/base/action/component/is_renderable.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::prelude::*; - -/// Tipo de función para determinar si un componente se renderiza o no. -/// -/// Se usa en la acción [`IsRenderable`] para controlar dinámicamente la visibilidad del componente -/// `component` según el contexto `cx`. El componente **no se renderiza** en cuanto una de las -/// funciones devuelva `false`. -pub type FnIsRenderable<C> = fn(component: &C, cx: &Context) -> bool; - -/// Con la función [`FnIsRenderable`] se puede decidir si se renderiza o no un componente. -pub struct IsRenderable<C: Component> { - f: FnIsRenderable<C>, - referer_type_id: Option<UniqueId>, - referer_id: AttrId, - weight: Weight, -} - -/// Filtro para despachar [`FnIsRenderable`] para decidir si se renderiza o no un componente `C`. -impl<C: Component> ActionDispatcher for IsRenderable<C> { - /// Devuelve el identificador de tipo ([`UniqueId`]) del componente `C`. - fn referer_type_id(&self) -> Option<UniqueId> { - self.referer_type_id - } - - /// Devuelve el identificador del componente. - fn referer_id(&self) -> Option<String> { - self.referer_id.get() - } - - /// Devuelve el peso para definir el orden de ejecución. - fn weight(&self) -> Weight { - self.weight - } -} - -impl<C: Component> IsRenderable<C> { - /// Permite [registrar](Extension::actions) una nueva acción [`FnIsRenderable`]. - pub fn new(f: FnIsRenderable<C>) -> Self { - IsRenderable { - f, - referer_type_id: Some(UniqueId::of::<C>()), - referer_id: AttrId::default(), - weight: 0, - } - } - - /// Afina el registro para ejecutar la acción [`FnIsRenderable`] sólo para el componente `C` - /// con identificador `id`. - pub fn filter_by_referer_id(mut self, id: impl AsRef<str>) -> Self { - self.referer_id.alter_value(id); - self - } - - /// Opcional. Acciones con pesos más bajos se aplican antes. Se pueden usar valores negativos. - pub fn with_weight(mut self, value: Weight) -> Self { - self.weight = value; - self - } - - // Despacha las acciones. Se detiene en cuanto una [`FnIsRenderable`] devuelve `false`. - #[inline] - pub(crate) fn dispatch(component: &C, cx: &mut Context) -> bool { - let mut renderable = true; - dispatch_actions( - &ActionKey::new( - UniqueId::of::<Self>(), - None, - Some(UniqueId::of::<C>()), - None, - ), - |action: &Self| { - if renderable && !(action.f)(component, cx) { - renderable = false; - } - }, - ); - if renderable { - if let Some(id) = component.id() { - dispatch_actions( - &ActionKey::new( - UniqueId::of::<Self>(), - None, - Some(UniqueId::of::<C>()), - Some(id), - ), - |action: &Self| { - if renderable && !(action.f)(component, cx) { - renderable = false; - } - }, - ); - } - } - renderable - } -} diff --git a/src/base/component.rs b/src/base/component.rs index 4df64ff..bdab35c 100644 --- a/src/base/component.rs +++ b/src/base/component.rs @@ -1,10 +1,56 @@ //! Componentes nativos proporcionados por PageTop. +use crate::prelude::*; + +// **< FontSize >*********************************************************************************** + +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum FontSize { + ExtraLarge, + XxLarge, + XLarge, + Large, + Medium, + #[default] + Normal, + Small, + XSmall, + XxSmall, + ExtraSmall, +} + +#[rustfmt::skip] +impl FontSize { + #[inline] + pub const fn as_str(self) -> &'static str { + match self { + FontSize::ExtraLarge => "fs__x3l", + FontSize::XxLarge => "fs__x2l", + FontSize::XLarge => "fs__xl", + FontSize::Large => "fs__l", + FontSize::Medium => "fs__m", + FontSize::Normal => "", + FontSize::Small => "fs__s", + FontSize::XSmall => "fs__xs", + FontSize::XxSmall => "fs__x2s", + FontSize::ExtraSmall => "fs__x3s", + } + } +} + +// ************************************************************************************************* + mod html; pub use html::Html; mod block; pub use block::Block; +mod intro; +pub use intro::{Intro, IntroOpening}; + mod poweredby; pub use poweredby::PoweredBy; + +mod icon; +pub use icon::{Icon, IconKind}; diff --git a/src/base/component/block.rs b/src/base/component/block.rs index c96f2ba..b2a754e 100644 --- a/src/base/component/block.rs +++ b/src/base/component/block.rs @@ -47,7 +47,7 @@ impl Component for Block { } impl Block { - // Block BUILDER ******************************************************************************* + // **< Block BUILDER >************************************************************************** /// Establece el identificador único (`id`) del bloque. #[builder_fn] @@ -71,32 +71,32 @@ impl Block { } /// Añade un nuevo componente hijo al bloque. - pub fn add_component(mut self, component: impl Component) -> Self { - self.children - .alter_child(ChildOp::Add(Child::with(component))); + #[inline] + pub fn add_child(mut self, component: impl Component) -> Self { + self.children.add(Child::with(component)); self } - /// Modifica la lista de hijos (`children`) aplicando una operación. + /// Modifica la lista de componentes (`children`) aplicando una operación [`ChildOp`]. #[builder_fn] pub fn with_child(mut self, op: ChildOp) -> Self { self.children.alter_child(op); self } - // Block GETTERS ******************************************************************************* + // **< Block GETTERS >************************************************************************** /// Devuelve las clases CSS asociadas al bloque. pub fn classes(&self) -> &AttrClasses { &self.classes } - /// Devuelve el título del bloque como [`L10n`]. + /// Devuelve el título del bloque. pub fn title(&self) -> &L10n { &self.title } - /// Devuelve la lista de hijos (`children`) del bloque. + /// Devuelve la lista de componentes (`children`) del bloque. pub fn children(&self) -> &Children { &self.children } diff --git a/src/base/component/html.rs b/src/base/component/html.rs index 8fa5690..a60d30f 100644 --- a/src/base/component/html.rs +++ b/src/base/component/html.rs @@ -8,8 +8,7 @@ use crate::prelude::*; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let component = Html::with(|_| { /// html! { /// div class="example" { @@ -22,8 +21,7 @@ use crate::prelude::*; /// Para renderizar contenido que dependa del contexto, se puede acceder a él dentro del *closure*: /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let component = Html::with(|cx| { /// let user = cx.param::<String>("username").cloned().unwrap_or("visitor".to_string()); /// html! { @@ -49,7 +47,7 @@ impl Component for Html { } impl Html { - // Html BUILDER ******************************************************************************** + // **< Html BUILDER >*************************************************************************** /// Crea una instancia que generará el `Markup`, con acceso opcional al contexto. /// @@ -77,7 +75,7 @@ impl Html { self } - // Html GETTERS ******************************************************************************** + // **< Html GETTERS >*************************************************************************** /// Aplica la función interna de renderizado con el [`Context`] proporcionado. /// diff --git a/src/base/component/icon.rs b/src/base/component/icon.rs new file mode 100644 index 0000000..73e5ac4 --- /dev/null +++ b/src/base/component/icon.rs @@ -0,0 +1,134 @@ +use crate::prelude::*; + +const DEFAULT_VIEWBOX: &str = "0 0 16 16"; + +#[derive(AutoDefault)] +pub enum IconKind { + #[default] + None, + Font(FontSize), + Svg { + shapes: Markup, + viewbox: AttrValue, + }, +} + +#[rustfmt::skip] +#[derive(AutoDefault)] +pub struct Icon { + classes : AttrClasses, + icon_kind : IconKind, + aria_label: AttrL10n, +} + +impl Component for Icon { + fn new() -> Self { + Icon::default() + } + + fn setup_before_prepare(&mut self, _cx: &mut Context) { + if !matches!(self.icon_kind(), IconKind::None) { + self.alter_classes(ClassesOp::Prepend, "icon"); + } + if let IconKind::Font(font_size) = self.icon_kind() { + self.alter_classes(ClassesOp::Add, font_size.as_str()); + } + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + match self.icon_kind() { + IconKind::None => PrepareMarkup::None, + IconKind::Font(_) => { + let aria_label = self.aria_label().lookup(cx); + let has_label = aria_label.is_some(); + PrepareMarkup::With(html! { + i + class=[self.classes().get()] + role=[has_label.then_some("img")] + aria-label=[aria_label] + aria-hidden=[(!has_label).then_some("true")] + {} + }) + } + IconKind::Svg { shapes, viewbox } => { + let aria_label = self.aria_label().lookup(cx); + let has_label = aria_label.is_some(); + let viewbox = viewbox.get().unwrap_or_else(|| DEFAULT_VIEWBOX.to_string()); + PrepareMarkup::With(html! { + svg + xmlns="http://www.w3.org/2000/svg" + viewBox=(viewbox) + fill="currentColor" + focusable="false" + class=[self.classes().get()] + role=[has_label.then_some("img")] + aria-label=[aria_label] + aria-hidden=[(!has_label).then_some("true")] + { + (shapes) + } + }) + } + } + } +} + +impl Icon { + pub fn font() -> Self { + Icon::default().with_icon_kind(IconKind::Font(FontSize::default())) + } + + pub fn font_sized(font_size: FontSize) -> Self { + Icon::default().with_icon_kind(IconKind::Font(font_size)) + } + + pub fn svg(shapes: Markup) -> Self { + Icon::default().with_icon_kind(IconKind::Svg { + shapes, + viewbox: AttrValue::default(), + }) + } + + pub fn svg_with_viewbox(shapes: Markup, viewbox: impl AsRef<str>) -> Self { + Icon::default().with_icon_kind(IconKind::Svg { + shapes, + viewbox: AttrValue::new(viewbox), + }) + } + + // **< Icon BUILDER >*************************************************************************** + + /// Modifica la lista de clases CSS aplicadas al icono. + #[builder_fn] + pub fn with_classes(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { + self.classes.alter_value(op, classes); + self + } + + #[builder_fn] + pub fn with_icon_kind(mut self, icon_kind: IconKind) -> Self { + self.icon_kind = icon_kind; + self + } + + #[builder_fn] + pub fn with_aria_label(mut self, label: L10n) -> Self { + self.aria_label.alter_value(label); + self + } + + // **< Icon GETTERS >*************************************************************************** + + /// Devuelve las clases CSS asociadas al icono. + pub fn classes(&self) -> &AttrClasses { + &self.classes + } + + pub fn icon_kind(&self) -> &IconKind { + &self.icon_kind + } + + pub fn aria_label(&self) -> &AttrL10n { + &self.aria_label + } +} diff --git a/src/base/component/intro.rs b/src/base/component/intro.rs new file mode 100644 index 0000000..052f9c6 --- /dev/null +++ b/src/base/component/intro.rs @@ -0,0 +1,319 @@ +use crate::prelude::*; + +/// Tipo de apertura que se mostrará en la introducción del componente [`Intro`]. +/// +/// Permite elegir entre una apertura con textos predefinidos sobre PageTop (como hace la página de +/// bienvenida [`Welcome`](crate::base::extension::Welcome)) o una introducción completamente +/// personalizada. +#[derive(AutoDefault, Copy, Clone, Debug, Eq, PartialEq)] +pub enum IntroOpening { + /// Modo por defecto. Muestra una introducción estándar de PageTop e incluye automáticamente + /// *badges* con información de la última versión liberada, fecha del último lanzamiento y + /// licencia de uso. + #[default] + PageTop, + /// Modo totalmente personalizado. No añade *badges* ni textos predefinidos. Usa la imagen de + /// PageTop pero el contenido lo define el propio desarrollador. + Custom, +} + +/// Componente para presentar PageTop (como [`Welcome`](crate::base::extension::Welcome)), o mostrar +/// introducciones. +/// +/// Usa la imagen de PageTop para presentar contenidos con: +/// +/// - Una **imagen decorativa** (el *monster* de PageTop) antecediendo al contenido. +/// - Una vista destacada con **título + eslogan**. +/// - Un **botón opcional** de llamada a la acción con texto y enlace configurables. +/// - El **área de textos** con *badges* predefinidos (en modo [`IntroOpening::PageTop`]) y bloques +/// ([`Block`](crate::base::component::Block)) para crear párrafos vistosos de texto. Aunque +/// admite todo tipo de componentes. +/// +/// ### Ejemplos +/// +/// **Intro mínima por defecto** +/// +/// ```rust +/// # use pagetop::prelude::*; +/// let intro = Intro::default(); +/// ``` +/// +/// **Título, eslogan y botón personalizados** +/// +/// ```rust +/// # use pagetop::prelude::*; +/// let intro = Intro::default() +/// .with_title(L10n::l("intro_custom_title")) +/// .with_slogan(L10n::l("intro_custom_slogan")) +/// .with_button(Some(( +/// L10n::l("intro_learn_more"), +/// |_| "/learn-more" +/// ))); +/// ``` +/// +/// **Sin botón + modo *Custom* (sin *badges* predefinidos)** +/// +/// ```rust +/// # use pagetop::prelude::*; +/// let intro = Intro::default() +/// .with_button(None::<(L10n, FnPathByContext)>) +/// .with_opening(IntroOpening::Custom); +/// ``` +/// +/// **Añadir contenidos hijo** +/// +/// ```rust +/// # use pagetop::prelude::*; +/// let intro = Intro::default() +/// .add_child( +/// Block::new() +/// .with_title(L10n::l("intro_custom_block_title")) +/// .add_child(Html::with(move |cx| { +/// html! { +/// p { (L10n::l("intro_custom_paragraph_1").using(cx)) } +/// p { (L10n::l("intro_custom_paragraph_2").using(cx)) } +/// } +/// })), +/// ); +/// ``` +#[rustfmt::skip] +pub struct Intro { + title : L10n, + slogan : L10n, + button : Option<(L10n, FnPathByContext)>, + opening : IntroOpening, + children: Children, +} + +impl Default for Intro { + #[rustfmt::skip] + fn default() -> Self { + Intro { + title : L10n::l("intro_default_title"), + slogan : L10n::l("intro_default_slogan").with_arg("app", &global::SETTINGS.app.name), + button : Some((L10n::l("intro_default_button"), |_| "https://pagetop.cillero.es")), + opening : IntroOpening::default(), + children: Children::default(), + } + } +} + +impl Component for Intro { + fn new() -> Self { + Intro::default() + } + + fn setup_before_prepare(&mut self, cx: &mut Context) { + cx.alter_assets(ContextOp::AddStyleSheet( + StyleSheet::from("/css/intro.css").with_version(env!("CARGO_PKG_VERSION")), + )); + } + + fn prepare_component(&self, cx: &mut Context) -> PrepareMarkup { + if self.opening() == IntroOpening::PageTop { + cx.alter_assets(ContextOp::AddJavaScript(JavaScript::on_load_async("intro-js", |cx| + util::indoc!(r#" + try { + const resp = await fetch("https://crates.io/api/v1/crates/pagetop"); + const data = await resp.json(); + const date = new Date(data.versions[0].created_at); + const formatted = date.toLocaleDateString("LANGID", { year: "numeric", month: "2-digit", day: "2-digit" }); + document.getElementById("intro-release").src = `https://img.shields.io/badge/Release%20date-${encodeURIComponent(formatted)}-blue?label=LABEL&style=for-the-badge`; + document.getElementById("intro-badges").style.display = "block"; + } catch (e) { + console.error("Failed to fetch release date from crates.io:", e); + } + "#) + .replace("LANGID", cx.langid().to_string().as_str()) + .replace("LABEL", L10n::l("intro_release_label").using(cx).as_str()) + ))); + } + + PrepareMarkup::With(html! { + div class="intro" { + div class="intro-header" { + section class="intro-header__body" { + h1 class="intro-header__title" { + span { (self.title().using(cx)) } + (self.slogan().using(cx)) + } + } + aside class="intro-header__image" aria-hidden="true" { + div class="intro-header__monster" { + (PageTopSvg::Color.render(cx)) + } + } + } + div class="intro-content" { + section class="intro-content__body" { + div class="intro-text" { + @if let Some((txt, lnk)) = self.button() { + div class="intro-button" { + a + class="intro-button__link" + href=((lnk)(cx)) + target="_blank" + rel="noopener noreferrer" + { + span {} span {} span {} + div class="intro-button__text" { + (txt.using(cx)) + } + } + } + } + div class="intro-text__children" { + @if self.opening() == IntroOpening::PageTop { + p { (L10n::l("intro_text1").using(cx)) } + div id="intro-badges" { + img + src="https://img.shields.io/crates/v/pagetop.svg?label=PageTop&style=for-the-badge" + alt=[L10n::l("intro_pagetop_label").lookup(cx)] {} (" ") + img + id="intro-release" + alt=[L10n::l("intro_release_label").lookup(cx)] {} (" ") + img + src=(format!( + "https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label={}&style=for-the-badge", + L10n::l("intro_license_label").lookup(cx).unwrap_or_default() + )) + alt=[L10n::l("intro_license_label").lookup(cx)] {} + } + p { (L10n::l("intro_text2").using(cx)) } + } + (self.children().render(cx)) + } + } + } + } + div class="intro-footer" { + section class="intro-footer__body" { + div class="intro-footer__logo" { + (PageTopSvg::LineLight.render(cx)) + } + div class="intro-footer__links" { + a href="https://crates.io/crates/pagetop" target="_blank" rel="noopener noreferrer" { ("Crates.io") } + a href="https://docs.rs/pagetop" target="_blank" rel="noopener noreferrer" { ("Docs.rs") } + a href="https://git.cillero.es/manuelcillero/pagetop" target="_blank" rel="noopener noreferrer" { (L10n::l("intro_code").using(cx)) } + em { (L10n::l("intro_have_fun").using(cx)) } + } + } + } + } + }) + } +} + +impl Intro { + // **< Intro BUILDER >************************************************************************** + + /// Establece el título de entrada. + /// + /// # Ejemplo + /// + /// ```rust + /// # use pagetop::prelude::*; + /// let intro = Intro::default().with_title(L10n::n("Intro title")); + /// ``` + #[builder_fn] + pub fn with_title(mut self, title: L10n) -> Self { + self.title = title; + self + } + + /// Establece el eslogan de entrada (línea secundaria del título). + /// + /// # Ejemplo + /// + /// ```rust + /// # use pagetop::prelude::*; + /// let intro = Intro::default().with_slogan(L10n::n("A short slogan")); + /// ``` + #[builder_fn] + pub fn with_slogan(mut self, slogan: L10n) -> Self { + self.slogan = slogan; + self + } + + /// Configura el botón opcional de llamada a la acción. + /// + /// - Usa `Some((texto, closure_url))` para mostrarlo, donde [`FnPathByContext`] recibe el + /// [`Context`] y devuelve la ruta o URL final al pulsar el botón. + /// - Usa `None` para ocultarlo. + /// + /// # Ejemplo + /// + /// ```rust + /// # use pagetop::prelude::*; + /// // Define un botón con texto y una URL fija. + /// let intro = Intro::default().with_button(Some((L10n::n("Learn more"), |_| "/start"))); + /// // Descarta el botón de la intro. + /// let intro_no_button = Intro::default().with_button(None); + /// ``` + #[builder_fn] + pub fn with_button(mut self, button: Option<(L10n, FnPathByContext)>) -> Self { + self.button = button; + self + } + + /// Selecciona el tipo de apertura: [`IntroOpening::PageTop`] (por defecto) o + /// [`IntroOpening::Custom`]. + /// + /// - `PageTop`: añade *badges* automáticos y una presentación de lo que es PageTop. + /// - `Custom`: introducción en blanco para añadir cualquier contenido. + /// + /// # Ejemplo + /// + /// ```rust + /// # use pagetop::prelude::*; + /// let intro = Intro::default().with_opening(IntroOpening::Custom); + /// ``` + #[builder_fn] + pub fn with_opening(mut self, opening: IntroOpening) -> Self { + self.opening = opening; + self + } + + /// Añade un nuevo componente hijo a la intro. + /// + /// Si es un bloque ([`Block`]) aplica estilos específicos para destacarlo. + #[inline] + pub fn add_child(mut self, component: impl Component) -> Self { + self.children.add(Child::with(component)); + self + } + + /// Modifica la lista de componentes (`children`) aplicando una operación [`ChildOp`]. + #[builder_fn] + pub fn with_child(mut self, op: ChildOp) -> Self { + self.children.alter_child(op); + self + } + + // **< Intro GETTERS >************************************************************************** + + /// Devuelve el título de entrada. + pub fn title(&self) -> &L10n { + &self.title + } + + /// Devuelve el eslogan de la entrada. + pub fn slogan(&self) -> &L10n { + &self.slogan + } + + /// Devuelve el botón de llamada a la acción, si existe. + pub fn button(&self) -> Option<(&L10n, &FnPathByContext)> { + self.button.as_ref().map(|(txt, lnk)| (txt, lnk)) + } + + /// Devuelve el modo de apertura configurado. + pub fn opening(&self) -> IntroOpening { + self.opening + } + + /// Devuelve la lista de componentes (`children`) de la intro. + pub fn children(&self) -> &Children { + &self.children + } +} diff --git a/src/base/component/poweredby.rs b/src/base/component/poweredby.rs index bfe3835..51ab79d 100644 --- a/src/base/component/poweredby.rs +++ b/src/base/component/poweredby.rs @@ -1,7 +1,7 @@ use crate::prelude::*; // Enlace a la página oficial de PageTop. -const LINK: &str = "<a href=\"https://pagetop.cillero.es\" rel=\"noreferrer\">PageTop</a>"; +const LINK: &str = "<a href=\"https://pagetop.cillero.es\" rel=\"noopener noreferrer\">PageTop</a>"; /// Componente que renderiza la sección 'Powered by' (*Funciona con*) típica del pie de página. /// @@ -39,7 +39,7 @@ impl Component for PoweredBy { } impl PoweredBy { - // PoweredBy BUILDER *************************************************************************** + // **< PoweredBy BUILDER >********************************************************************** /// Establece el texto de copyright que mostrará el componente. /// @@ -47,8 +47,7 @@ impl PoweredBy { /// eliminará, pero en este caso es necesario especificar el tipo explícitamente: /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let p1 = PoweredBy::default().with_copyright(Some("2001 © Foo Inc.")); /// let p2 = PoweredBy::new().with_copyright(None::<String>); /// ``` @@ -58,7 +57,7 @@ impl PoweredBy { self } - // PoweredBy GETTERS *************************************************************************** + // **< PoweredBy GETTERS >********************************************************************** /// Devuelve el texto de copyright actual, si existe. pub fn copyright(&self) -> Option<&str> { diff --git a/src/base/extension/welcome.rs b/src/base/extension/welcome.rs index 5c6fec5..b875163 100644 --- a/src/base/extension/welcome.rs +++ b/src/base/extension/welcome.rs @@ -25,31 +25,29 @@ async fn homepage(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { let app = &global::SETTINGS.app.name; Page::new(request) - .with_theme("Basic") - .with_layout("PageTopIntro") .with_title(L10n::l("welcome_title")) - .with_description(L10n::l("welcome_intro").with_arg("app", app)) - .with_param("intro_button_txt", L10n::l("welcome_powered")) - .with_param("intro_button_lnk", "https://pagetop.cillero.es".to_string()) - .add_component( - Block::new() - .with_title(L10n::l("welcome_status_title")) - .add_component(Html::with(move |cx| { - html! { - p { (L10n::l("welcome_status_1").using(cx)) } - p { (L10n::l("welcome_status_2").using(cx)) } - } - })), - ) - .add_component( - Block::new() - .with_title(L10n::l("welcome_support_title")) - .add_component(Html::with(move |cx| { - html! { - p { (L10n::l("welcome_support_1").using(cx)) } - p { (L10n::l("welcome_support_2").with_arg("app", app).using(cx)) } - } - })), + .add_child( + Intro::new() + .add_child( + Block::new() + .with_title(L10n::l("welcome_status_title")) + .add_child(Html::with(move |cx| { + html! { + p { (L10n::l("welcome_status_1").using(cx)) } + p { (L10n::l("welcome_status_2").using(cx)) } + } + })), + ) + .add_child( + Block::new() + .with_title(L10n::l("welcome_support_title")) + .add_child(Html::with(move |cx| { + html! { + p { (L10n::l("welcome_support_1").using(cx)) } + p { (L10n::l("welcome_support_2").with_arg("app", app).using(cx)) } + } + })), + ), ) .render() } diff --git a/src/base/theme.rs b/src/base/theme.rs index 40129bf..1e5b1a8 100644 --- a/src/base/theme.rs +++ b/src/base/theme.rs @@ -1,4 +1,4 @@ //! Temas básicos soportados por PageTop. mod basic; -pub use basic::Basic; +pub use basic::{Basic, BasicRegions}; diff --git a/src/base/theme/basic.rs b/src/base/theme/basic.rs index 2f49274..2d713e3 100644 --- a/src/base/theme/basic.rs +++ b/src/base/theme/basic.rs @@ -1,33 +1,10 @@ /// Es el tema básico que incluye PageTop por defecto. use crate::prelude::*; -/// Tema básico por defecto. -/// -/// Ofrece las siguientes composiciones (*layouts*): -/// -/// - **Composición predeterminada** -/// - Renderizado genérico con -/// [`ThemePage::render_body()`](crate::core::theme::ThemePage::render_body) usando las regiones -/// predefinidas en [`page_regions()`](crate::core::theme::Theme::page_regions). -/// -/// - **`Intro`** -/// - Página de entrada con cabecera visual, título y descripción y un botón opcional de llamada a -/// la acción. Ideal para una página de inicio o bienvenida en el contexto de PageTop. -/// - **Regiones:** `content` (se renderiza dentro de `.intro-content__body`). -/// - **Parámetros:** -/// - `intro_button_txt` (`L10n`) – Texto del botón. -/// - `intro_button_lnk` (`Option<String>`) – URL del botón; si no se indica, el botón no se -/// muestra. -/// -/// - **`PageTopIntro`** -/// - Variante de `Intro` con textos predefinidos sobre PageTop al inicio del contenido. Añade una -/// banda de *badges* con la versión de [PageTop en crates.io](https://crates.io/crates/pagetop) -/// más la fecha de la última versión publicada y la licencia de uso. -/// - **Regiones:** `content` (igual que `Intro`). -/// - **Parámetros:** los mismos que `Intro`. -/// -/// **Nota:** si no se especifica `layout` o el valor no coincide con ninguno de los anteriores, se -/// aplica la composición predeterminada. +/// El tema básico usa las mismas regiones predefinidas por [`DefaultRegions`]. +pub type BasicRegions = DefaultRegions; + +/// Tema básico por defecto que extiende el funcionamiento predeterminado de [`Theme`]. pub struct Basic; impl Extension for Basic { @@ -37,152 +14,7 @@ impl Extension for Basic { } impl Theme for Basic { - fn render_page_body(&self, page: &mut Page) -> Markup { - match page.layout() { - "Intro" => render_intro(page), - "PageTopIntro" => render_pagetop_intro(page), - _ => <Self as ThemePage>::render_body(self, page, self.page_regions()), - } - } - - fn after_render_page_body(&self, page: &mut Page) { - let styles = match page.layout() { - "Intro" => "/css/intro.css", - "PageTopIntro" => "/css/intro.css", - _ => "/css/basic.css", - }; - page.alter_assets(AssetsOp::AddStyleSheet( - StyleSheet::from("/css/normalize.css") - .with_version("8.0.1") - .with_weight(-99), - )) - .alter_assets(AssetsOp::AddStyleSheet( - StyleSheet::from(styles) - .with_version(env!("CARGO_PKG_VERSION")) - .with_weight(-99), - )); + fn before_render_page_body(&self, page: &mut Page) { + page.alter_param("include_basic_assets", true); } } - -fn render_intro(page: &mut Page) -> Markup { - let title = page.title().unwrap_or_default(); - let intro = page.description().unwrap_or_default(); - - let intro_button_txt: L10n = page.param_or_default("intro_button_txt"); - let intro_button_lnk: Option<&String> = page.param("intro_button_lnk"); - - html! { - body id=[page.body_id().get()] class=[page.body_classes().get()] { - header class="intro-header" { - section class="intro-header__body" { - h1 class="intro-header__title" { - span { (title) } - (intro) - } - } - aside class="intro-header__image" aria-hidden="true" { - div class="intro-header__monster" { - picture { - source - type="image/avif" - src="/img/monster-pagetop_250.avif" - srcset="/img/monster-pagetop_500.avif 1.5x"; - source - type="image/webp" - src="/img/monster-pagetop_250.webp" - srcset="/img/monster-pagetop_500.webp 1.5x"; - img - src="/img/monster-pagetop_250.png" - srcset="/img/monster-pagetop_500.png 1.5x" - alt="Monster PageTop"; - } - } - } - } - main class="intro-content" { - section class="intro-content__body" { - @if intro_button_lnk.is_some() { - div class="intro-button" { - a - class="intro-button__link" - href=[intro_button_lnk] - target="_blank" - rel="noreferrer" - { - span {} span {} span {} - div class="intro-button__text" { - (intro_button_txt.using(page)) - } - } - } - } - div class="intro-text" { (page.render_region("content")) } - } - } - footer class="intro-footer" { - section class="intro-footer__body" { - div class="intro-footer__logo" { - svg - viewBox="0 0 1614 1614" - xmlns="http://www.w3.org/2000/svg" - role="img" - aria-label=[L10n::l("pagetop_logo").lookup(page)] - preserveAspectRatio="xMidYMid slice" - focusable="false" - { - path fill="rgb(255,255,255)" d="M 1573,357 L 1415,357 C 1400,357 1388,369 1388,383 L 1388,410 1335,410 1335,357 C 1335,167 1181,13 992,13 L 621,13 C 432,13 278,167 278,357 L 278,410 225,410 225,383 C 225,369 213,357 198,357 L 40,357 C 25,357 13,369 13,383 L 13,648 C 13,662 25,674 40,674 L 198,674 C 213,674 225,662 225,648 L 225,621 278,621 278,1256 C 278,1446 432,1600 621,1600 L 992,1600 C 1181,1600 1335,1446 1335,1256 L 1335,621 1388,621 1388,648 C 1388,662 1400,674 1415,674 L 1573,674 C 1588,674 1600,662 1600,648 L 1600,383 C 1600,369 1588,357 1573,357 L 1573,357 1573,357 Z M 66,410 L 172,410 172,621 66,621 66,410 66,410 Z M 1282,357 L 1282,488 C 1247,485 1213,477 1181,464 L 1196,437 C 1203,425 1199,409 1186,401 1174,394 1158,398 1150,411 L 1133,440 C 1105,423 1079,401 1056,376 L 1075,361 C 1087,352 1089,335 1079,324 1070,313 1054,311 1042,320 L 1023,335 C 1000,301 981,263 967,221 L 1011,196 C 1023,189 1028,172 1021,160 1013,147 997,143 984,150 L 953,168 C 945,136 941,102 940,66 L 992,66 C 1152,66 1282,197 1282,357 L 1282,357 1282,357 Z M 621,66 L 674,66 674,225 648,225 C 633,225 621,237 621,251 621,266 633,278 648,278 L 674,278 674,357 648,357 C 633,357 621,369 621,383 621,398 633,410 648,410 L 674,410 674,489 648,489 C 633,489 621,501 621,516 621,530 633,542 648,542 L 664,542 C 651,582 626,623 600,662 583,653 563,648 542,648 469,648 410,707 410,780 410,787 411,794 412,801 388,805 361,806 331,806 L 331,357 C 331,197 461,66 621,66 L 621,66 621,66 Z M 621,780 C 621,824 586,859 542,859 498,859 463,824 463,780 463,736 498,701 542,701 586,701 621,736 621,780 L 621,780 621,780 Z M 225,463 L 278,463 278,569 225,569 225,463 225,463 Z M 992,1547 L 621,1547 C 461,1547 331,1416 331,1256 L 331,859 C 367,859 400,858 431,851 454,888 495,912 542,912 615,912 674,853 674,780 674,747 662,718 642,695 675,645 706,594 720,542 L 780,542 C 795,542 807,530 807,516 807,501 795,489 780,489 L 727,489 727,410 780,410 C 795,410 807,398 807,383 807,369 795,357 780,357 L 727,357 727,278 780,278 C 795,278 807,266 807,251 807,237 795,225 780,225 L 727,225 727,66 887,66 C 889,111 895,155 905,196 L 869,217 C 856,224 852,240 859,253 864,261 873,266 882,266 887,266 891,265 895,263 L 921,248 C 937,291 958,331 983,367 L 938,403 C 926,412 925,429 934,440 939,447 947,450 954,450 960,450 966,448 971,444 L 1016,408 C 1043,438 1074,465 1108,485 L 1084,527 C 1076,539 1081,555 1093,563 1098,565 1102,566 1107,566 1116,566 1125,561 1129,553 L 1155,509 C 1194,527 1237,538 1282,541 L 1282,1256 C 1282,1416 1152,1547 992,1547 L 992,1547 992,1547 Z M 1335,463 L 1388,463 1388,569 1335,569 1335,463 1335,463 Z M 1441,410 L 1547,410 1547,621 1441,621 1441,410 1441,410 Z" {} - path fill="rgb(255,255,255)" d="M 1150,1018 L 463,1018 C 448,1018 436,1030 436,1044 L 436,1177 C 436,1348 545,1468 701,1468 L 912,1468 C 1068,1468 1177,1348 1177,1177 L 1177,1044 C 1177,1030 1165,1018 1150,1018 L 1150,1018 1150,1018 Z M 912,1071 L 1018,1071 1018,1124 912,1124 912,1071 912,1071 Z M 489,1071 L 542,1071 542,1124 489,1124 489,1071 489,1071 Z M 701,1415 L 700,1415 C 701,1385 704,1352 718,1343 731,1335 759,1341 795,1359 802,1363 811,1363 818,1359 854,1341 882,1335 895,1343 909,1352 912,1385 913,1415 L 912,1415 701,1415 701,1415 701,1415 Z M 1124,1177 C 1124,1296 1061,1384 966,1408 964,1365 958,1320 922,1298 894,1281 856,1283 807,1306 757,1283 719,1281 691,1298 655,1320 649,1365 647,1408 552,1384 489,1296 489,1177 L 569,1177 C 583,1177 595,1165 595,1150 L 595,1071 859,1071 859,1150 C 859,1165 871,1177 886,1177 L 1044,1177 C 1059,1177 1071,1165 1071,1150 L 1071,1071 1124,1071 1124,1177 1124,1177 1124,1177 Z" {} - path fill="rgb(255,255,255)" d="M 1071,648 C 998,648 939,707 939,780 939,853 998,912 1071,912 1144,912 1203,853 1203,780 1203,707 1144,648 1071,648 L 1071,648 1071,648 Z M 1071,859 C 1027,859 992,824 992,780 992,736 1027,701 1071,701 1115,701 1150,736 1150,780 1150,824 1115,859 1071,859 L 1071,859 1071,859 Z" {} - } - } - div class="intro-footer__links" { - a href="https://crates.io/crates/pagetop" target="_blank" rel="noreferrer" { ("Crates.io") } - a href="https://docs.rs/pagetop" target="_blank" rel="noreferrer" { ("Docs.rs") } - a href="https://git.cillero.es/manuelcillero/pagetop" target="_blank" rel="noreferrer" { (L10n::l("intro_code").using(page)) } - em { (L10n::l("intro_have_fun").using(page)) } - } - } - } - } - } -} - -fn render_pagetop_intro(page: &mut Page) -> Markup { - page.alter_assets(AssetsOp::AddJavaScript(JavaScript::on_load_async("intro-js", |cx| - util::indoc!(r#" - try { - const resp = await fetch("https://crates.io/api/v1/crates/pagetop"); - const data = await resp.json(); - const date = new Date(data.versions[0].created_at); - const formatted = date.toLocaleDateString("LANGID", { year: "numeric", month: "2-digit", day: "2-digit" }); - document.getElementById("intro-release").src = `https://img.shields.io/badge/Release%20date-${encodeURIComponent(formatted)}-blue?label=LABEL&style=for-the-badge`; - document.getElementById("intro-badges").style.display = "block"; - } catch (e) { - console.error("Failed to fetch release date from crates.io:", e); - } - "#) - .replace("LANGID", cx.langid().to_string().as_str()) - .replace("LABEL", L10n::l("intro_release_label").using(cx).as_str()) - .to_string(), - ))) - .alter_child_in("content", ChildOp::Prepend(Child::with(Html::with(|cx| html! { - p { (L10n::l("intro_text1").using(cx)) } - div id="intro-badges" style="display: none; margin-bottom: 1.1rem;" { - img - src="https://img.shields.io/crates/v/pagetop.svg?label=PageTop&style=for-the-badge" - alt=[L10n::l("intro_pagetop_label").lookup(cx)] {} (" ") - img - id="intro-release" - alt=[L10n::l("intro_release_label").lookup(cx)] {} (" ") - img - src=(format!( - "https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label={}&style=for-the-badge", - L10n::l("intro_license_label").lookup(cx).unwrap_or_default() - )) - alt=[L10n::l("intro_license_label").lookup(cx)] {} - } - p { (L10n::l("intro_text2").using(cx)) } - })))); - - render_intro(page) -} diff --git a/src/config.rs b/src/config.rs index f2fb9f7..1607a87 100644 --- a/src/config.rs +++ b/src/config.rs @@ -23,9 +23,9 @@ //! * Si `PAGETOP_RUN_MODE` no está definida, se asume el valor `default`, y PageTop intentará //! cargar *config/default.toml* si el archivo existe. //! -//! * Útil para definir configuraciones específicas por entorno, garantizando que cada uno (p.ej. -//! *dev*, *staging* o *production*) disponga de sus propias opciones, como claves de API, -//! URLs o ajustes de rendimiento, sin afectar a los demás. +//! * Permite definir configuraciones específicas por entorno, garantizando que cada uno (p. ej., +//! *dev*, *staging* o *production*) disponga de sus propias opciones, como claves de API, URLs +//! o ajustes de rendimiento, sin afectar a los demás. //! //! 3. **config/local.{rm}.toml**, útil para configuraciones locales específicas de la máquina o de //! la ejecución: @@ -132,15 +132,15 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( let config_dir = util::resolve_absolute_dir(&dir).unwrap_or_else(|_| PathBuf::from(&dir)); // Modo de ejecución según la variable de entorno PAGETOP_RUN_MODE. Si no está definida, se usa - // por defecto, DEFAULT_RUN_MODE (p.ej.: PAGETOP_RUN_MODE=production). + // por defecto DEFAULT_RUN_MODE (p. ej. PAGETOP_RUN_MODE=production). let rm = env::var("PAGETOP_RUN_MODE").unwrap_or_else(|_| DEFAULT_RUN_MODE.into()); Config::builder() // 1. Configuración común para todos los entornos (common.toml). .add_source(File::from(config_dir.join("common.toml")).required(false)) - // 2. Configuración específica del entorno (p.ej.: default.toml, production.toml). + // 2. Configuración específica del entorno (p. ej. default.toml o production.toml). .add_source(File::from(config_dir.join(format!("{rm}.toml"))).required(false)) - // 3. Configuración local reservada para cada entorno (p.ej.: local.default.toml). + // 3. Configuración local reservada para cada entorno (p. ej. local.default.toml). .add_source(File::from(config_dir.join(format!("local.{rm}.toml"))).required(false)) // 4. Configuración local común (local.toml). .add_source(File::from(config_dir.join("local.toml")).required(false)) @@ -206,7 +206,7 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( /// * **Valores por defecto**. Declara un valor por defecto para cada clave obligatoria. Las claves /// opcionales pueden ser `Option<T>`. /// -/// * **Secciones únicas**. Agrupa tus claves dentro de una sección exclusiva (p.ej. `[blog]`) para +/// * **Secciones únicas**. Agrupa tus claves dentro de una sección exclusiva (p. ej. `[blog]`) para /// evitar colisiones con otras librerías. /// /// * **Solo lectura**. La variable generada es inmutable durante toda la vida del programa. Para @@ -229,9 +229,7 @@ pub static CONFIG_VALUES: LazyLock<ConfigBuilder<DefaultState>> = LazyLock::new( macro_rules! include_config { ( $SETTINGS_NAME:ident : $Settings_Type:ty => [ $( $k:literal => $v:expr ),* $(,)? ] ) => { #[doc = concat!( - "Referencia y valores por defecto de los ajustes de configuración para [`", - stringify!($Settings_Type), - "`]." + "Instancia los ajustes de configuración para [`", stringify!($Settings_Type), "`]." )] #[doc = ""] #[doc = "Valores por defecto:"] diff --git a/src/core.rs b/src/core.rs index 79d9207..ab4d693 100644 --- a/src/core.rs +++ b/src/core.rs @@ -7,7 +7,7 @@ use std::any::Any; pub enum TypeInfo { /// Ruta completa tal y como la devuelve [`core::any::type_name`]. FullName, - /// Último segmento de la ruta – por ejemplo `Vec<i32>` en lugar de `alloc::vec::Vec<i32>`. + /// Último segmento de la ruta, por ejemplo `Vec<i32>` en lugar de `alloc::vec::Vec<i32>`. ShortName, /// Conserva todo **desde** `start` inclusive hasta el final. NameFrom(isize), @@ -122,8 +122,7 @@ impl TypeInfo { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let n = 3u32; /// assert_eq!(n.type_name(), "u32"); /// ``` diff --git a/src/core/action.rs b/src/core/action.rs index cbbe79c..9f81cd5 100644 --- a/src/core/action.rs +++ b/src/core/action.rs @@ -22,8 +22,7 @@ pub use all::dispatch_actions; /// # Ejemplo /// /// ```rust,ignore -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// impl Extension for MyTheme { /// fn actions(&self) -> Vec<ActionBox> { /// actions_boxed![ diff --git a/src/core/action/all.rs b/src/core/action/all.rs index 7fff970..fbbf842 100644 --- a/src/core/action/all.rs +++ b/src/core/action/all.rs @@ -5,12 +5,12 @@ use parking_lot::RwLock; use std::collections::HashMap; use std::sync::LazyLock; -// ACCIONES **************************************************************************************** +// **< ACCIONES >*********************************************************************************** static ACTIONS: LazyLock<RwLock<HashMap<ActionKey, ActionsList>>> = LazyLock::new(|| RwLock::new(HashMap::new())); -// AÑADIR ACCIONES ********************************************************************************* +// **< AÑADIR ACCIONES >**************************************************************************** // Registra una nueva acción en el sistema. // @@ -36,7 +36,7 @@ pub fn add_action(action: ActionBox) { } } -// DESPLEGAR ACCIONES ****************************************************************************** +// **< DESPLEGAR ACCIONES >************************************************************************* /// Despacha y ejecuta las funciones asociadas a una [`ActionKey`]. /// diff --git a/src/core/action/definition.rs b/src/core/action/definition.rs index 9ec9af1..7ebe410 100644 --- a/src/core/action/definition.rs +++ b/src/core/action/definition.rs @@ -24,7 +24,8 @@ impl ActionKey { /// - `action_type_id`: Tipo de la acción. /// - `theme_type_id`: Opcional, identificador de tipo ([`UniqueId`]) del tema asociado. /// - `referer_type_id`: Opcional, identificador de tipo ([`UniqueId`]) del componente referido. - /// - `referer_id`: Opcional, identificador de la instancia (p.ej. para un formulario concreto). + /// - `referer_id`: Opcional, identificador de la instancia (p. ej. para asociar la acción a un + /// componente concreto). /// /// Esta clave permitirá seleccionar las funciones a ejecutar para ese tipo de acción, con /// filtros opcionales por tema, componente, o una instancia concreta según su identificador. diff --git a/src/core/component.rs b/src/core/component.rs index 3691472..9c9ade2 100644 --- a/src/core/component.rs +++ b/src/core/component.rs @@ -8,5 +8,64 @@ pub use children::Children; pub use children::{Child, ChildOp}; pub use children::{Typed, TypedOp}; -mod slot; -pub use slot::TypedSlot; +mod context; +pub use context::{Context, ContextError, ContextOp, Contextual}; + +/// Alias de función (*callback*) para **determinar si un componente se renderiza o no**. +/// +/// Puede usarse para permitir que una instancia concreta de un tipo de componente dado decida +/// dinámicamente durante el proceso de renderizado ([`Component::is_renderable()`]) si se renderiza +/// o no. +/// +/// # Ejemplo +/// +/// ```rust +/// # use pagetop::prelude::*; +/// #[derive(AutoDefault)] +/// struct SampleComponent { +/// renderable: Option<FnIsRenderable>, +/// } +/// +/// impl Component for SampleComponent { +/// fn new() -> Self { +/// Self::default() +/// } +/// +/// fn is_renderable(&self, cx: &mut Context) -> bool { +/// // Si hay callback, se usa; en caso contrario, se renderiza por defecto. +/// self.renderable.map_or(true, |f| f(cx)) +/// } +/// +/// fn prepare_component(&self, _cx: &mut Context) -> PrepareMarkup { +/// PrepareMarkup::Escaped("Visible component".into()) +/// } +/// } +/// +/// impl SampleComponent { +/// /// Asigna una función que decidirá si el componente se renderiza o no. +/// #[builder_fn] +/// pub fn with_renderable(mut self, f: Option<FnIsRenderable>) -> Self { +/// self.renderable = f; +/// self +/// } +/// } +/// +/// fn sample() { +/// let mut cx = Context::default().with_param("user_logged_in", true); +/// +/// // Se instancia un componente que sólo se renderiza si `user_logged_in` es `true`. +/// let mut component = SampleComponent::new().with_renderable(Some(|cx: &Context| { +/// cx.param::<bool>("user_logged_in").copied().unwrap_or(false) +/// })); +/// +/// // Aquí simplemente se comprueba que compila y se puede invocar. +/// let _markup = component.render(&mut cx); +/// } +/// ``` +pub type FnIsRenderable = fn(cx: &Context) -> bool; + +/// Alias de función (*callback*) para **resolver una URL** según el contexto de renderizado. +/// +/// Se usa para generar enlaces dinámicos en función del contexto (petición, idioma, etc.). Debe +/// devolver una referencia válida durante el renderizado. +pub type FnPathByContext = fn(cx: &Context) -> &str; diff --git a/src/core/component/children.rs b/src/core/component/children.rs index cb112e1..3b8f2ab 100644 --- a/src/core/component/children.rs +++ b/src/core/component/children.rs @@ -1,9 +1,12 @@ -use crate::core::component::Component; -use crate::html::{html, Context, Markup}; -use crate::{builder_fn, UniqueId}; +use crate::core::component::{Component, Context}; +use crate::html::{html, Markup}; +use crate::{builder_fn, AutoDefault, UniqueId}; use parking_lot::RwLock; +pub use parking_lot::RwLockReadGuard as ComponentReadGuard; +pub use parking_lot::RwLockWriteGuard as ComponentWriteGuard; + use std::sync::Arc; use std::vec::IntoIter; @@ -11,87 +14,169 @@ use std::vec::IntoIter; /// /// Esta estructura permite manipular y renderizar un componente que implemente [`Component`], y /// habilita acceso concurrente mediante [`Arc<RwLock<_>>`]. -#[derive(Clone)] -pub struct Child(Arc<RwLock<dyn Component>>); +#[derive(AutoDefault, Clone)] +pub struct Child(Option<Arc<RwLock<dyn Component>>>); impl Child { /// Crea un nuevo `Child` a partir de un componente. pub fn with(component: impl Component) -> Self { - Child(Arc::new(RwLock::new(component))) + Child(Some(Arc::new(RwLock::new(component)))) } - // Child GETTERS ******************************************************************************* + // **< Child BUILDER >************************************************************************** - /// Devuelve el identificador del componente, si está definido. + /// Establece un componente nuevo, o lo vacía. + /// + /// Si se proporciona `Some(component)`, se encapsula como [`Child`]; y si es `None`, se limpia. + #[builder_fn] + pub fn with_component<C: Component>(mut self, component: Option<C>) -> Self { + if let Some(c) = component { + self.0 = Some(Arc::new(RwLock::new(c))); + } else { + self.0 = None; + } + self + } + + // **< Child GETTERS >************************************************************************** + + /// Devuelve el identificador del componente, si existe y está definido. + #[inline] pub fn id(&self) -> Option<String> { - self.0.read().id() + self.0.as_ref().and_then(|c| c.read().id()) } - // Child RENDER ******************************************************************************** + // **< Child RENDER >*************************************************************************** /// Renderiza el componente con el contexto proporcionado. pub fn render(&self, cx: &mut Context) -> Markup { - self.0.write().render(cx) + self.0.as_ref().map_or(html! {}, |c| c.write().render(cx)) } - // Child HELPERS ******************************************************************************* + // **< Child HELPERS >************************************************************************** - // Devuelve el [`UniqueId`] del tipo del componente. - fn type_id(&self) -> UniqueId { - self.0.read().type_id() + // Devuelve el [`UniqueId`] del tipo del componente, si existe. + #[inline] + fn type_id(&self) -> Option<UniqueId> { + self.0.as_ref().map(|c| c.read().type_id()) } } // ************************************************************************************************* -/// Variante tipada de [`Child`] para evitar conversiones durante el uso. +/// Variante tipada de [`Child`] para evitar conversiones de tipo durante el uso. /// /// Esta estructura permite manipular y renderizar un componente concreto que implemente /// [`Component`], y habilita acceso concurrente mediante [`Arc<RwLock<_>>`]. -pub struct Typed<C: Component>(Arc<RwLock<C>>); - -impl<C: Component> Clone for Typed<C> { - fn clone(&self) -> Self { - Self(self.0.clone()) - } -} +#[derive(AutoDefault, Clone)] +pub struct Typed<C: Component>(Option<Arc<RwLock<C>>>); impl<C: Component> Typed<C> { /// Crea un nuevo `Typed` a partir de un componente. pub fn with(component: C) -> Self { - Typed(Arc::new(RwLock::new(component))) + Typed(Some(Arc::new(RwLock::new(component)))) } - // Typed GETTERS ******************************************************************************* + // **< Typed BUILDER >************************************************************************** - /// Devuelve el identificador del componente, si está definido. + /// Establece un componente nuevo, o lo vacía. + /// + /// Si se proporciona `Some(component)`, se encapsula como [`Typed`]; y si es `None`, se limpia. + #[builder_fn] + pub fn with_component(mut self, component: Option<C>) -> Self { + self.0 = component.map(|c| Arc::new(RwLock::new(c))); + self + } + + // **< Typed GETTERS >************************************************************************** + + /// Devuelve el identificador del componente, si existe y está definido. + #[inline] pub fn id(&self) -> Option<String> { - self.0.read().id() + self.0.as_ref().and_then(|c| c.read().id()) } - // Typed RENDER ******************************************************************************** + /// Devuelve una **referencia inmutable** al componente interno. + /// + /// - Devuelve `Some(ComponentReadGuard<C>)` si existe el componente, o `None` si está vacío. + /// - Permite realizar **múltiples lecturas concurrentes**. + /// - Mientras el *guard* esté activo, no se pueden realizar escrituras concurrentes (ver + /// [`borrow_mut`](Self::borrow_mut)). + /// - Se recomienda mantener el *guard* **el menor tiempo posible** para evitar bloqueos + /// innecesarios. + /// + /// # Ejemplo + /// + /// Lectura del nombre del componente: + /// + /// ```rust + /// # use pagetop::prelude::*; + /// let typed = Typed::with(Html::with(|_| html! { "Prueba" })); + /// { + /// if let Some(component) = typed.borrow() { + /// assert_eq!(component.name(), "Html"); + /// } + /// }; // El *guard* se libera aquí, antes del *drop* de `typed`. + /// ``` + pub fn borrow(&self) -> Option<ComponentReadGuard<'_, C>> { + self.0.as_ref().map(|a| a.read()) + } + + /// Obtiene una **referencia mutable exclusiva** al componente interno. + /// + /// - Devuelve `Some(ComponentWriteGuard<C>)` si existe el componente, o `None` si está vacío. + /// - **Exclusivo**: mientras el *guard* esté activo, no habrá otros lectores ni escritores. + /// - Usar sólo para operaciones que **modifican** el estado interno. + /// - Igual que con [`borrow`](Self::borrow), se recomienda mantener el *guard* en un **ámbito + /// reducido**. + /// + /// # Ejemplo + /// + /// Acceso mutable (ámbito corto): + /// + /// ```rust + /// # use pagetop::prelude::*; + /// let typed = Typed::with(Block::new().with_title(L10n::n("Título"))); + /// { + /// if let Some(mut component) = typed.borrow_mut() { + /// component.alter_title(L10n::n("Nuevo título")); + /// } + /// }; // El *guard* se libera aquí, antes del *drop* de `typed`. + /// ``` + pub fn borrow_mut(&self) -> Option<ComponentWriteGuard<'_, C>> { + self.0.as_ref().map(|a| a.write()) + } + + // **< Typed RENDER >*************************************************************************** /// Renderiza el componente con el contexto proporcionado. pub fn render(&self, cx: &mut Context) -> Markup { - self.0.write().render(cx) + self.0.as_ref().map_or(html! {}, |c| c.write().render(cx)) } - // Typed HELPERS ******************************************************************************* + // **< Typed HELPERS >************************************************************************** - // Convierte el componente tipado en un [`Child`]. - fn into_child(self) -> Child { - Child(self.0.clone()) + // Método interno para convertir un componente tipado en un [`Child`]. + #[inline] + fn into(self) -> Child { + if let Some(c) = &self.0 { + Child(Some(c.clone())) + } else { + Child(None) + } } } // ************************************************************************************************* -/// Operaciones con un componente hijo [`Child`] en una lista [`Children`]. +/// Operaciones para componentes hijo [`Child`] en una lista [`Children`]. pub enum ChildOp { Add(Child), + AddMany(Vec<Child>), InsertAfterId(&'static str, Child), InsertBeforeId(&'static str, Child), Prepend(Child), + PrependMany(Vec<Child>), RemoveById(&'static str), ReplaceById(&'static str, Child), Reset, @@ -100,9 +185,11 @@ pub enum ChildOp { /// Operaciones con un componente hijo tipado [`Typed<C>`] en una lista [`Children`]. pub enum TypedOp<C: Component> { Add(Typed<C>), + AddMany(Vec<Typed<C>>), InsertAfterId(&'static str, Typed<C>), InsertBeforeId(&'static str, Typed<C>), Prepend(Typed<C>), + PrependMany(Vec<Typed<C>>), RemoveById(&'static str), ReplaceById(&'static str, Typed<C>), Reset, @@ -136,16 +223,18 @@ impl Children { opt } - // Children BUILDER **************************************************************************** + // **< Children BUILDER >*********************************************************************** /// Ejecuta una operación con [`ChildOp`] en la lista. #[builder_fn] pub fn with_child(mut self, op: ChildOp) -> Self { match op { ChildOp::Add(any) => self.add(any), + ChildOp::AddMany(many) => self.add_many(many), ChildOp::InsertAfterId(id, any) => self.insert_after_id(id, any), ChildOp::InsertBeforeId(id, any) => self.insert_before_id(id, any), ChildOp::Prepend(any) => self.prepend(any), + ChildOp::PrependMany(many) => self.prepend_many(many), ChildOp::RemoveById(id) => self.remove_by_id(id), ChildOp::ReplaceById(id, any) => self.replace_by_id(id, any), ChildOp::Reset => self.reset(), @@ -154,14 +243,16 @@ impl Children { /// Ejecuta una operación con [`TypedOp`] en la lista. #[builder_fn] - pub fn with_typed<C: Component + Default>(mut self, op: TypedOp<C>) -> Self { + pub fn with_typed<C: Component>(mut self, op: TypedOp<C>) -> Self { match op { - TypedOp::Add(typed) => self.add(typed.into_child()), - TypedOp::InsertAfterId(id, typed) => self.insert_after_id(id, typed.into_child()), - TypedOp::InsertBeforeId(id, typed) => self.insert_before_id(id, typed.into_child()), - TypedOp::Prepend(typed) => self.prepend(typed.into_child()), + TypedOp::Add(typed) => self.add(typed.into()), + TypedOp::AddMany(many) => self.add_many(many.into_iter().map(Typed::<C>::into)), + TypedOp::InsertAfterId(id, typed) => self.insert_after_id(id, typed.into()), + TypedOp::InsertBeforeId(id, typed) => self.insert_before_id(id, typed.into()), + TypedOp::Prepend(typed) => self.prepend(typed.into()), + TypedOp::PrependMany(many) => self.prepend_many(many.into_iter().map(Typed::<C>::into)), TypedOp::RemoveById(id) => self.remove_by_id(id), - TypedOp::ReplaceById(id, typed) => self.replace_by_id(id, typed.into_child()), + TypedOp::ReplaceById(id, typed) => self.replace_by_id(id, typed.into()), TypedOp::Reset => self.reset(), } } @@ -175,7 +266,7 @@ impl Children { self } - // Children GETTERS **************************************************************************** + // **< Children GETTERS >*********************************************************************** /// Devuelve el número de componentes hijo de la lista. pub fn len(&self) -> usize { @@ -201,10 +292,10 @@ impl Children { /// Devuelve un iterador sobre los componentes hijo con el identificador de tipo ([`UniqueId`]) /// indicado. pub fn iter_by_type_id(&self, type_id: UniqueId) -> impl Iterator<Item = &Child> { - self.0.iter().filter(move |&c| c.type_id() == type_id) + self.0.iter().filter(move |c| c.type_id() == Some(type_id)) } - // Children RENDER ***************************************************************************** + // **< Children RENDER >************************************************************************ /// Renderiza todos los componentes hijo, en orden. pub fn render(&self, cx: &mut Context) -> Markup { @@ -215,7 +306,17 @@ impl Children { } } - // Children HELPERS **************************************************************************** + // **< Children HELPERS >*********************************************************************** + + // Añade más de un componente hijo al final de la lista (en el orden recibido). + #[inline] + fn add_many<I>(&mut self, iter: I) -> &mut Self + where + I: IntoIterator<Item = Child>, + { + self.0.extend(iter); + self + } // Inserta un hijo después del componente con el `id` dado, o al final si no se encuentra. #[inline] @@ -246,6 +347,17 @@ impl Children { self } + // Inserta más de un componente hijo al principio de la lista (manteniendo el orden recibido). + #[inline] + fn prepend_many<I>(&mut self, iter: I) -> &mut Self + where + I: IntoIterator<Item = Child>, + { + let buf: Vec<Child> = iter.into_iter().collect(); + self.0.splice(0..0, buf); + self + } + // Elimina el primer hijo con el `id` dado. #[inline] fn remove_by_id(&mut self, id: impl AsRef<str>) -> &mut Self { diff --git a/src/html/context.rs b/src/core/component/context.rs similarity index 81% rename from src/html/context.rs rename to src/core/component/context.rs index 7b78268..8c4e47e 100644 --- a/src/html/context.rs +++ b/src/core/component/context.rs @@ -1,5 +1,6 @@ +use crate::core::component::ChildOp; use crate::core::theme::all::{theme_by_short_name, DEFAULT_THEME}; -use crate::core::theme::ThemeRef; +use crate::core::theme::{ChildrenInRegions, ThemeRef}; use crate::core::TypeInfo; use crate::html::{html, Markup}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; @@ -10,8 +11,8 @@ use crate::{builder_fn, join}; use std::any::Any; use std::collections::HashMap; -/// Operaciones para modificar el contexto ([`Context`]) de un documento. -pub enum AssetsOp { +/// Operaciones para modificar recursos asociados al contexto ([`Context`]) de un documento. +pub enum ContextOp { // Favicon. /// Define el *favicon* del documento. Sobrescribe cualquier valor anterior. SetFavicon(Option<Favicon>), @@ -33,14 +34,14 @@ pub enum AssetsOp { /// Errores de acceso a parámetros dinámicos del contexto. /// -/// - [`ErrorParam::NotFound`]: la clave no existe. -/// - [`ErrorParam::TypeMismatch`]: la clave existe, pero el valor guardado no coincide con el tipo -/// solicitado. Incluye nombre de la clave (`key`), tipo esperado (`expected`) y tipo realmente -/// guardado (`saved`) para facilitar el diagnóstico. +/// - [`ContextError::ParamNotFound`]: la clave no existe. +/// - [`ContextError::ParamTypeMismatch`]: la clave existe, pero el valor guardado no coincide con +/// el tipo solicitado. Incluye nombre de la clave (`key`), tipo esperado (`expected`) y tipo +/// realmente guardado (`saved`) para facilitar el diagnóstico. #[derive(Debug)] -pub enum ErrorParam { - NotFound, - TypeMismatch { +pub enum ContextError { + ParamNotFound, + ParamTypeMismatch { key: &'static str, expected: &'static str, saved: &'static str, @@ -55,30 +56,29 @@ pub enum ErrorParam { /// - Almacenar la **solicitud HTTP** de origen. /// - Seleccionar **tema** y **composición** (*layout*) de renderizado. /// - Administrar **recursos** del documento como el icono [`Favicon`], las hojas de estilo -/// [`StyleSheet`] o los scripts [`JavaScript`] mediante [`AssetsOp`]. +/// [`StyleSheet`] o los scripts [`JavaScript`] mediante [`ContextOp`]. /// - Leer y mantener **parámetros dinámicos tipados** de contexto. /// - Generar **identificadores únicos** por tipo de componente. /// /// Lo implementan, típicamente, estructuras que representan el contexto de renderizado, como -/// [`Context`](crate::html::Context) o [`Page`](crate::response::page::Page). +/// [`Context`](crate::core::component::Context) o [`Page`](crate::response::page::Page). /// /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// fn prepare_context<C: Contextual>(cx: C) -> C { /// cx.with_langid(&LangMatch::resolve("es-ES")) /// .with_theme("aliner") /// .with_layout("default") -/// .with_assets(AssetsOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) -/// .with_assets(AssetsOp::AddStyleSheet(StyleSheet::from("/css/app.css"))) -/// .with_assets(AssetsOp::AddJavaScript(JavaScript::defer("/js/app.js"))) +/// .with_assets(ContextOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) +/// .with_assets(ContextOp::AddStyleSheet(StyleSheet::from("/css/app.css"))) +/// .with_assets(ContextOp::AddJavaScript(JavaScript::defer("/js/app.js"))) /// .with_param("usuario_id", 42_i32) /// } /// ``` pub trait Contextual: LangId { - // Contextual BUILDER ************************************************************************** + // **< Contextual BUILDER >********************************************************************* /// Establece el idioma del documento. #[builder_fn] @@ -100,11 +100,15 @@ pub trait Contextual: LangId { #[builder_fn] fn with_param<T: 'static>(self, key: &'static str, value: T) -> Self; - /// Define los recursos del contexto usando [`AssetsOp`]. + /// Define los recursos del contexto usando [`ContextOp`]. #[builder_fn] - fn with_assets(self, op: AssetsOp) -> Self; + fn with_assets(self, op: ContextOp) -> Self; - // Contextual GETTERS ************************************************************************** + /// Opera con [`ChildOp`] en una región (`region_key`) de la página. + #[builder_fn] + fn with_child_in(self, region_key: &'static str, op: ChildOp) -> Self; + + // **< Contextual GETTERS >********************************************************************* /// Devuelve una referencia a la solicitud HTTP asociada, si existe. fn request(&self) -> Option<&HttpRequest>; @@ -142,7 +146,7 @@ pub trait Contextual: LangId { /// Devuelve los scripts JavaScript de los recursos del contexto. fn javascripts(&self) -> &Assets<JavaScript>; - // Contextual HELPERS ************************************************************************** + // **< Contextual HELPERS >********************************************************************* /// Genera un identificador único por tipo (`<tipo>-<n>`) cuando no se aporta uno explícito. /// @@ -163,8 +167,7 @@ pub trait Contextual: LangId { /// Crea un nuevo contexto asociado a una solicitud HTTP: /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// fn new_context(request: HttpRequest) -> Context { /// Context::new(Some(request)) /// // Establece el idioma del documento a español. @@ -172,11 +175,11 @@ pub trait Contextual: LangId { /// // Selecciona un tema (por su nombre corto). /// .with_theme("aliner") /// // Asigna un favicon. -/// .with_assets(AssetsOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) +/// .with_assets(ContextOp::SetFavicon(Some(Favicon::new().with_icon("/favicon.ico")))) /// // Añade una hoja de estilo externa. -/// .with_assets(AssetsOp::AddStyleSheet(StyleSheet::from("/css/style.css"))) +/// .with_assets(ContextOp::AddStyleSheet(StyleSheet::from("/css/style.css"))) /// // Añade un script JavaScript. -/// .with_assets(AssetsOp::AddJavaScript(JavaScript::defer("/js/main.js"))) +/// .with_assets(ContextOp::AddJavaScript(JavaScript::defer("/js/main.js"))) /// // Añade un parámetro dinámico al contexto. /// .with_param("usuario_id", 42) /// } @@ -185,8 +188,7 @@ pub trait Contextual: LangId { /// Y hace operaciones con un contexto dado: /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// fn use_context(cx: &mut Context) { /// // Recupera el tema seleccionado. /// let active_theme = cx.theme(); @@ -211,6 +213,7 @@ pub struct Context { favicon : Option<Favicon>, // Favicon, si se ha definido. stylesheets: Assets<StyleSheet>, // Hojas de estilo CSS. javascripts: Assets<JavaScript>, // Scripts JavaScript. + regions : ChildrenInRegions, // Regiones de componentes para renderizar. params : HashMap<&'static str, (Box<dyn Any>, &'static str)>, // Parámetros en ejecución. id_counter : usize, // Contador para generar identificadores únicos. } @@ -250,12 +253,13 @@ impl Context { favicon : None, stylesheets: Assets::<StyleSheet>::new(), javascripts: Assets::<JavaScript>::new(), + regions : ChildrenInRegions::default(), params : HashMap::default(), id_counter : 0, } } - // Context RENDER ****************************************************************************** + // **< Context RENDER >************************************************************************* /// Renderiza los recursos del contexto. pub fn render_assets(&mut self) -> Markup { @@ -283,21 +287,27 @@ impl Context { markup } - // Context PARAMS ****************************************************************************** + /// Renderiza los componentes de una región (`region_key`). + pub fn render_components_of(&mut self, region_key: &'static str) -> Markup { + self.regions + .merge_all_components(self.theme, region_key) + .render(self) + } + + // **< Context PARAMS >************************************************************************* /// Recupera una *referencia tipada* al parámetro solicitado. /// /// Devuelve: /// /// - `Ok(&T)` si la clave existe y el tipo coincide. - /// - `Err(ErrorParam::NotFound)` si la clave no existe. - /// - `Err(ErrorParam::TypeMismatch)` si la clave existe pero el tipo no coincide. + /// - `Err(ContextError::ParamNotFound)` si la clave no existe. + /// - `Err(ContextError::ParamTypeMismatch)` si la clave existe pero el tipo no coincide. /// /// # Ejemplos /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let cx = Context::new(None) /// .with_param("usuario_id", 42_i32) /// .with_param("titulo", "Hola".to_string()); @@ -308,10 +318,10 @@ impl Context { /// // Error de tipo: /// assert!(cx.get_param::<String>("usuario_id").is_err()); /// ``` - pub fn get_param<T: 'static>(&self, key: &'static str) -> Result<&T, ErrorParam> { - let (any, type_name) = self.params.get(key).ok_or(ErrorParam::NotFound)?; + pub fn get_param<T: 'static>(&self, key: &'static str) -> Result<&T, ContextError> { + let (any, type_name) = self.params.get(key).ok_or(ContextError::ParamNotFound)?; any.downcast_ref::<T>() - .ok_or_else(|| ErrorParam::TypeMismatch { + .ok_or_else(|| ContextError::ParamTypeMismatch { key, expected: TypeInfo::FullName.of::<T>(), saved: type_name, @@ -323,14 +333,13 @@ impl Context { /// Devuelve: /// /// - `Ok(T)` si la clave existía y el tipo coincide. - /// - `Err(ErrorParam::NotFound)` si la clave no existe. - /// - `Err(ErrorParam::TypeMismatch)` si el tipo no coincide. + /// - `Err(ContextError::ParamNotFound)` si la clave no existe. + /// - `Err(ContextError::ParamTypeMismatch)` si el tipo no coincide. /// /// # Ejemplos /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let mut cx = Context::new(None) /// .with_param("contador", 7_i32) /// .with_param("titulo", "Hola".to_string()); @@ -341,12 +350,12 @@ impl Context { /// // Error de tipo: /// assert!(cx.take_param::<i32>("titulo").is_err()); /// ``` - pub fn take_param<T: 'static>(&mut self, key: &'static str) -> Result<T, ErrorParam> { - let (boxed, saved) = self.params.remove(key).ok_or(ErrorParam::NotFound)?; + pub fn take_param<T: 'static>(&mut self, key: &'static str) -> Result<T, ContextError> { + let (boxed, saved) = self.params.remove(key).ok_or(ContextError::ParamNotFound)?; boxed .downcast::<T>() .map(|b| *b) - .map_err(|_| ErrorParam::TypeMismatch { + .map_err(|_| ContextError::ParamTypeMismatch { key, expected: TypeInfo::FullName.of::<T>(), saved, @@ -360,8 +369,7 @@ impl Context { /// # Ejemplos /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let mut cx = Context::new(None).with_param("temp", 1u8); /// assert!(cx.remove_param("temp")); /// assert!(!cx.remove_param("temp")); // ya no existe @@ -371,7 +379,7 @@ impl Context { } } -/// Permite a [`Context`](crate::html::Context) actuar como proveedor de idioma. +/// Permite a [`Context`](crate::core::component::Context) actuar como proveedor de idioma. /// /// Devuelve un [`LanguageIdentifier`] siguiendo este orden de prioridad: /// @@ -389,7 +397,7 @@ impl LangId for Context { } impl Contextual for Context { - // Contextual BUILDER ************************************************************************** + // **< Contextual BUILDER >********************************************************************* #[builder_fn] fn with_request(mut self, request: Option<HttpRequest>) -> Self { @@ -427,8 +435,7 @@ impl Contextual for Context { /// # Ejemplos /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let cx = Context::new(None) /// .with_param("usuario_id", 42_i32) /// .with_param("titulo", "Hola".to_string()) @@ -442,36 +449,42 @@ impl Contextual for Context { } #[builder_fn] - fn with_assets(mut self, op: AssetsOp) -> Self { + fn with_assets(mut self, op: ContextOp) -> Self { match op { // Favicon. - AssetsOp::SetFavicon(favicon) => { + ContextOp::SetFavicon(favicon) => { self.favicon = favicon; } - AssetsOp::SetFaviconIfNone(icon) => { + ContextOp::SetFaviconIfNone(icon) => { if self.favicon.is_none() { self.favicon = Some(icon); } } // Stylesheets. - AssetsOp::AddStyleSheet(css) => { + ContextOp::AddStyleSheet(css) => { self.stylesheets.add(css); } - AssetsOp::RemoveStyleSheet(path) => { + ContextOp::RemoveStyleSheet(path) => { self.stylesheets.remove(path); } // JavaScripts. - AssetsOp::AddJavaScript(js) => { + ContextOp::AddJavaScript(js) => { self.javascripts.add(js); } - AssetsOp::RemoveJavaScript(path) => { + ContextOp::RemoveJavaScript(path) => { self.javascripts.remove(path); } } self } - // Contextual GETTERS ************************************************************************** + #[builder_fn] + fn with_child_in(mut self, region_key: &'static str, op: ChildOp) -> Self { + self.regions.alter_child_in(region_key, op); + self + } + + // **< Contextual GETTERS >********************************************************************* fn request(&self) -> Option<&HttpRequest> { self.request.as_ref() @@ -497,8 +510,7 @@ impl Contextual for Context { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let cx = Context::new(None).with_param("username", "Alice".to_string()); /// /// // Devuelve Some(&String) si existe y coincide el tipo. @@ -530,7 +542,7 @@ impl Contextual for Context { &self.javascripts } - // Contextual HELPERS ************************************************************************** + // **< Contextual HELPERS >********************************************************************* /// Devuelve un identificador único dentro del contexto para el tipo `T`, si no se proporciona /// un `id` explícito. diff --git a/src/core/component/definition.rs b/src/core/component/definition.rs index 333cf69..13b0385 100644 --- a/src/core/component/definition.rs +++ b/src/core/component/definition.rs @@ -1,6 +1,7 @@ use crate::base::action; +use crate::core::component::Context; use crate::core::{AnyInfo, TypeInfo}; -use crate::html::{html, Context, Markup, PrepareMarkup}; +use crate::html::{html, Markup, PrepareMarkup}; /// Define la función de renderizado para todos los componentes. /// @@ -44,6 +45,20 @@ pub trait Component: AnyInfo + ComponentRender + Send + Sync { None } + /// Indica si el componente es renderizable. + /// + /// Por defecto, todos los componentes son renderizables (`true`). Sin embargo, este método + /// puede sobrescribirse para decidir dinámicamente si los componentes de este tipo se + /// renderizan o no en función del contexto de renderizado. + /// + /// También puede usarse junto con un alias de función como + /// ([`FnIsRenderable`](crate::core::component::FnIsRenderable)) para permitir que instancias + /// concretas del componente decidan si se renderizan o no. + #[allow(unused_variables)] + fn is_renderable(&self, cx: &mut Context) -> bool { + true + } + /// Configura el componente justo antes de preparar el renderizado. /// /// Este método puede sobrescribirse para modificar la estructura interna del componente o el @@ -71,30 +86,30 @@ pub trait Component: AnyInfo + ComponentRender + Send + Sync { /// Implementa [`render()`](ComponentRender::render) para todos los componentes. /// -/// Y para cada componente ejecuta la siguiente secuencia: +/// El proceso de renderizado de cada componente sigue esta secuencia: /// -/// 1. Despacha [`action::component::IsRenderable`](crate::base::action::component::IsRenderable) -/// para ver si se puede renderizar. Si no es así, devuelve un [`Markup`] vacío. +/// 1. Ejecuta [`is_renderable()`](Component::is_renderable) para ver si puede renderizarse en el +/// contexto actual. Si no es así, devuelve un [`Markup`] vacío. /// 2. Ejecuta [`setup_before_prepare()`](Component::setup_before_prepare) para que el componente /// pueda ajustar su estructura interna o modificar el contexto. /// 3. Despacha [`action::theme::BeforeRender<C>`](crate::base::action::theme::BeforeRender) para -/// que el tema pueda hacer ajustes en el componente o el contexto. +/// permitir que el tema realice ajustes previos. /// 4. Despacha [`action::component::BeforeRender<C>`](crate::base::action::component::BeforeRender) -/// para que otras extensiones puedan hacer ajustes. +/// para que otras extensiones puedan también hacer ajustes previos. /// 5. **Prepara el renderizado del componente**: /// - Despacha [`action::theme::PrepareRender<C>`](crate::base::action::theme::PrepareRender) -/// para permitir al tema preparar un renderizado diferente al predefinido. -/// - Si no es así, ejecuta [`prepare_component()`](Component::prepare_component) para preparar -/// el renderizado predefinido del componente. +/// para permitir al tema generar un renderizado alternativo. +/// - Si el tema no lo modifica, llama a [`prepare_component()`](Component::prepare_component) +/// para obtener el renderizado por defecto del componente. /// 6. Despacha [`action::theme::AfterRender<C>`](crate::base::action::theme::AfterRender) para -/// que el tema pueda hacer sus últimos ajustes. +/// que el tema pueda aplicar ajustes finales. /// 7. Despacha [`action::component::AfterRender<C>`](crate::base::action::component::AfterRender) /// para que otras extensiones puedan hacer sus últimos ajustes. -/// 8. Finalmente devuelve un [`Markup`] del renderizado preparado en el paso 5. +/// 8. Devuelve el [`Markup`] generado en el paso 5. impl<C: Component> ComponentRender for C { fn render(&mut self, cx: &mut Context) -> Markup { // Si no es renderizable, devuelve un bloque HTML vacío. - if !action::component::IsRenderable::dispatch(self, cx) { + if !self.is_renderable(cx) { return html! {}; } diff --git a/src/core/component/slot.rs b/src/core/component/slot.rs deleted file mode 100644 index 19ed72a..0000000 --- a/src/core/component/slot.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::builder_fn; -use crate::core::component::{Component, Typed}; -use crate::html::{html, Context, Markup}; - -/// Contenedor para un componente [`Typed`] opcional. -/// -/// Un `TypedSlot` actúa como un contenedor dentro de otro componente para incluir o no un -/// subcomponente. Internamente encapsula `Option<Typed<C>>`, pero proporciona una API más sencilla -/// para construir estructuras jerárquicas. -/// -/// # Ejemplo -/// -/// ```rust,ignore -/// use pagetop::prelude::*; -/// -/// let comp = MyComponent::new(); -/// let opt = TypedSlot::new(comp); -/// assert!(opt.get().is_some()); -/// ``` -pub struct TypedSlot<C: Component>(Option<Typed<C>>); - -impl<C: Component> Default for TypedSlot<C> { - fn default() -> Self { - TypedSlot(None) - } -} - -impl<C: Component> TypedSlot<C> { - /// Crea un nuevo [`TypedSlot`]. - /// - /// El componente se envuelve automáticamente en un [`Typed`] y se almacena. - pub fn new(component: C) -> Self { - TypedSlot(Some(Typed::with(component))) - } - - // TypedSlot BUILDER ********************************************************************* - - /// Establece un componente nuevo, o lo vacía. - /// - /// Si se proporciona `Some(component)`, se guarda en [`Typed`]; y si es `None`, se limpia. - #[builder_fn] - pub fn with_value(mut self, component: Option<C>) -> Self { - self.0 = component.map(Typed::with); - self - } - - // TypedSlot GETTERS ********************************************************************* - - /// Devuelve un clon (incrementa el contador `Arc`) de [`Typed<C>`], si existe. - pub fn get(&self) -> Option<Typed<C>> { - self.0.clone() - } - - // TypedSlot RENDER ************************************************************************ - - /// Renderiza el componente, si existe. - pub fn render(&self, cx: &mut Context) -> Markup { - if let Some(component) = &self.0 { - component.render(cx) - } else { - html! {} - } - } -} diff --git a/src/core/extension/all.rs b/src/core/extension/all.rs index a243778..fa67671 100644 --- a/src/core/extension/all.rs +++ b/src/core/extension/all.rs @@ -7,7 +7,7 @@ use parking_lot::RwLock; use std::sync::LazyLock; -// EXTENSIONES ************************************************************************************* +// **< EXTENSIONES >******************************************************************************** static ENABLED_EXTENSIONS: LazyLock<RwLock<Vec<ExtensionRef>>> = LazyLock::new(|| RwLock::new(Vec::new())); @@ -15,7 +15,7 @@ static ENABLED_EXTENSIONS: LazyLock<RwLock<Vec<ExtensionRef>>> = static DROPPED_EXTENSIONS: LazyLock<RwLock<Vec<ExtensionRef>>> = LazyLock::new(|| RwLock::new(Vec::new())); -// REGISTRO DE LAS EXTENSIONES ********************************************************************* +// **< REGISTRO DE LAS EXTENSIONES >**************************************************************** pub fn register_extensions(root_extension: Option<ExtensionRef>) { // Prepara la lista de extensiones habilitadas. @@ -104,7 +104,7 @@ fn add_to_dropped(list: &mut Vec<ExtensionRef>, extension: ExtensionRef) { } } -// REGISTRO DE LAS ACCIONES ************************************************************************ +// **< REGISTRO DE LAS ACCIONES >******************************************************************* pub fn register_actions() { for extension in ENABLED_EXTENSIONS.read().iter() { @@ -114,7 +114,7 @@ pub fn register_actions() { } } -// INICIALIZA LAS EXTENSIONES ********************************************************************** +// **< INICIALIZA LAS EXTENSIONES >***************************************************************** pub fn initialize_extensions() { trace::info!("Calling application bootstrap"); @@ -123,7 +123,7 @@ pub fn initialize_extensions() { } } -// CONFIGURA LOS SERVICIOS ************************************************************************* +// **< CONFIGURA LOS SERVICIOS >******************************************************************** pub fn configure_services(scfg: &mut service::web::ServiceConfig) { // Sólo compila durante el desarrollo, para evitar errores 400 en la traza de eventos. diff --git a/src/core/extension/definition.rs b/src/core/extension/definition.rs index 90bdbad..520153d 100644 --- a/src/core/extension/definition.rs +++ b/src/core/extension/definition.rs @@ -16,13 +16,12 @@ pub type ExtensionRef = &'static dyn Extension; /// extensión y sobreescribir los métodos que sea necesario. /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// pub struct Blog; /// /// impl Extension for Blog { /// fn name(&self) -> L10n { L10n::n("Blog") } -/// fn description(&self) -> L10n { L10n::n("Sistema de blogs") } +/// fn description(&self) -> L10n { L10n::n("Blog system") } /// } /// ``` pub trait Extension: AnyInfo + Send + Sync { @@ -45,8 +44,7 @@ pub trait Extension: AnyInfo + Send + Sync { /// la extensión no es un tema, este método devuelve `None` por defecto. /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// pub struct MyTheme; /// /// impl Extension for MyTheme { @@ -88,8 +86,7 @@ pub trait Extension: AnyInfo + Send + Sync { /// estáticos, etc., usando [`ServiceConfig`](crate::service::web::ServiceConfig). /// /// ```rust,ignore - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// pub struct ExtensionSample; /// /// impl Extension for ExtensionSample { diff --git a/src/core/theme.rs b/src/core/theme.rs index 61d820b..28638ba 100644 --- a/src/core/theme.rs +++ b/src/core/theme.rs @@ -9,16 +9,17 @@ //! tipografías, espaciados y cualquier otro detalle visual o de comportamiento (como animaciones, //! scripts de interfaz, etc.). //! -//! Los temas son extensiones que implementan [`Extension`](crate::core::extension::Extension); por -//! lo que se instancian, declaran sus dependencias y se inician igual que el resto de extensiones; -//! pero serán temas si además implementan [`theme()`](crate::core::extension::Extension::theme) y -//! [`Theme`]. +//! Los temas son extensiones que implementan [`Extension`](crate::core::extension::Extension), por +//! lo que se instancian, declaran dependencias y se inician igual que cualquier otra extensión. +//! También deben implementar [`Theme`] y sobrescribir el método +//! [`Extension::theme()`](crate::core::extension::Extension::theme) para que PageTop pueda +//! registrarlos como temas mod definition; -pub use definition::{Theme, ThemePage, ThemeRef}; +pub use definition::{Theme, ThemePage, ThemeRef, DefaultRegions}; mod regions; pub(crate) use regions::{ChildrenInRegions, REGION_CONTENT}; -pub use regions::{InRegion, Region}; +pub use regions::{InRegion, Region, RegionRef}; pub(crate) mod all; diff --git a/src/core/theme/all.rs b/src/core/theme/all.rs index ebb2848..5e6b65b 100644 --- a/src/core/theme/all.rs +++ b/src/core/theme/all.rs @@ -5,11 +5,11 @@ use parking_lot::RwLock; use std::sync::LazyLock; -// TEMAS ******************************************************************************************* +// **< TEMAS >************************************************************************************** pub static THEMES: LazyLock<RwLock<Vec<ThemeRef>>> = LazyLock::new(|| RwLock::new(Vec::new())); -// TEMA PREDETERMINADO ***************************************************************************** +// **< TEMA PREDETERMINADO >************************************************************************ pub static DEFAULT_THEME: LazyLock<ThemeRef> = LazyLock::new(|| match theme_by_short_name(&global::SETTINGS.app.theme) { @@ -17,7 +17,7 @@ pub static DEFAULT_THEME: LazyLock<ThemeRef> = None => &crate::base::theme::Basic, }); -// TEMA POR NOMBRE ********************************************************************************* +// **< TEMA POR NOMBRE >**************************************************************************** // Devuelve el tema identificado por su [`short_name()`](AnyInfo::short_name). pub fn theme_by_short_name(short_name: &'static str) -> Option<ThemeRef> { diff --git a/src/core/theme/definition.rs b/src/core/theme/definition.rs index 38a0bfc..7d21c14 100644 --- a/src/core/theme/definition.rs +++ b/src/core/theme/definition.rs @@ -1,9 +1,10 @@ +use crate::core::component::{ContextOp, Contextual}; use crate::core::extension::Extension; -use crate::core::theme::Region; -use crate::global; -use crate::html::{html, Markup}; +use crate::core::theme::{Region, RegionRef, REGION_CONTENT}; +use crate::html::{html, Markup, StyleSheet}; use crate::locale::L10n; use crate::response::page::Page; +use crate::{global, join, AutoDefault}; use std::sync::LazyLock; @@ -13,78 +14,141 @@ use std::sync::LazyLock; /// implementen [`Theme`] y, a su vez, [`Extension`]. pub type ThemeRef = &'static dyn Theme; +/// Conjunto de regiones predefinidas que los temas pueden exponer para el renderizado. +/// +/// `DefaultRegions` define un conjunto de regiones predefinidas para estructurar un documento HTML. +/// Proporciona **identificadores estables** (vía [`Region::key()`]) y **etiquetas localizables** +/// (vía [`Region::label()`]) a las regiones donde se añadirán los componentes. +/// +/// Se usa por defecto en [`Theme::page_regions()`](crate::core::theme::Theme::page_regions) y sus +/// variantes representan el conjunto mínimo recomendado para cualquier tema. Sin embargo, cada tema +/// podría exponer su propio conjunto de regiones. +#[derive(AutoDefault)] +pub enum DefaultRegions { + /// Cabecera de la página. + /// + /// Clave: `"header"`. Suele contener *branding*, navegación principal o avisos globales. + Header, + + /// Contenido principal de la página (**obligatoria**). + /// + /// Clave: `"content"`. Es el destino por defecto para insertar componentes a nivel de página. + #[default] + Content, + + /// Pie de página. + /// + /// Clave: `"footer"`. Suele contener enlaces legales, créditos o navegación secundaria. + Footer, +} + +impl Region for DefaultRegions { + fn key(&self) -> &str { + match self { + Self::Header => "header", + Self::Content => REGION_CONTENT, + Self::Footer => "footer", + } + } + + fn label(&self) -> L10n { + L10n::l(join!("region_", self.key())) + } +} + /// Métodos predefinidos de renderizado para las páginas de un tema. /// -/// Contiene las implementaciones base de las **secciones** `<head>` y `<body>`. Se implementa -/// automáticamente para cualquier tipo que implemente [`Theme`], por lo que normalmente no requiere -/// implementación explícita. +/// Contiene las implementaciones base para renderizar las **secciones** `<head>` y `<body>`. Se +/// implementa automáticamente para cualquier tipo que implemente [`Theme`], por lo que normalmente +/// no requiere implementación explícita. /// -/// Si un tema **sobrescribe** [`render_page_head()`](Theme::render_page_head) o -/// [`render_page_body()`](Theme::render_page_body), se puede volver al comportamiento por defecto -/// cuando se necesite usando FQS (*Fully Qualified Syntax*): +/// Si un tema **sobrescribe** uno o más de los siguientes métodos de [`Theme`]: /// -/// - `<Self as ThemePage>::render_body(self, page, self.page_regions())` -/// - `<Self as ThemePage>::render_head(self, page)` +/// - [`render_page_region()`](Theme::render_page_region), +/// - [`render_page_head()`](Theme::render_page_head), o +/// - [`render_page_body()`](Theme::render_page_body); +/// +/// puede volver al comportamiento por defecto con una llamada FQS (*Fully Qualified Syntax*) a: +/// +/// - `<Self as ThemePage>::render_region(self, page, region)`, +/// - `<Self as ThemePage>::render_body(self, page, self.page_regions())`, o +/// - `<Self as ThemePage>::render_head(self, page)`. pub trait ThemePage { - /// Renderiza el contenido del `<body>` de la página. + /// Renderiza el **contenedor** de una región concreta del `<body>` de la página. /// - /// Recorre `regions` en el **orden declarado** y, para cada región con contenido, genera un - /// contenedor con `role="region"` y un `aria-label` localizado. Se asume que cada identificador - /// de región es **único** dentro de la página. - fn render_body(&self, page: &mut Page, regions: &[(Region, L10n)]) -> Markup { + /// Obtiene los componentes asociados a `region.key()` desde el contexto de la página y, si hay + /// salida, envuelve el contenido en un contenedor `<div>` predefinido. + /// + /// Si la región **no produce contenido**, devuelve un `Markup` vacío. + #[inline] + fn render_region(&self, page: &mut Page, region: RegionRef) -> Markup { html! { - body id=[page.body_id().get()] class=[page.body_classes().get()] { - @for (region, region_label) in regions { - @let output = page.render_region(region.key()); - @if !output.is_empty() { - @let region_name = region.name(); - div - id=(region_name) - class={ "region region--" (region_name) } - role="region" - aria-label=[region_label.lookup(page)] - { - (output) - } - } + @let key = region.key(); + @let output = page.context().render_components_of(key); + @if !output.is_empty() { + div + id=(key) + class={ "region region--" (key) } + role="region" + aria-label=[region.label().lookup(page)] + { + (output) } } } } - /// Renderiza el contenido del `<head>` de la página. + /// Renderiza el **contenido interior** del `<body>` de la página. /// - /// Por defecto incluye las etiquetas básicas (`charset`, `title`, `description`, `viewport`, + /// Recorre `regions` en el **orden declarado** y, para cada región con contenido, delega en + /// [`render_region()`](Self::render_region) la generación del contenedor. Las regiones sin + /// contenido **no** producen salida. Se asume que cada identificador de región es **único** + /// dentro de la página. + /// + /// La etiqueta `<body>` no se incluye aquí; únicamente renderiza su contenido. + #[inline] + fn render_body(&self, page: &mut Page, regions: &[RegionRef]) -> Markup { + html! { + @for region in regions { + (self.render_region(page, *region)) + } + } + } + + /// Renderiza el **contenido interior** del `<head>` de la página. + /// + /// Incluye por defecto las etiquetas básicas (`charset`, `title`, `description`, `viewport`, /// `X-UA-Compatible`), los metadatos (`name/content`) y propiedades (`property/content`), /// además de los recursos CSS/JS de la página. + /// + /// La etiqueta `<head>` no se incluye aquí; únicamente se renderiza su contenido. + #[inline] fn render_head(&self, page: &mut Page) -> Markup { let viewport = "width=device-width, initial-scale=1, shrink-to-fit=no"; html! { - head { - meta charset="utf-8"; + meta charset="utf-8"; - @if let Some(title) = page.title() { - title { (global::SETTINGS.app.name) (" | ") (title) } - } @else { - title { (global::SETTINGS.app.name) } - } - - @if let Some(description) = page.description() { - meta name="description" content=(description); - } - - meta name="viewport" content=(viewport); - @for (name, content) in page.metadata() { - meta name=(name) content=(content) {} - } - - meta http-equiv="X-UA-Compatible" content="IE=edge"; - @for (property, content) in page.properties() { - meta property=(property) content=(content) {} - } - - (page.render_assets()) + @if let Some(title) = page.title() { + title { (global::SETTINGS.app.name) (" | ") (title) } + } @else { + title { (global::SETTINGS.app.name) } } + + @if let Some(description) = page.description() { + meta name="description" content=(description); + } + + meta name="viewport" content=(viewport); + @for (name, content) in page.metadata() { + meta name=(name) content=(content) {} + } + + meta http-equiv="X-UA-Compatible" content="IE=edge"; + @for (property, content) in page.properties() { + meta property=(property) content=(content) {} + } + + (page.context().render_assets()) } } } @@ -95,8 +159,7 @@ pub trait ThemePage { /// **obligatorio** de `Extension` para un tema es [`theme()`](Extension::theme). /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// pub struct MyTheme; /// /// impl Extension for MyTheme { @@ -125,31 +188,53 @@ pub trait Theme: Extension + ThemePage + Send + Sync { /// Declaración ordenada de las regiones disponibles en la página. /// - /// Devuelve una **lista estática** de pares `(Region, L10n)` que se usará para renderizar todas - /// las regiones que componen una página en el orden indicado . + /// Retorna una **lista estática** de referencias ([`RegionRef`](crate::core::theme::RegionRef)) + /// que representan las regiones que el tema admite dentro del `<body>`. /// - /// Si un tema necesita un conjunto distinto de regiones, se puede **sobrescribir** este método - /// con los siguientes requisitos y recomendaciones: + /// Cada referencia apunta a una instancia que implementa [`Region`](crate::core::theme::Region) + /// para definir cada región de forma segura y estable. Y si un tema necesita un conjunto + /// distinto de regiones, puede **sobrescribir** este método siguiendo estas recomendaciones: /// - /// - Los identificadores deben ser **estables** (p. ej. `"sidebar-left"`, `"content"`). - /// - La región `"content"` es **obligatoria**. Se puede usar [`Region::default()`] para - /// declararla. - /// - La etiqueta `L10n` se evalúa con el idioma activo de la página. + /// - Los identificadores devueltos por [`Region::key()`](crate::core::theme::Region::key) + /// deben ser **estables** (p. ej. `"sidebar-left"`, `"content"`). + /// - La región `"content"` es **obligatoria**, ya que se usa como destino por defecto para + /// insertar componentes y renderizarlos. + /// - El orden de la lista podría tener relevancia como **orden de renderizado** dentro del + /// `<body>` segun la implementación de [`render_page_body()`](Self::render_page_body). + /// - Las etiquetas (`L10n`) de cada región se evaluarán con el idioma activo de la página. /// - /// Por defecto devuelve: + /// # Ejemplo /// - /// - `"header"`: cabecera. - /// - `"content"`: contenido principal (**obligatoria**). - /// - `"footer"`: pie. - fn page_regions(&self) -> &'static [(Region, L10n)] { - static REGIONS: LazyLock<[(Region, L10n); 3]> = LazyLock::new(|| { + /// ```rust,ignore + /// fn page_regions(&self) -> &'static [RegionRef] { + /// static REGIONS: LazyLock<[RegionRef; 4]> = LazyLock::new(|| { + /// [ + /// &DefaultRegions::Header, + /// &DefaultRegions::Content, + /// &DefaultRegions::Footer, + /// ] + /// }); + /// &*REGIONS + /// } + /// ``` + fn page_regions(&self) -> &'static [RegionRef] { + static REGIONS: LazyLock<[RegionRef; 3]> = LazyLock::new(|| { [ - (Region::declare("header"), L10n::l("region_header")), - (Region::default(), L10n::l("region_content")), - (Region::declare("footer"), L10n::l("region_footer")), + &DefaultRegions::Header, + &DefaultRegions::Content, + &DefaultRegions::Footer, ] }); - &REGIONS[..] + &*REGIONS + } + + /// Renderiza una región de la página. + /// + /// Si se sobrescribe este método, se puede volver al comportamiento base con: + /// `<Self as ThemePage>::render_region(self, page, region)`. + #[inline] + fn render_page_region(&self, page: &mut Page, region: RegionRef) -> Markup { + <Self as ThemePage>::render_region(self, page, region) } /// Acciones específicas del tema antes de renderizar el `<body>` de la página. @@ -160,7 +245,7 @@ pub trait Theme: Extension + ThemePage + Send + Sync { /// Renderiza el contenido del `<body>` de la página. /// - /// Si se sobrescribe este método, se puede volver al comportamiento base con: + /// Si se sobrescribe este método, se puede volver al renderizado base con: /// `<Self as ThemePage>::render_body(self, page, self.page_regions())`. #[inline] fn render_page_body(&self, page: &mut Page) -> Markup { @@ -175,21 +260,40 @@ pub trait Theme: Extension + ThemePage + Send + Sync { /// Renderiza el contenido del `<head>` de la página. /// - /// Si se sobrescribe este método, se puede volver al comportamiento base con: + /// Si se sobrescribe este método, se puede volver al renderizado base con: /// `<Self as ThemePage>::render_head(self, page)`. #[inline] fn render_page_head(&self, page: &mut Page) -> Markup { + if page.param_or("include_basic_assets", false) { + let pkg_version = env!("CARGO_PKG_VERSION"); + + page.alter_assets(ContextOp::AddStyleSheet( + StyleSheet::from("/css/normalize.css") + .with_version("8.0.1") + .with_weight(-99), + )) + .alter_assets(ContextOp::AddStyleSheet( + StyleSheet::from("/css/root.css") + .with_version(pkg_version) + .with_weight(-99), + )) + .alter_assets(ContextOp::AddStyleSheet( + StyleSheet::from("/css/basic.css") + .with_version(pkg_version) + .with_weight(-99), + )); + } <Self as ThemePage>::render_head(self, page) } - /// Contenido predeterminado para la página de error "*403 – Forbidden*". + /// Contenido predeterminado para la página de error "*403 - Forbidden*". /// /// Se puede sobrescribir este método para personalizar y adaptar este contenido al tema. fn error403(&self, page: &mut Page) -> Markup { html! { div { h1 { (L10n::l("error403_notice").using(page)) } } } } - /// Contenido predeterminado para la página de error "*404 – Not Found*". + /// Contenido predeterminado para la página de error "*404 - Not Found*". /// /// Se puede sobrescribir este método para personalizar y adaptar este contenido al tema. fn error404(&self, page: &mut Page) -> Markup { diff --git a/src/core/theme/regions.rs b/src/core/theme/regions.rs index 8082aac..17e1543 100644 --- a/src/core/theme/regions.rs +++ b/src/core/theme/regions.rs @@ -1,5 +1,6 @@ use crate::core::component::{Child, ChildOp, Children}; use crate::core::theme::ThemeRef; +use crate::locale::L10n; use crate::{builder_fn, AutoDefault, UniqueId}; use parking_lot::RwLock; @@ -18,93 +19,99 @@ static COMMON_REGIONS: LazyLock<RwLock<ChildrenInRegions>> = /// Nombre de la región de contenido por defecto (`"content"`). pub const REGION_CONTENT: &str = "content"; -/// Identificador de una región de página. +/// Define la interfaz mínima que describe una **región de renderizado** dentro de una página. /// -/// Incluye una **clave estática** ([`key()`](Self::key)) que identifica la región en el tema, y un -/// **nombre normalizado** ([`name()`](Self::name)) en minúsculas para su uso en atributos HTML -/// (p.ej., clases `region__{name}`). +/// Una *región* representa una zona del documento HTML (por ejemplo: `"header"`, `"content"` o +/// `"sidebar-left"`), en la que se pueden incluir y renderizar componentes dinámicamente. /// -/// Se utiliza para declarar las regiones que componen una página en un tema (ver -/// [`page_regions()`](crate::core::theme::Theme::page_regions)). -pub struct Region { - key: &'static str, - name: String, -} - -impl Default for Region { - #[inline] - fn default() -> Self { - Self { - key: REGION_CONTENT, - name: REGION_CONTENT.to_string(), - } - } -} - -impl Region { - /// Declara una región a partir de su clave estática. +/// Este `trait` abstrae los metadatos básicos de cada región, esencialmente: +/// +/// - su **clave interna** (`key()`), que la identifica de forma única dentro de la página, y +/// - su **etiqueta localizada** (`label()`), que se usa como texto accesible (por ejemplo en +/// `aria-label` o en descripciones semánticas del contenedor). +/// +/// Las implementaciones típicas son *enumeraciones estáticas* declaradas por cada tema (ver como +/// ejemplo [`DefaultRegions`](crate::core::theme::DefaultRegions)), de modo que las claves y +/// etiquetas permanecen inmutables y fácilmente referenciables. +/// +/// # Ejemplo +/// +/// ```rust +/// # use pagetop::prelude::*; +/// pub enum MyThemeRegions { +/// Header, +/// Content, +/// Footer, +/// } +/// +/// impl Region for MyThemeRegions { +/// fn key(&self) -> &str { +/// match self { +/// Self::Header => "header", +/// Self::Content => "content", +/// Self::Footer => "footer", +/// } +/// } +/// +/// fn label(&self) -> L10n { +/// L10n::l(join!("region__", self.key())) +/// } +/// } +/// ``` +pub trait Region: Send + Sync { + /// Devuelve la **clave interna** que identifica de forma única una región. /// - /// Genera además un nombre normalizado de la clave, eliminando espacios iniciales y finales, - /// convirtiendo a minúsculas y sustituyendo los espacios intermedios por guiones (`-`). + /// La clave se utiliza para asociar los componentes de la región con su contenedor HTML + /// correspondiente. Por convención, se emplean nombres en minúsculas y con guiones (`"header"`, + /// `"main"`, `"sidebar-right"`, etc.), y la región `"content"` es **obligatoria** en todos los + /// temas. + fn key(&self) -> &str; + + /// Devuelve la **etiqueta localizada** (`L10n`) asociada a la región. /// - /// Esta clave se usará para añadir componentes a la región; por ello se recomiendan nombres - /// sencillos, limitando los caracteres a `[a-z0-9-]` (p.ej., `"sidebar"` o `"main-menu"`), cuyo - /// nombre normalizado coincidirá con la clave. - #[inline] - pub fn declare(key: &'static str) -> Self { - Self { - key, - name: key.trim().to_ascii_lowercase().replace(' ', "-"), - } - } - - /// Devuelve la clave estática asignada a la región. - #[inline] - pub fn key(&self) -> &'static str { - self.key - } - - /// Devuelve el nombre normalizado de la región (para atributos y búsquedas). - #[inline] - pub fn name(&self) -> &str { - &self.name - } + /// Esta etiqueta se evalúa en el idioma activo de la página y se utiliza principalmente para + /// accesibilidad, como el valor de `aria-label` en el contenedor generado por + /// [`ThemePage::render_region()`](crate::core::theme::ThemePage::render_region). + fn label(&self) -> L10n; } +/// Referencia estática a una región. +pub type RegionRef = &'static dyn Region; + // Contenedor interno de componentes agrupados por región. #[derive(AutoDefault)] pub struct ChildrenInRegions(HashMap<&'static str, Children>); impl ChildrenInRegions { - pub fn with(region_name: &'static str, child: Child) -> Self { - ChildrenInRegions::default().with_child_in(region_name, ChildOp::Add(child)) + pub fn with(region_key: &'static str, child: Child) -> Self { + ChildrenInRegions::default().with_child_in(region_key, ChildOp::Add(child)) } #[builder_fn] - pub fn with_child_in(mut self, region_name: &'static str, op: ChildOp) -> Self { - if let Some(region) = self.0.get_mut(region_name) { + pub fn with_child_in(mut self, region_key: &'static str, op: ChildOp) -> Self { + if let Some(region) = self.0.get_mut(region_key) { region.alter_child(op); } else { - self.0.insert(region_name, Children::new().with_child(op)); + self.0.insert(region_key, Children::new().with_child(op)); } self } - pub fn merge_all_components(&self, theme_ref: ThemeRef, region_name: &'static str) -> Children { + pub fn merge_all_components(&self, theme_ref: ThemeRef, region_key: &'static str) -> Children { let common = COMMON_REGIONS.read(); if let Some(r) = THEME_REGIONS.read().get(&theme_ref.type_id()) { Children::merge(&[ - common.0.get(region_name), - self.0.get(region_name), - r.0.get(region_name), + common.0.get(region_key), + self.0.get(region_key), + r.0.get(region_key), ]) } else { - Children::merge(&[common.0.get(region_name), self.0.get(region_name)]) + Children::merge(&[common.0.get(region_key), self.0.get(region_key)]) } } } -/// Punto de acceso para añadir componentes a regiones globales o específicas de un tema. +/// Permite añadir componentes a regiones globales o específicas de un tema. /// /// Según la variante, se pueden añadir componentes ([`add()`](Self::add)) que permanecerán /// disponibles durante toda la ejecución. @@ -114,9 +121,9 @@ impl ChildrenInRegions { pub enum InRegion { /// Región de contenido por defecto. Content, - /// Región identificada por el nombre proporcionado. - Named(&'static str), - /// Región identificada por un nombre y asociada a un tema concreto. + /// Región identificada por la clave proporcionado. + Key(&'static str), + /// Región identificada por una clave para un tema concreto. OfTheme(&'static str, ThemeRef), } @@ -126,15 +133,14 @@ impl InRegion { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// // Banner global, en la región por defecto de cualquier página. /// InRegion::Content.add(Child::with(Html::with(|_| /// html! { ("🎉 ¡Bienvenido!") } /// ))); /// /// // Texto en la región "sidebar". - /// InRegion::Named("sidebar").add(Child::with(Html::with(|_| + /// InRegion::Key("sidebar").add(Child::with(Html::with(|_| /// html! { ("Publicidad") } /// ))); /// ``` @@ -145,19 +151,19 @@ impl InRegion { .write() .alter_child_in(REGION_CONTENT, ChildOp::Add(child)); } - InRegion::Named(region_name) => { + InRegion::Key(region_key) => { COMMON_REGIONS .write() - .alter_child_in(region_name, ChildOp::Add(child)); + .alter_child_in(region_key, ChildOp::Add(child)); } - InRegion::OfTheme(region_name, theme_ref) => { + InRegion::OfTheme(region_key, theme_ref) => { let mut regions = THEME_REGIONS.write(); if let Some(r) = regions.get_mut(&theme_ref.type_id()) { - r.alter_child_in(region_name, ChildOp::Add(child)); + r.alter_child_in(region_key, ChildOp::Add(child)); } else { regions.insert( theme_ref.type_id(), - ChildrenInRegions::with(region_name, child), + ChildrenInRegions::with(region_key, child), ); } } diff --git a/src/global.rs b/src/global.rs index ccc6d9d..ee07d81 100644 --- a/src/global.rs +++ b/src/global.rs @@ -30,7 +30,7 @@ include_config!(SETTINGS: Settings => [ ]); #[derive(Debug, Deserialize)] -/// Ajustes para las secciones globales [`[app]`](App), [`[dev]`](Dev), [`[log]`](Log) y +/// Tipos para las secciones globales [`[app]`](App), [`[dev]`](Dev), [`[log]`](Log) y /// [`[server]`](Server) de [`SETTINGS`]. pub struct Settings { pub app: App, @@ -50,11 +50,11 @@ pub struct App { pub theme: String, /// Idioma por defecto para la aplicación. /// - /// Si no está definido o no es válido, el idioma efectivo para el renderizado se resolverá - /// según la implementación de [`LangId`](crate::locale::LangId) en este orden: primero intenta - /// con el establecido en [`Contextual::with_langid()`](crate::html::Contextual::with_langid); - /// pero si no se ha definido explícitamente, usará el indicado en la cabecera `Accept-Language` - /// del navegador; y, si ninguno aplica, se empleará el idioma de respaldo ("en-US"). + /// Si no está definido o no es válido, [`LangId`](crate::locale::LangId) determinará el idioma + /// efectivo para el renderizado en este orden: primero intentará usar el establecido mediante + /// [`Contextual::with_langid()`](crate::core::component::Contextual::with_langid); si no se ha + /// definido explícitamente, probará el indicado en la cabecera `Accept-Language` del navegador; + /// y, si ninguno aplica, se empleará el idioma de respaldo ("en-US"). pub language: String, /// Banner ASCII mostrado al inicio: *"Off"* (desactivado), *"Slant"*, *"Small"*, *"Speed"* o /// *"Starwars"*. @@ -105,7 +105,7 @@ pub struct Server { pub bind_address: String, /// Puerto de escucha del servidor web. pub bind_port: u16, - /// Duración de la cookie de sesión en segundos (p.ej. `604_800` para una semana). + /// Duración de la cookie de sesión en segundos (p. ej., `604_800` para una semana). /// /// El valor `0` indica que la cookie permanecerá activa hasta que se cierre el navegador. pub session_lifetime: i64, diff --git a/src/html.rs b/src/html.rs index 4858bbf..82fdcd7 100644 --- a/src/html.rs +++ b/src/html.rs @@ -3,7 +3,7 @@ mod maud; pub use maud::{display, html, html_private, Escaper, Markup, PreEscaped, DOCTYPE}; -// HTML DOCUMENT ASSETS **************************************************************************** +// **< HTML DOCUMENT ASSETS >*********************************************************************** mod assets; pub use assets::favicon::Favicon; @@ -11,12 +11,41 @@ pub use assets::javascript::JavaScript; pub use assets::stylesheet::{StyleSheet, TargetMedia}; pub use assets::{Asset, Assets}; -// HTML DOCUMENT CONTEXT *************************************************************************** +mod logo; +pub use logo::PageTopSvg; -mod context; -pub use context::{AssetsOp, Context, Contextual, ErrorParam}; +// **< HTML DOCUMENT CONTEXT >********************************************************************** -// HTML ATTRIBUTES ********************************************************************************* +/// **Obsoleto desde la versión 0.5.0**: usar [`core::component::Context`] en su lugar. +#[deprecated(since = "0.5.0", note = "Moved to `pagetop::core::component::Context`")] +pub type Context = crate::core::component::Context; + +/// **Obsoleto desde la versión 0.5.0**: usar [`core::component::ContextOp`] en su lugar. +#[deprecated( + since = "0.5.0", + note = "Moved to `pagetop::core::component::ContextOp`" +)] +pub type ContextOp = crate::core::component::ContextOp; + +/// **Obsoleto desde la versión 0.5.0**: usar [`core::component::Contextual`] en su lugar. +#[deprecated( + since = "0.5.0", + note = "Moved to `pagetop::core::component::Contextual`" +)] +pub trait Contextual: crate::core::component::Contextual {} + +/// **Obsoleto desde la versión 0.5.0**: usar [`core::component::ContextError`] en su lugar. +#[deprecated( + since = "0.5.0", + note = "Moved to `pagetop::core::component::ContextError`" +)] +pub type ContextError = crate::core::component::ContextError; + +/// **Obsoleto desde la versión 0.5.0**: usar [`ContextOp`] en su lugar. +#[deprecated(since = "0.5.0", note = "Use `ContextOp` instead")] +pub type AssetsOp = crate::core::component::ContextOp; + +// **< HTML ATTRIBUTES >**************************************************************************** mod attr_id; pub use attr_id::AttrId; @@ -50,14 +79,18 @@ pub type OptionClasses = AttrClasses; use crate::{core, AutoDefault}; -/// **Obsoleto desde la versión 0.4.0**: usar [`TypedSlot`](crate::core::component::TypedSlot) en su -/// lugar. +/// **Obsoleto desde la versión 0.4.0**: usar [`Typed`](crate::core::component::Typed) en su lugar. #[deprecated( since = "0.4.0", - note = "Use `pagetop::core::component::TypedSlot` instead" + note = "Use `pagetop::core::component::Typed` instead" )] #[allow(type_alias_bounds)] -pub type OptionComponent<C: core::component::Component> = core::component::TypedSlot<C>; +pub type OptionComponent<C: core::component::Component> = core::component::Typed<C>; + +mod unit; +pub use unit::UnitValue; + +// **< HTML PrepareMarkup >************************************************************************* /// Prepara contenido HTML para su conversión a [`Markup`]. /// @@ -68,15 +101,14 @@ pub type OptionComponent<C: core::component::Component> = core::component::Typed /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Texto normal, se escapa automáticamente para evitar inyección de HTML. /// let fragment = PrepareMarkup::Escaped("Hola <b>mundo</b>".to_string()); -/// assert_eq!(fragment.render().into_string(), "Hola &lt;b&gt;mundo&lt;/b&gt;"); +/// assert_eq!(fragment.into_string(), "Hola &lt;b&gt;mundo&lt;/b&gt;"); /// /// // HTML literal, se inserta directamente, sin escapado adicional. /// let raw_html = PrepareMarkup::Raw("<b>negrita</b>".to_string()); -/// assert_eq!(raw_html.render().into_string(), "<b>negrita</b>"); +/// assert_eq!(raw_html.into_string(), "<b>negrita</b>"); /// /// // Fragmento ya preparado con la macro `html!`. /// let prepared = PrepareMarkup::With(html! { @@ -84,11 +116,11 @@ pub type OptionComponent<C: core::component::Component> = core::component::Typed /// p { "Este es un párrafo con contenido dinámico." } /// }); /// assert_eq!( -/// prepared.render().into_string(), +/// prepared.into_string(), /// "<h2>Título de ejemplo</h2><p>Este es un párrafo con contenido dinámico.</p>" /// ); /// ``` -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone)] pub enum PrepareMarkup { /// No se genera contenido HTML (equivale a `html! {}`). #[default] @@ -120,8 +152,13 @@ impl PrepareMarkup { } } - /// Integra el renderizado fácilmente en la macro [`html!`]. - pub fn render(&self) -> Markup { + /// Convierte el contenido en una cadena HTML renderizada. Usar sólo para pruebas o depuración. + pub fn into_string(&self) -> String { + self.render().into_string() + } + + // Integra el renderizado fácilmente en la macro [`html!`]. + pub(crate) fn render(&self) -> Markup { match self { PrepareMarkup::None => html! {}, PrepareMarkup::Escaped(text) => html! { (text) }, diff --git a/src/html/assets.rs b/src/html/assets.rs index 41cd471..fe5f5b7 100644 --- a/src/html/assets.rs +++ b/src/html/assets.rs @@ -2,7 +2,8 @@ pub mod favicon; pub mod javascript; pub mod stylesheet; -use crate::html::{html, Context, Markup}; +use crate::core::component::Context; +use crate::html::{html, Markup}; use crate::{AutoDefault, Weight}; /// Representación genérica de un script [`JavaScript`](crate::html::JavaScript) o una hoja de diff --git a/src/html/assets/favicon.rs b/src/html/assets/favicon.rs index d731b8f..7598603 100644 --- a/src/html/assets/favicon.rs +++ b/src/html/assets/favicon.rs @@ -1,4 +1,5 @@ -use crate::html::{html, Context, Markup}; +use crate::core::component::Context; +use crate::html::{html, Markup}; use crate::AutoDefault; /// Un **Favicon** es un recurso gráfico que usa el navegador como icono asociado al sitio. @@ -17,8 +18,7 @@ use crate::AutoDefault; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let favicon = Favicon::new() /// // Estándar de facto admitido por todos los navegadores. /// .with_icon("/icons/favicon.ico") @@ -52,7 +52,7 @@ impl Favicon { Favicon::default() } - // Favicon BUILDER ***************************************************************************** + // **< Favicon BUILDER >************************************************************************ /// Le añade un icono genérico apuntando a `image`. El tipo MIME se infiere automáticamente a /// partir de la extensión. @@ -63,7 +63,7 @@ impl Favicon { /// Le añade un icono genérico con atributo `sizes`, útil para indicar resoluciones específicas. /// /// El atributo `sizes` informa al navegador de las dimensiones de la imagen para que seleccione - /// el recurso más adecuado. Puede enumerar varias dimensiones separadas por espacios, p.ej. + /// el recurso más adecuado. Puede enumerar varias dimensiones separadas por espacios, p. ej. /// `"16x16 32x32 48x48"` o usar `any` para iconos escalables (SVG). /// /// No es imprescindible, pero puede mejorar la selección del icono más adecuado. @@ -73,7 +73,7 @@ impl Favicon { /// Le añade un *Apple Touch Icon*, usado por dispositivos iOS para las pantallas de inicio. /// - /// Se recomienda indicar también el tamaño, p.ej. `"256x256"`. + /// Se recomienda indicar también el tamaño, p. ej. `"256x256"`. pub fn with_apple_touch_icon(self, image: impl Into<String>, sizes: impl Into<String>) -> Self { self.add_icon_item("apple-touch-icon", image.into(), Some(sizes.into()), None) } @@ -152,6 +152,8 @@ impl Favicon { self } + // **< Favicon RENDER >************************************************************************* + /// Renderiza el **Favicon** completo con todas las etiquetas declaradas. /// /// El parámetro `Context` se acepta por coherencia con el resto de *assets*, aunque en este diff --git a/src/html/assets/javascript.rs b/src/html/assets/javascript.rs index a8ed3e8..6394842 100644 --- a/src/html/assets/javascript.rs +++ b/src/html/assets/javascript.rs @@ -1,5 +1,6 @@ +use crate::core::component::Context; use crate::html::assets::Asset; -use crate::html::{html, Context, Markup, PreEscaped}; +use crate::html::{html, Markup, PreEscaped}; use crate::{join, join_pair, AutoDefault, Weight}; // Define el origen del recurso JavaScript y cómo debe cargarse en el navegador. @@ -7,16 +8,16 @@ use crate::{join, join_pair, AutoDefault, Weight}; // Los distintos modos de carga permiten optimizar el rendimiento y controlar el comportamiento del // script en relación con el análisis del documento HTML y la ejecución del resto de scripts. // -// - [`From`] – Carga estándar con la etiqueta `<script src="...">`. -// - [`Defer`] – Igual que [`From`], pero con el atributo `defer`, descarga en paralelo y se +// - [`From`] - Carga estándar con la etiqueta `<script src="...">`. +// - [`Defer`] - Igual que [`From`], pero con el atributo `defer`, descarga en paralelo y se // ejecuta tras el análisis del documento HTML, respetando el orden de // aparición. -// - [`Async`] – Igual que [`From`], pero con el atributo `async`, descarga en paralelo y se +// - [`Async`] - Igual que [`From`], pero con el atributo `async`, descarga en paralelo y se // ejecuta en cuanto esté listo, **sin garantizar** el orden relativo respecto a // otros scripts. -// - [`Inline`] – Inserta el código directamente en la etiqueta `<script>`. -// - [`OnLoad`] – Inserta el código JavaScript y lo ejecuta tras el evento `DOMContentLoaded`. -// - [`OnLoadAsync`] – Igual que [`OnLoad`], pero con manejador asíncrono (`async`), útil si dentro +// - [`Inline`] - Inserta el código directamente en la etiqueta `<script>`. +// - [`OnLoad`] - Inserta el código JavaScript y lo ejecuta tras el evento `DOMContentLoaded`. +// - [`OnLoadAsync`] - Igual que [`OnLoad`], pero con manejador asíncrono (`async`), útil si dentro // del código JavaScript se utiliza `await`. #[derive(AutoDefault)] enum Source { @@ -45,8 +46,7 @@ enum Source { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Script externo con carga diferida, versión de caché y prioridad en el renderizado. /// let script = JavaScript::defer("/assets/js/app.js") /// .with_version("1.2.3") @@ -171,7 +171,7 @@ impl JavaScript { } } - // JavaScript BUILDER ************************************************************************** + // **< JavaScript BUILDER >********************************************************************* /// Asocia una **versión** al recurso (usada para control de la caché del navegador). /// @@ -210,16 +210,18 @@ impl Asset for JavaScript { self.weight } + // **< JavaScript RENDER >********************************************************************** + fn render(&self, cx: &mut Context) -> Markup { match &self.source { Source::From(path) => html! { - script src=(join_pair!(path, "?v=", self.version.as_str())) {}; + script src=(join_pair!(path, "?v=", &self.version)) {}; }, Source::Defer(path) => html! { - script src=(join_pair!(path, "?v=", self.version.as_str())) defer {}; + script src=(join_pair!(path, "?v=", &self.version)) defer {}; }, Source::Async(path) => html! { - script src=(join_pair!(path, "?v=", self.version.as_str())) async {}; + script src=(join_pair!(path, "?v=", &self.version)) async {}; }, Source::Inline(_, f) => html! { script { (PreEscaped((f)(cx))) }; diff --git a/src/html/assets/stylesheet.rs b/src/html/assets/stylesheet.rs index 3ecc77f..abadef8 100644 --- a/src/html/assets/stylesheet.rs +++ b/src/html/assets/stylesheet.rs @@ -1,5 +1,6 @@ +use crate::core::component::Context; use crate::html::assets::Asset; -use crate::html::{html, Context, Markup, PreEscaped}; +use crate::html::{html, Markup, PreEscaped}; use crate::{join_pair, AutoDefault, Weight}; // Define el origen del recurso CSS y cómo se incluye en el documento. @@ -7,9 +8,9 @@ use crate::{join_pair, AutoDefault, Weight}; // Los estilos pueden cargarse desde un archivo externo o estar embebidos directamente en una // etiqueta `<style>`. // -// - [`From`] – Carga la hoja de estilos desde un archivo externo, insertándola mediante una +// - [`From`] - Carga la hoja de estilos desde un archivo externo, insertándola mediante una // etiqueta `<link>` con `rel="stylesheet"`. -// - [`Inline`] – Inserta directamente el contenido CSS dentro de una etiqueta `<style>`. +// - [`Inline`] - Inserta directamente el contenido CSS dentro de una etiqueta `<style>`. #[derive(AutoDefault)] enum Source { #[default] @@ -22,7 +23,7 @@ enum Source { /// /// Permite especificar en qué contexto se aplica el CSS, adaptándose a diferentes dispositivos o /// situaciones de impresión. -#[derive(AutoDefault)] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] pub enum TargetMedia { /// Se aplica en todos los casos (el atributo `media` se omite). #[default] @@ -38,7 +39,7 @@ pub enum TargetMedia { /// Devuelve el valor para el atributo `media` (`Some(...)`) o `None` para `Default`. #[rustfmt::skip] impl TargetMedia { - fn as_str_opt(&self) -> Option<&str> { + const fn as_str(self) -> Option<&'static str> { match self { TargetMedia::Default => None, TargetMedia::Print => Some("print"), @@ -61,8 +62,7 @@ impl TargetMedia { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Crea una hoja de estilos externa con control de versión y medio específico (`screen`). /// let stylesheet = StyleSheet::from("/assets/css/main.css") /// .with_version("2.0.1") @@ -113,7 +113,7 @@ impl StyleSheet { } } - // StyleSheet BUILDER ************************************************************************** + // **< StyleSheet BUILDER >********************************************************************* /// Asocia una versión al recurso (usada para control de la caché del navegador). /// @@ -132,7 +132,7 @@ impl StyleSheet { self } - // StyleSheet EXTRAS *************************************************************************** + // **< StyleSheet HELPERS >********************************************************************* /// Especifica el medio donde se aplican los estilos. /// @@ -163,13 +163,15 @@ impl Asset for StyleSheet { self.weight } + // **< StyleSheet RENDER >********************************************************************** + fn render(&self, cx: &mut Context) -> Markup { match &self.source { Source::From(path) => html! { link rel="stylesheet" - href=(join_pair!(path, "?v=", self.version.as_str())) - media=[self.media.as_str_opt()]; + href=(join_pair!(path, "?v=", &self.version)) + media=[self.media.as_str()]; }, Source::Inline(_, f) => html! { style { (PreEscaped((f)(cx))) }; diff --git a/src/html/attr_classes.rs b/src/html/attr_classes.rs index 098c26c..bb88f58 100644 --- a/src/html/attr_classes.rs +++ b/src/html/attr_classes.rs @@ -31,8 +31,7 @@ pub enum ClassesOp { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let classes = AttrClasses::new("Btn btn-primary") /// .with_value(ClassesOp::Add, "Active") /// .with_value(ClassesOp::Remove, "btn-primary"); @@ -48,7 +47,7 @@ impl AttrClasses { AttrClasses::default().with_value(ClassesOp::Prepend, classes) } - // AttrClasses BUILDER ************************************************************************* + // **< AttrClasses BUILDER >******************************************************************** #[builder_fn] pub fn with_value(mut self, op: ClassesOp, classes: impl AsRef<str>) -> Self { @@ -114,7 +113,7 @@ impl AttrClasses { } } - // AttrClasses GETTERS ************************************************************************* + // **< AttrClasses GETTERS >******************************************************************** /// Devuelve la cadena de clases, si existe. pub fn get(&self) -> Option<String> { diff --git a/src/html/attr_id.rs b/src/html/attr_id.rs index 8bb1d33..a1d8a1d 100644 --- a/src/html/attr_id.rs +++ b/src/html/attr_id.rs @@ -12,8 +12,7 @@ use crate::{builder_fn, AutoDefault}; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let id = AttrId::new(" main Section "); /// assert_eq!(id.as_str(), Some("main_section")); /// @@ -29,7 +28,7 @@ impl AttrId { AttrId::default().with_value(value) } - // AttrId BUILDER ****************************************************************************** + // **< AttrId BUILDER >************************************************************************* /// Establece un identificador nuevo normalizando el valor. #[builder_fn] @@ -39,7 +38,7 @@ impl AttrId { self } - // AttrId GETTERS ****************************************************************************** + // **< AttrId GETTERS >************************************************************************* /// Devuelve el identificador normalizado, si existe. pub fn get(&self) -> Option<String> { diff --git a/src/html/attr_l10n.rs b/src/html/attr_l10n.rs index 8250c74..86d1c4a 100644 --- a/src/html/attr_l10n.rs +++ b/src/html/attr_l10n.rs @@ -9,8 +9,7 @@ use crate::{builder_fn, AutoDefault}; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Traducción por clave en las locales por defecto de PageTop. /// let hello = AttrL10n::new(L10n::l("test-hello-world")); /// @@ -39,7 +38,7 @@ impl AttrL10n { AttrL10n(value) } - // AttrL10n BUILDER **************************************************************************** + // **< AttrL10n BUILDER >*********************************************************************** /// Establece una traducción nueva. #[builder_fn] @@ -48,7 +47,7 @@ impl AttrL10n { self } - // AttrL10n GETTERS **************************************************************************** + // **< AttrL10n GETTERS >*********************************************************************** /// Devuelve la traducción para `language`, si existe. pub fn lookup(&self, language: &impl LangId) -> Option<String> { diff --git a/src/html/attr_name.rs b/src/html/attr_name.rs index 928f841..1741695 100644 --- a/src/html/attr_name.rs +++ b/src/html/attr_name.rs @@ -12,8 +12,7 @@ use crate::{builder_fn, AutoDefault}; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let name = AttrName::new(" DISplay name "); /// assert_eq!(name.as_str(), Some("display_name")); /// @@ -29,7 +28,7 @@ impl AttrName { AttrName::default().with_value(value) } - // AttrName BUILDER **************************************************************************** + // **< AttrName BUILDER >*********************************************************************** /// Establece un nombre nuevo normalizando el valor. #[builder_fn] @@ -39,7 +38,7 @@ impl AttrName { self } - // AttrName GETTERS **************************************************************************** + // **< AttrName GETTERS >*********************************************************************** /// Devuelve el nombre normalizado, si existe. pub fn get(&self) -> Option<String> { diff --git a/src/html/attr_value.rs b/src/html/attr_value.rs index 4e03120..b20dec3 100644 --- a/src/html/attr_value.rs +++ b/src/html/attr_value.rs @@ -10,8 +10,7 @@ use crate::{builder_fn, AutoDefault}; /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let s = AttrValue::new(" a new string "); /// assert_eq!(s.as_str(), Some("a new string")); /// @@ -27,7 +26,7 @@ impl AttrValue { AttrValue::default().with_value(value) } - // AttrValue BUILDER *************************************************************************** + // **< AttrValue BUILDER >********************************************************************** /// Establece una cadena nueva normalizando el valor. #[builder_fn] @@ -41,7 +40,7 @@ impl AttrValue { self } - // AttrValue GETTERS *************************************************************************** + // **< AttrValue GETTERS >********************************************************************** /// Devuelve la cadena normalizada, si existe. pub fn get(&self) -> Option<String> { diff --git a/src/html/logo.rs b/src/html/logo.rs new file mode 100644 index 0000000..fd60441 --- /dev/null +++ b/src/html/logo.rs @@ -0,0 +1,93 @@ +use crate::core::component::Context; +use crate::html::{html, Markup}; +use crate::locale::L10n; +use crate::AutoDefault; + +/// Representación SVG del **logotipo de PageTop** para incrustar en HTML. +/// +/// # Ejemplo +/// +/// ```rust +/// # use pagetop::prelude::*; +/// fn render_logo(cx: &mut Context) -> PrepareMarkup { +/// PrepareMarkup::With(html! { +/// div class="logo_color" { +/// (PageTopSvg::Color.render(cx)) +/// } +/// div class="line_dark" { +/// (PageTopSvg::LineDark.render(cx)) +/// } +/// div class="line_light" { +/// (PageTopSvg::LineLight.render(cx)) +/// } +/// div class="line_red" { +/// (PageTopSvg::LineRGB(255, 0, 0).render(cx)) +/// } +/// }) +/// }; +/// ``` + +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum PageTopSvg { + /// Versión por defecto con el logotipo a color. + #[default] + Color, + /// Versión monocroma (línea) oscura, ideal sobre fondos claros. + LineDark, + /// Versión monocroma (línea) clara, ideal sobre fondos oscuros. + LineLight, + /// Versión monocroma configurable por RGB. + LineRGB(u8, u8, u8), +} + +impl PageTopSvg { + /// Renderiza el SVG del logotipo según la variante elegida. + pub fn render(&self, cx: &Context) -> Markup { + let path_fills = match self { + Self::Color => self.logo_color(), + Self::LineDark => self.logo_line(10, 11, 9), + Self::LineLight => self.logo_line(255, 255, 255), + Self::LineRGB(r, g, b) => self.logo_line(*r, *g, *b), + }; + html! { + svg + viewBox="0 0 1614 1614" + xmlns="http://www.w3.org/2000/svg" + role="img" + aria-label=[L10n::l("pagetop_logo").lookup(cx)] + preserveAspectRatio="xMidYMid slice" + focusable="false" + { + (path_fills) + } + } + } + + // **< PageTopSvg HELPERS >********************************************************************* + + fn logo_color(&self) -> Markup { + html! { + path fill="rgb(255,184,75)" d="M 633,61 L 633,61 C 579,61 527,75 480,102 433,129 395,167 368,214 341,261 327,313 327,367 L 327,1244 327,1245 C 327,1299 341,1351 368,1398 395,1445 433,1483 480,1510 527,1537 579,1551 633,1551 L 982,1550 982,1551 C 1036,1551 1088,1537 1135,1510 1182,1483 1220,1445 1247,1398 1274,1351 1288,1299 1288,1245 L 1288,367 1288,367 1288,367 C 1288,313 1274,261 1247,214 1220,167 1182,129 1135,102 1088,75 1036,61 982,61 L 633,61 Z" {} + path fill="rgb(158,96,0)" d="M 1389,573 L 1328,573 1328,460 1449,460 1449,573 1389,573 Z M 1491,627 L 1430,627 1430,404 1551,404 1551,627 1491,627 Z M 222,573 L 161,573 161,460 282,460 282,573 222,573 Z M 120,627 L 59,627 59,404 180,404 180,627 120,627 Z" {} + path fill="rgb(150,0,184)" d="M 678,1040 L 678,1040 C 645,1040 612,1049 583,1065 554,1082 530,1106 513,1135 497,1164 488,1197 488,1230 L 488,1230 488,1230 C 488,1263 497,1296 513,1325 530,1354 554,1378 583,1395 612,1411 645,1420 678,1420 L 940,1420 940,1420 C 973,1420 1006,1411 1035,1395 1064,1378 1088,1354 1105,1325 1121,1296 1130,1263 1130,1230 L 1130,1230 1130,1230 1130,1230 C 1130,1197 1121,1164 1105,1135 1088,1106 1064,1082 1035,1065 1006,1049 973,1040 940,1040 L 678,1040 Z M 488,1040 L 488,1040 488,1040 488,1040 488,1040 488,1040 488,1238 488,1238 488,1238 488,1238 488,1238 1130,1238 1130,1238 1130,1238 1130,1238 1130,1238 1130,1238 1130,1040 1130,1040 1130,1040 1130,1040 1130,1040 488,1040 Z" {} + path fill="rgb(255,255,255)" d="M 518,1128 L 488,1128 488,1066 547,1066 547,1128 518,1128 Z M 966,1128 L 908,1128 908,1066 1024,1066 1024,1128 966,1128 Z" {} + path fill="rgb(221,255,149)" d="M 898,71 C 940,48 987,36 1035,36 1086,36 1137,50 1181,77 1226,104 1263,142 1289,189 1314,236 1328,288 1328,342 1328,396 1314,448 1289,495 1281,509 1272,522 1262,535 L 898,71 Z M 1337,429 C 1307,460 1272,480 1233,488 1192,496 1148,490 1107,470 1066,451 1029,418 999,375 969,332 948,281 938,227 927,173 928,117 940,66 943,51 948,36 953,22 L 1337,429 Z" {} + path fill="rgb(146,128,99)" d="M 703,99 C 717,121 722,149 719,178 715,208 702,238 682,267 661,295 634,320 602,340 571,360 536,373 501,379 467,385 434,383 405,373 377,363 355,346 341,323 327,301 322,273 325,244 329,214 342,184 362,155 383,127 410,102 442,82 473,62 508,49 543,43 577,37 610,39 639,49 667,59 689,76 703,99 L 703,99 Z" {} + path fill="rgb(146,128,99)" d="M 672,550 C 683,568 685,590 678,615 671,640 655,668 632,694 609,720 580,745 547,765 514,785 479,801 446,810 412,819 381,821 355,816 329,811 310,799 299,782 288,765 286,742 293,717 301,692 316,665 339,638 362,612 391,588 424,567 457,547 492,531 526,523 559,514 591,511 616,516 642,521 661,533 672,550 L 672,550 Z" {} + path fill="rgb(146,128,99)" d="M 455,160 L 456,160 C 430,160 404,167 381,180 359,193 340,212 327,234 314,257 307,283 307,309 L 307,580 307,580 C 307,606 314,632 327,655 340,677 359,696 381,709 404,722 430,729 456,729 L 529,729 529,729 C 555,729 581,722 604,709 626,696 645,677 658,655 671,632 678,606 678,580 L 677,308 678,309 678,309 C 678,283 671,257 658,234 645,212 626,193 604,180 581,167 555,160 529,160 L 455,160 Z" {} + path fill="rgb(240,0,0)" d="M 698,1332 L 699,1332 C 696,1332 694,1333 691,1334 689,1335 687,1337 686,1339 685,1342 684,1344 684,1347 L 684,1405 684,1405 C 684,1408 685,1410 686,1413 687,1415 689,1417 691,1418 694,1419 696,1420 699,1420 L 914,1419 914,1420 C 917,1420 919,1419 922,1418 924,1417 926,1415 927,1413 928,1410 929,1408 929,1405 L 929,1346 929,1347 929,1347 C 929,1344 928,1342 927,1339 926,1337 924,1335 922,1334 919,1333 917,1332 914,1332 L 698,1332 Z M 643,780 C 643,797 638,814 630,830 621,845 608,858 593,867 577,875 560,880 543,880 525,880 508,875 492,867 477,858 464,845 455,830 447,814 442,797 442,780 442,762 447,745 455,729 464,714 477,701 492,692 508,684 525,679 542,679 560,679 577,684 593,692 608,701 621,714 630,729 638,745 643,762 643,779 L 643,780 Z M 1171,780 C 1171,797 1166,814 1158,830 1149,845 1136,858 1121,867 1105,875 1088,880 1071,880 1053,880 1036,875 1020,867 1005,858 992,845 983,830 975,814 970,797 970,780 970,762 975,745 983,729 992,714 1005,701 1020,692 1036,684 1053,679 1071,679 1088,679 1105,684 1121,692 1136,701 1149,714 1158,729 1166,745 1171,762 1171,779 L 1171,780 Z" {} + path fill="rgb(10,11,9)" d="M 1573,357 L 1415,357 C 1400,357 1388,369 1388,383 L 1388,410 1335,410 1335,357 C 1335,167 1181,13 992,13 L 621,13 C 432,13 278,167 278,357 L 278,410 225,410 225,383 C 225,369 213,357 198,357 L 40,357 C 25,357 13,369 13,383 L 13,648 C 13,662 25,674 40,674 L 198,674 C 213,674 225,662 225,648 L 225,621 278,621 278,1256 C 278,1446 432,1600 621,1600 L 992,1600 C 1181,1600 1335,1446 1335,1256 L 1335,621 1388,621 1388,648 C 1388,662 1400,674 1415,674 L 1573,674 C 1588,674 1600,662 1600,648 L 1600,383 C 1600,369 1588,357 1573,357 L 1573,357 1573,357 Z M 66,410 L 172,410 172,621 66,621 66,410 66,410 Z M 1282,357 L 1282,488 C 1247,485 1213,477 1181,464 L 1196,437 C 1203,425 1199,409 1186,401 1174,394 1158,398 1150,411 L 1133,440 C 1105,423 1079,401 1056,376 L 1075,361 C 1087,352 1089,335 1079,324 1070,313 1054,311 1042,320 L 1023,335 C 1000,301 981,263 967,221 L 1011,196 C 1023,189 1028,172 1021,160 1013,147 997,143 984,150 L 953,168 C 945,136 941,102 940,66 L 992,66 C 1152,66 1282,197 1282,357 L 1282,357 1282,357 Z M 621,66 L 674,66 674,225 648,225 C 633,225 621,237 621,251 621,266 633,278 648,278 L 674,278 674,357 648,357 C 633,357 621,369 621,383 621,398 633,410 648,410 L 674,410 674,489 648,489 C 633,489 621,501 621,516 621,530 633,542 648,542 L 664,542 C 651,582 626,623 600,662 583,653 563,648 542,648 469,648 410,707 410,780 410,787 411,794 412,801 388,805 361,806 331,806 L 331,357 C 331,197 461,66 621,66 L 621,66 621,66 Z M 621,780 C 621,824 586,859 542,859 498,859 463,824 463,780 463,736 498,701 542,701 586,701 621,736 621,780 L 621,780 621,780 Z M 225,463 L 278,463 278,569 225,569 225,463 225,463 Z M 992,1547 L 621,1547 C 461,1547 331,1416 331,1256 L 331,859 C 367,859 400,858 431,851 454,888 495,912 542,912 615,912 674,853 674,780 674,747 662,718 642,695 675,645 706,594 720,542 L 780,542 C 795,542 807,530 807,516 807,501 795,489 780,489 L 727,489 727,410 780,410 C 795,410 807,398 807,383 807,369 795,357 780,357 L 727,357 727,278 780,278 C 795,278 807,266 807,251 807,237 795,225 780,225 L 727,225 727,66 887,66 C 889,111 895,155 905,196 L 869,217 C 856,224 852,240 859,253 864,261 873,266 882,266 887,266 891,265 895,263 L 921,248 C 937,291 958,331 983,367 L 938,403 C 926,412 925,429 934,440 939,447 947,450 954,450 960,450 966,448 971,444 L 1016,408 C 1043,438 1074,465 1108,485 L 1084,527 C 1076,539 1081,555 1093,563 1098,565 1102,566 1107,566 1116,566 1125,561 1129,553 L 1155,509 C 1194,527 1237,538 1282,541 L 1282,1256 C 1282,1416 1152,1547 992,1547 L 992,1547 992,1547 Z M 1335,463 L 1388,463 1388,569 1335,569 1335,463 1335,463 Z M 1441,410 L 1547,410 1547,621 1441,621 1441,410 1441,410 Z" {} + path fill="rgb(10,11,9)" d="M 1150,1018 L 463,1018 C 448,1018 436,1030 436,1044 L 436,1177 C 436,1348 545,1468 701,1468 L 912,1468 C 1068,1468 1177,1348 1177,1177 L 1177,1044 C 1177,1030 1165,1018 1150,1018 L 1150,1018 1150,1018 Z M 912,1071 L 1018,1071 1018,1124 912,1124 912,1071 912,1071 Z M 489,1071 L 542,1071 542,1124 489,1124 489,1071 489,1071 Z M 701,1415 L 700,1415 C 701,1385 704,1352 718,1343 731,1335 759,1341 795,1359 802,1363 811,1363 818,1359 854,1341 882,1335 895,1343 909,1352 912,1385 913,1415 L 912,1415 701,1415 701,1415 701,1415 Z M 1124,1177 C 1124,1296 1061,1384 966,1408 964,1365 958,1320 922,1298 894,1281 856,1283 807,1306 757,1283 719,1281 691,1298 655,1320 649,1365 647,1408 552,1384 489,1296 489,1177 L 569,1177 C 583,1177 595,1165 595,1150 L 595,1071 859,1071 859,1150 C 859,1165 871,1177 886,1177 L 1044,1177 C 1059,1177 1071,1165 1071,1150 L 1071,1071 1124,1071 1124,1177 1124,1177 1124,1177 Z" {} + path fill="rgb(10,11,9)" d="M 1071,648 C 998,648 939,707 939,780 939,853 998,912 1071,912 1144,912 1203,853 1203,780 1203,707 1144,648 1071,648 L 1071,648 1071,648 Z M 1071,859 C 1027,859 992,824 992,780 992,736 1027,701 1071,701 1115,701 1150,736 1150,780 1150,824 1115,859 1071,859 L 1071,859 1071,859 Z" {} + } + } + + fn logo_line(&self, r: u8, g: u8, b: u8) -> Markup { + let logo_rgb = format!("rgb({r},{g},{b})"); + html! { + path fill=(logo_rgb) d="M 1573,357 L 1415,357 C 1400,357 1388,369 1388,383 L 1388,410 1335,410 1335,357 C 1335,167 1181,13 992,13 L 621,13 C 432,13 278,167 278,357 L 278,410 225,410 225,383 C 225,369 213,357 198,357 L 40,357 C 25,357 13,369 13,383 L 13,648 C 13,662 25,674 40,674 L 198,674 C 213,674 225,662 225,648 L 225,621 278,621 278,1256 C 278,1446 432,1600 621,1600 L 992,1600 C 1181,1600 1335,1446 1335,1256 L 1335,621 1388,621 1388,648 C 1388,662 1400,674 1415,674 L 1573,674 C 1588,674 1600,662 1600,648 L 1600,383 C 1600,369 1588,357 1573,357 L 1573,357 1573,357 Z M 66,410 L 172,410 172,621 66,621 66,410 66,410 Z M 1282,357 L 1282,488 C 1247,485 1213,477 1181,464 L 1196,437 C 1203,425 1199,409 1186,401 1174,394 1158,398 1150,411 L 1133,440 C 1105,423 1079,401 1056,376 L 1075,361 C 1087,352 1089,335 1079,324 1070,313 1054,311 1042,320 L 1023,335 C 1000,301 981,263 967,221 L 1011,196 C 1023,189 1028,172 1021,160 1013,147 997,143 984,150 L 953,168 C 945,136 941,102 940,66 L 992,66 C 1152,66 1282,197 1282,357 L 1282,357 1282,357 Z M 621,66 L 674,66 674,225 648,225 C 633,225 621,237 621,251 621,266 633,278 648,278 L 674,278 674,357 648,357 C 633,357 621,369 621,383 621,398 633,410 648,410 L 674,410 674,489 648,489 C 633,489 621,501 621,516 621,530 633,542 648,542 L 664,542 C 651,582 626,623 600,662 583,653 563,648 542,648 469,648 410,707 410,780 410,787 411,794 412,801 388,805 361,806 331,806 L 331,357 C 331,197 461,66 621,66 L 621,66 621,66 Z M 621,780 C 621,824 586,859 542,859 498,859 463,824 463,780 463,736 498,701 542,701 586,701 621,736 621,780 L 621,780 621,780 Z M 225,463 L 278,463 278,569 225,569 225,463 225,463 Z M 992,1547 L 621,1547 C 461,1547 331,1416 331,1256 L 331,859 C 367,859 400,858 431,851 454,888 495,912 542,912 615,912 674,853 674,780 674,747 662,718 642,695 675,645 706,594 720,542 L 780,542 C 795,542 807,530 807,516 807,501 795,489 780,489 L 727,489 727,410 780,410 C 795,410 807,398 807,383 807,369 795,357 780,357 L 727,357 727,278 780,278 C 795,278 807,266 807,251 807,237 795,225 780,225 L 727,225 727,66 887,66 C 889,111 895,155 905,196 L 869,217 C 856,224 852,240 859,253 864,261 873,266 882,266 887,266 891,265 895,263 L 921,248 C 937,291 958,331 983,367 L 938,403 C 926,412 925,429 934,440 939,447 947,450 954,450 960,450 966,448 971,444 L 1016,408 C 1043,438 1074,465 1108,485 L 1084,527 C 1076,539 1081,555 1093,563 1098,565 1102,566 1107,566 1116,566 1125,561 1129,553 L 1155,509 C 1194,527 1237,538 1282,541 L 1282,1256 C 1282,1416 1152,1547 992,1547 L 992,1547 992,1547 Z M 1335,463 L 1388,463 1388,569 1335,569 1335,463 1335,463 Z M 1441,410 L 1547,410 1547,621 1441,621 1441,410 1441,410 Z" {} + path fill=(logo_rgb) d="M 1150,1018 L 463,1018 C 448,1018 436,1030 436,1044 L 436,1177 C 436,1348 545,1468 701,1468 L 912,1468 C 1068,1468 1177,1348 1177,1177 L 1177,1044 C 1177,1030 1165,1018 1150,1018 L 1150,1018 1150,1018 Z M 912,1071 L 1018,1071 1018,1124 912,1124 912,1071 912,1071 Z M 489,1071 L 542,1071 542,1124 489,1124 489,1071 489,1071 Z M 701,1415 L 700,1415 C 701,1385 704,1352 718,1343 731,1335 759,1341 795,1359 802,1363 811,1363 818,1359 854,1341 882,1335 895,1343 909,1352 912,1385 913,1415 L 912,1415 701,1415 701,1415 701,1415 Z M 1124,1177 C 1124,1296 1061,1384 966,1408 964,1365 958,1320 922,1298 894,1281 856,1283 807,1306 757,1283 719,1281 691,1298 655,1320 649,1365 647,1408 552,1384 489,1296 489,1177 L 569,1177 C 583,1177 595,1165 595,1150 L 595,1071 859,1071 859,1150 C 859,1165 871,1177 886,1177 L 1044,1177 C 1059,1177 1071,1165 1071,1150 L 1071,1071 1124,1071 1124,1177 1124,1177 1124,1177 Z" {} + path fill=(logo_rgb) d="M 1071,648 C 998,648 939,707 939,780 939,853 998,912 1071,912 1144,912 1203,853 1203,780 1203,707 1144,648 1071,648 L 1071,648 1071,648 Z M 1071,859 C 1027,859 992,824 992,780 992,736 1027,701 1071,701 1115,701 1150,736 1150,780 1150,824 1115,859 1071,859 L 1071,859 1071,859 Z" {} + } + } +} diff --git a/src/html/unit.rs b/src/html/unit.rs new file mode 100644 index 0000000..4a99de1 --- /dev/null +++ b/src/html/unit.rs @@ -0,0 +1,283 @@ +use crate::AutoDefault; + +use serde::{Deserialize, Deserializer}; + +use std::fmt; +use std::str::FromStr; + +/// Representa una **unidad CSS** lista para formatear o deserializar. +/// +/// ## Unidades soportadas +/// +/// - **Absolutas** *(valores enteros, `isize`)*: +/// - `Cm(isize)` - `cm` (centímetros) +/// - `In(isize)` - `in` (pulgadas; `1in = 96px = 2.54cm`) +/// - `Mm(isize)` - `mm` (milímetros) +/// - `Pc(isize)` - `pc` (picas; `1pc = 12pt`) +/// - `Pt(isize)` - `pt` (puntos; `1pt = 1/72in`) +/// - `Px(isize)` - `px` (píxeles; `1px = 1/96in`) +/// +/// - **Relativas** *(valores decimales, `f32`)*: +/// - `RelEm(f32)` - `em` (relativa al tamaño de fuente del elemento) +/// - `RelRem(f32)` - `rem` (relativa al tamaño de fuente de `:root`) +/// - `RelPct(f32)` - `%` (porcentaje relativo al elemento padre) +/// - `RelVh(f32)` - `vh` (1% de la **altura** del viewport) +/// - `RelVw(f32)` - `vw` (1% del **ancho** del viewport) +/// +/// ## Valores especiales +/// +/// - `None` - equivale a un texto vacío (`""`), útil para atributos opcionales. +/// - `Auto` - equivale a `"auto"`. +/// - `Zero` - equivale a `"0"` (cero sin unidad). +/// +/// ## Características +/// +/// - Soporta unidades **absolutas** (`cm`, `in`, `mm`, `pc`, `pt`, `px`) y **relativas** (`em`, +/// `rem`, `%`, `vh`, `vw`). +/// - `FromStr` para convertir desde texto (p. ej., `"12px"`, `"1.25rem"`, `"auto"`). +/// - `Display` para formatear a cadena (p. ej., `UnitValue::Px(12)` genera `"12px"`). +/// - `Deserialize` delega en `FromStr`, garantizando una gramática única. +/// +/// ## Ejemplos +/// +/// ```rust +/// # use pagetop::prelude::*; +/// use std::str::FromStr; +/// +/// assert_eq!(UnitValue::from_str("16px").unwrap(), UnitValue::Px(16)); +/// assert_eq!(UnitValue::from_str("1.25rem").unwrap(), UnitValue::RelRem(1.25)); +/// assert_eq!(UnitValue::from_str("33%").unwrap(), UnitValue::RelPct(33.0)); +/// assert_eq!(UnitValue::from_str("auto").unwrap(), UnitValue::Auto); +/// assert_eq!(UnitValue::from_str("").unwrap(), UnitValue::None); +/// assert_eq!(UnitValue::from_str("0").unwrap(), UnitValue::Zero); +/// ``` +/// +/// ## Notas +/// +/// - Las absolutas **no aceptan** decimales (p. ej., `"1.5px"` sería erróneo). +/// - Se aceptan signos `+`/`-` en todas las unidades (p. ej., `"-12px"`, `"+0.5em"`). +/// - La comparación de unidad es *case-insensitive* al interpretar el texto (`"PX"`, `"Px"`, …). +/// - **Sobre píxeles**: Los píxeles (px) son relativos al dispositivo de visualización. En +/// dispositivos con baja densidad de píxeles (dpi), 1px equivale a un píxel (punto) del +/// dispositivo. En impresoras y pantallas de alta resolución, 1px implica múltiples píxeles del +/// dispositivo. +/// - **Sobre `em` y `rem`**: +/// - `em` es **relativo al tamaño de fuente *del propio elemento***. Si el elemento hereda o +/// cambia su `font-size`, todos los valores en `em` dentro de él **se escalan en cascada**. +/// - `rem` es **relativo al tamaño de fuente del elemento raíz** (`:root`/`html`), **no se verá +/// afectado** por cambios de `font-size` en elementos anidados. +/// - Ejemplo: si `:root { font-size: 16px }` y un contenedor tiene `font-size: 20px`, entonces +/// dentro del contenedor `1em == 20px` pero `1rem == 16px`. +/// - Uso típico: `rem` para tipografía y espaciados globales (consistencia al cambiar la base del +/// sitio); `em` para tamaños que deban escalar **con el propio componente** (p. ej., +/// `padding: 0.5em` que crece si el componente aumenta su `font-size`). +/// - **Sobre el viewport**: Si el ancho de la ventana del navegador es de 50cm, 1vw equivale a +/// 0.5cm (1vw siempre es 1% del ancho del viewport, independientemente del zoom del navegador o +/// la densidad de píxeles del dispositivo). +#[rustfmt::skip] +#[derive(AutoDefault, Clone, Copy, Debug, PartialEq)] +pub enum UnitValue { + #[default] + None, + Auto, + /// Cero sin unidad. + Zero, + /// Centímetros. + Cm(isize), + /// Pulgadas (1in = 96px = 2.54cm). + In(isize), + /// Milímetros. + Mm(isize), + /// Picas (1pc = 12pt). + Pc(isize), + /// Puntos (1pt = 1/72in). + Pt(isize), + /// Píxeles (1px = 1/96in). + Px(isize), + /// Relativo al tamaño de la fuente del elemento. + RelEm(f32), + /// Relativo al tamaño de la fuente del elemento raíz. + RelRem(f32), + /// Porcentaje relativo al elemento padre. + RelPct(f32), + /// Relativo al 1% de la altura del viewport. + RelVh(f32), + /// Relativo al 1% del ancho del viewport. + RelVw(f32), +} + +impl UnitValue { + /// Indica si el valor es **medible**, incluyendo `Zero` sin unidad. + /// + /// Devuelve `false` para [`UnitValue::None`] y [`UnitValue::Auto`]. + /// + /// # Ejemplos + /// + /// ```rust + /// # use pagetop::prelude::*; + /// // Numéricos (incluido el cero sin unidad). + /// assert!(UnitValue::Zero.is_measurable()); + /// assert!(UnitValue::Px(0).is_measurable()); + /// assert!(UnitValue::Px(10).is_measurable()); + /// assert!(UnitValue::RelPct(33.0).is_measurable()); + /// // No numéricos. + /// assert!(!UnitValue::None.is_measurable()); + /// assert!(!UnitValue::Auto.is_measurable()); + /// ``` + #[inline] + pub const fn is_measurable(&self) -> bool { + !matches!(self, UnitValue::None | UnitValue::Auto) + } +} + +/// Formatea la unidad como cadena CSS. +/// +/// Reglas: +/// +/// - `None` - `""` (cadena vacía). +/// - `Auto` - `"auto"`. +/// - `Zero` - `"0"` (cero sin unidad). +/// - Absolutas - entero con su unidad: `Px(12)` a `"12px"`. +/// - Relativas - número en punto flotante; si es entero, se imprime sin decimales: +/// - `RelEm(2.0)` a `"2em"` +/// - `RelPct(33.5)` a `"33.5%"` +#[rustfmt::skip] +impl fmt::Display for UnitValue { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + UnitValue::None => Ok(()), + UnitValue::Auto => f.write_str("auto"), + UnitValue::Zero => f.write_str("0"), + // Valor absoluto. + UnitValue::Cm(av) => write!(f, "{av}cm"), + UnitValue::In(av) => write!(f, "{av}in"), + UnitValue::Mm(av) => write!(f, "{av}mm"), + UnitValue::Pc(av) => write!(f, "{av}pc"), + UnitValue::Pt(av) => write!(f, "{av}pt"), + UnitValue::Px(av) => write!(f, "{av}px"), + // Valor relativo. + UnitValue::RelEm(rv) => write!(f, "{rv}em"), + UnitValue::RelRem(rv) => write!(f, "{rv}rem"), + UnitValue::RelPct(rv) => write!(f, "{rv}%"), + UnitValue::RelVh(rv) => write!(f, "{rv}vh"), + UnitValue::RelVw(rv) => write!(f, "{rv}vw"), + } + } +} + +/// Convierte una cadena a [`UnitValue`] siguiendo una gramática CSS acotada. +/// +/// ## Acepta +/// +/// - `""` para `UnitValue::None` +/// - `"auto"` +/// - **Cero sin unidad**: `"0"`, `"+0"`, `"-0"`, `"0.0"`, `"0."`, `".0"` para `UnitValue::Zero` +/// - Porcentaje: `"<n>%"` (p. ej., `"33%"`, `"33 %"`) +/// - Absolutas enteras: `"<entero><unidad>"`, p. ej., `"12px"`, `"-5pt"` +/// - Relativas decimales: `"<float><unidad>"`, p. ej., `"1.25rem"`, `"-0.5vh"`, `".5em"`, `"1.rem"` +/// +/// (Se toleran espacios entre número y unidad: `"12 px"`, `"1.5 rem"`). +/// +/// ## Ejemplo +/// +/// ```rust +/// # use pagetop::prelude::*; +/// use std::str::FromStr; +/// +/// assert_eq!(UnitValue::from_str("12px").unwrap(), UnitValue::Px(12)); +/// assert!(UnitValue::from_str("12").is_err()); +/// ``` +/// +/// ## Errores de interpretación +/// +/// - Falta la unidad cuando es necesaria (p. ej., `"12"`, excepto para el valor cero). +/// - Decimales en valores que deben ser absolutos (p. ej. `"1.5px"`). +/// - Unidades desconocidas (p. ej., `"10ch"`, no soportada aún). +/// - Notación científica o bases no decimales: `"1e3vw"`, `"0x10px"` (no soportadas). Los ceros a +/// la izquierda (p. ej. `"020px"`) se interpretan en **base 10** (`20px`). +/// +/// La comparación de la unidad es *case-insensitive*. +impl FromStr for UnitValue { + type Err = String; + + fn from_str(input: &str) -> Result<Self, Self::Err> { + let s = input.trim(); + if s.is_empty() { + return Ok(UnitValue::None); + } + if s.eq_ignore_ascii_case("auto") { + return Ok(UnitValue::Auto); + } + + match s.find(|c: char| c.is_ascii_alphabetic() || c == '%') { + None => { + let n: f32 = s + .parse() + .map_err(|e| format!("Invalid number `{s}`: {e}"))?; + if n == 0.0 { + Ok(UnitValue::Zero) + } else { + Err( + "Missing unit (expected one of cm,in,mm,pc,pt,px,em,rem,vh,vw, or %)" + .to_string(), + ) + } + } + Some(split_pos) => { + let (num_str, unit_str) = s.split_at(split_pos); + let u = unit_str.trim(); + let n = num_str.trim(); + + let parse_abs = |n_s: &str| -> Result<isize, String> { + n_s.parse::<isize>() + .map_err(|e| format!("Invalid integer `{n_s}`: {e}")) + }; + let parse_rel = |n_s: &str| -> Result<f32, String> { + n_s.parse::<f32>() + .map_err(|e| format!("Invalid float `{n_s}`: {e}")) + }; + + match u.to_ascii_lowercase().as_str() { + // Unidades absolutas. + "cm" => Ok(UnitValue::Cm(parse_abs(n)?)), + "in" => Ok(UnitValue::In(parse_abs(n)?)), + "mm" => Ok(UnitValue::Mm(parse_abs(n)?)), + "pc" => Ok(UnitValue::Pc(parse_abs(n)?)), + "pt" => Ok(UnitValue::Pt(parse_abs(n)?)), + "px" => Ok(UnitValue::Px(parse_abs(n)?)), + // Unidades relativas. + "em" => Ok(UnitValue::RelEm(parse_rel(n)?)), + "rem" => Ok(UnitValue::RelRem(parse_rel(n)?)), + "vh" => Ok(UnitValue::RelVh(parse_rel(n)?)), + "vw" => Ok(UnitValue::RelVw(parse_rel(n)?)), + // Porcentaje como unidad. + "%" => Ok(UnitValue::RelPct(parse_rel(n)?)), + // Unidad desconocida. + _ => Err(format!("Unknown unit: `{u}`")), + } + } + } + } +} + +/// Deserializa desde una cadena usando la misma gramática que [`FromStr`]. +/// +/// ### Ejemplo con `serde_json` +/// ```rust +/// # use pagetop::prelude::*; +/// use serde::Deserialize; +/// +/// #[derive(Deserialize)] +/// struct Style { width: UnitValue } +/// +/// // "{\"width\":\"12px\"}" deserializa como `Style { width: UnitValue::Px(12) }` +/// ``` +impl<'de> Deserialize<'de> for UnitValue { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: Deserializer<'de>, + { + let raw = String::deserialize(deserializer)?; + raw.parse().map_err(serde::de::Error::custom) + } +} diff --git a/src/lib.rs b/src/lib.rs index 1c1ba2c..a268349 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,10 +7,10 @@ <p>Un entorno para el desarrollo de soluciones web modulares, extensibles y configurables.</p> -[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](#-licencia) [![Doc API](https://img.shields.io/docsrs/pagetop?label=Doc%20API&style=for-the-badge&logo=Docs.rs)](https://docs.rs/pagetop) [![Crates.io](https://img.shields.io/crates/v/pagetop.svg?style=for-the-badge&logo=ipfs)](https://crates.io/crates/pagetop) [![Descargas](https://img.shields.io/crates/d/pagetop.svg?label=Descargas&style=for-the-badge&logo=transmission)](https://crates.io/crates/pagetop) +[![Licencia](https://img.shields.io/badge/license-MIT%2FApache-blue.svg?label=Licencia&style=for-the-badge)](https://git.cillero.es/manuelcillero/pagetop#licencia) <br> </div> @@ -61,7 +61,7 @@ impl Extension for HelloWorld { async fn hello_world(request: HttpRequest) -> ResultPage<Markup, ErrorPage> { Page::new(request) - .add_component(Html::with(move |_| html! { h1 { "Hello World!" } })) + .add_child(Html::with(|_| html! { h1 { "Hello World!" } })) .render() } @@ -97,7 +97,7 @@ extern crate self as pagetop; use std::collections::HashMap; use std::ops::Deref; -// RE-EXPORTED ************************************************************************************* +// **< RE-EXPORTED >******************************************************************************** pub use pagetop_macros::{builder_fn, html, main, test, AutoDefault}; @@ -136,7 +136,7 @@ pub type UniqueId = std::any::TypeId; /// antes en la ordenación. pub type Weight = i8; -// API ********************************************************************************************* +// **< API >**************************************************************************************** // Macros y funciones útiles. pub mod util; @@ -163,6 +163,6 @@ pub mod base; // Prepara y ejecuta la aplicación. pub mod app; -// PRELUDE ***************************************************************************************** +// **< PRELUDE >************************************************************************************ pub mod prelude; diff --git a/src/locale.rs b/src/locale.rs index 2bf0da9..5c000f7 100644 --- a/src/locale.rs +++ b/src/locale.rs @@ -76,8 +76,7 @@ //! que declarar: //! //! ```rust -//! use pagetop::prelude::*; -//! +//! # use pagetop::prelude::*; //! include_locales!(LOCALES_SAMPLE); //! ``` //! @@ -149,8 +148,7 @@ pub trait LangId { /// # Ejemplos /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Coincidencia exacta. /// let lang = LangMatch::resolve("es-ES"); /// assert_eq!(lang.langid().to_string(), "es-ES"); @@ -173,8 +171,7 @@ pub trait LangId { /// respaldo ("en-US"): /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Idioma por defecto o de respaldo si no resuelve. /// let lang = LangMatch::resolve("it-IT"); /// let langid = lang.langid(); @@ -184,8 +181,8 @@ pub enum LangMatch { /// Cuando el identificador de idioma es una cadena vacía. Unspecified, /// Si encuentra un [`LanguageIdentifier`] en la lista de idiomas soportados por PageTop que - /// coincide exactamente con el identificador de idioma (p.ej. "es-ES"), o con el identificador - /// del idioma base (p.ej. "es"). + /// coincide exactamente con el identificador de idioma (p. ej. "es-ES"), o con el identificador + /// del idioma base (p. ej. "es"). Found(&'static LanguageIdentifier), /// Si el identificador de idioma no está entre los soportados por PageTop. Unsupported(String), @@ -208,13 +205,13 @@ impl LangMatch { return Self::Unspecified; } - // Intenta aplicar coincidencia exacta con el código completo (p.ej. "es-MX"). + // Intenta aplicar coincidencia exacta con el código completo (p. ej. "es-MX"). let lang = language.to_ascii_lowercase(); if let Some(langid) = LANGUAGES.get(lang.as_str()).map(|(langid, _)| langid) { return Self::Found(langid); } - // Si la variante regional no existe, retrocede al idioma base (p.ej. "es"). + // Si la variante regional no existe, retrocede al idioma base (p. ej. "es"). if let Some((base_lang, _)) = lang.split_once('-') { if let Some(langid) = LANGUAGES.get(base_lang).map(|(langid, _)| langid) { return Self::Found(langid); @@ -236,8 +233,7 @@ impl LangMatch { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let lang = LangMatch::resolve("es-ES").as_option(); /// assert_eq!(lang.unwrap().to_string(), "es-ES"); /// @@ -327,8 +323,7 @@ enum L10nOp { /// Los argumentos dinámicos se añaden con `with_arg()` o `with_args()`. /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Texto literal sin traducción. /// let raw = L10n::n("© 2025 PageTop").get(); /// @@ -380,13 +375,13 @@ impl L10n { } } - /// Añade un argumento `{$arg}` → `value` a la traducción. + /// Añade un argumento `{$arg}` => `value` a la traducción. pub fn with_arg(mut self, arg: impl Into<String>, value: impl Into<String>) -> Self { self.args.insert(arg.into(), value.into()); self } - /// Añade varios argumentos a la traducción de una sola vez (p.ej. usando la macro [`hm!`], + /// Añade varios argumentos a la traducción de una sola vez (p. ej. usando la macro [`hm!`], /// también vec![("k", "v")], incluso un array de duplas u otras colecciones). pub fn with_args<I, K, V>(mut self, args: I) -> Self where @@ -407,8 +402,7 @@ impl L10n { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let text = L10n::l("greeting").with_arg("name", "Manuel").get(); /// ``` pub fn get(&self) -> Option<String> { @@ -422,8 +416,7 @@ impl L10n { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// struct ResourceLang; /// /// impl LangId for ResourceLang { @@ -464,8 +457,7 @@ impl L10n { /// # Ejemplo /// /// ```rust - /// use pagetop::prelude::*; - /// + /// # use pagetop::prelude::*; /// let html = L10n::l("welcome.message").using(&LangMatch::resolve("es")); /// ``` pub fn using(&self, language: &impl LangId) -> Markup { diff --git a/src/locale/en-US/base.ftl b/src/locale/en-US/base.ftl index 16b1a3e..76baa12 100644 --- a/src/locale/en-US/base.ftl +++ b/src/locale/en-US/base.ftl @@ -1,4 +1,8 @@ -# Basic theme, intro layout. +# Intro component. +intro_default_title = Hello, world! +intro_default_slogan = Discover⚡{ $app } +intro_default_button = A web solution powered by <strong>PageTop</strong> + intro_pagetop_label = PageTop version on Crates.io intro_release_label = Release date intro_license_label = License diff --git a/src/locale/en-US/sample.ftl b/src/locale/en-US/sample.ftl new file mode 100644 index 0000000..ae5b9a7 --- /dev/null +++ b/src/locale/en-US/sample.ftl @@ -0,0 +1,24 @@ +# menus.rs +sample_menus_item_label = Label +sample_menus_item_link = Link +sample_menus_item_blank = External link +sample_menus_item_disabled = Disabled link + +sample_menus_test_title = Dropdown + +sample_menus_dev_header = Intro +sample_menus_dev_getting_started = Getting started +sample_menus_dev_guides = Development guides +sample_menus_dev_forum = Developers forum + +sample_menus_sdk_header = Software Development Kits +sample_menus_sdk_rust = SDKs Rust +sample_menus_sdk_js = SDKs JavaScript +sample_menus_sdk_python = SDKs Python + +sample_menus_plugin_header = Plugins +sample_menus_plugin_auth = Rust Plugin Auth +sample_menus_plugin_cache = Rust Plugin Cache + +sample_menus_item_sign_up = Sign up +sample_menus_item_login = Login diff --git a/src/locale/en-US/welcome.ftl b/src/locale/en-US/welcome.ftl index 20faf96..ec691d1 100644 --- a/src/locale/en-US/welcome.ftl +++ b/src/locale/en-US/welcome.ftl @@ -1,16 +1,12 @@ welcome_extension_name = Default Homepage welcome_extension_description = Displays a default homepage when none is configured. -welcome_page = Welcome page -welcome_title = Hello, world! - -welcome_intro = Discover⚡{ $app } -welcome_powered = A web solution powered by <strong>PageTop</strong> +welcome_title = Welcome page welcome_status_title = Status welcome_status_1 = If you can see this page, it means the <strong>PageTop</strong> server is running correctly, but the application is not fully configured. This may be due to routine maintenance or a temporary issue. welcome_status_2 = If the issue persists, please <strong>contact the system administrator</strong>. welcome_support_title = Support -welcome_support_1 = To report issues with the <strong>PageTop</strong> framework, use <a href="https://git.cillero.es/manuelcillero/pagetop/issues" target="_blank" rel="noreferrer">SoloGit</a>. Remember, before opening a new issue, review the existing ones to avoid duplicates. +welcome_support_1 = To report issues with the <strong>PageTop</strong> framework, use <a href="https://github.com/manuelcillero/pagetop/issues" target="_blank" rel="noopener noreferrer">GitHub</a>. Remember, before opening a new issue, review the existing ones to avoid duplicates. welcome_support_2 = For issues specific to the application (<strong>{ $app }</strong>), please use its official repository or support channel. diff --git a/src/locale/es-ES/base.ftl b/src/locale/es-ES/base.ftl index fee21a9..09867d1 100644 --- a/src/locale/es-ES/base.ftl +++ b/src/locale/es-ES/base.ftl @@ -1,4 +1,8 @@ -# Basic theme, intro layout. +# Intro component. +intro_default_title = ¡Hola, mundo! +intro_default_slogan = Descubre⚡{ $app } +intro_default_button = Una solución web creada con <strong>PageTop</strong> + intro_pagetop_label = Versión de PageTop en Crates.io intro_release_label = Lanzamiento intro_license_label = Licencia diff --git a/src/locale/es-ES/sample.ftl b/src/locale/es-ES/sample.ftl new file mode 100644 index 0000000..6578597 --- /dev/null +++ b/src/locale/es-ES/sample.ftl @@ -0,0 +1,24 @@ +# menus.rs +sample_menus_item_label = Etiqueta +sample_menus_item_link = Enlace +sample_menus_item_blank = Enlace externo +sample_menus_item_disabled = Enlace deshabilitado + +sample_menus_test_title = Desplegable + +sample_menus_dev_header = Introducción +sample_menus_dev_getting_started = Primeros pasos +sample_menus_dev_guides = Guías de desarrollo +sample_menus_dev_forum = Foro de desarrolladores + +sample_menus_sdk_header = Kits de Desarrollo Software +sample_menus_sdk_rust = SDKs de Rust +sample_menus_sdk_js = SDKs de JavaScript +sample_menus_sdk_python = SDKs de Python + +sample_menus_plugin_header = Plugins +sample_menus_plugin_auth = Plugin Rust de autenticación +sample_menus_plugin_cache = Plugin Rust de caché + +sample_menus_item_sign_up = Registrarse +sample_menus_item_login = Iniciar sesión diff --git a/src/locale/es-ES/welcome.ftl b/src/locale/es-ES/welcome.ftl index 13330db..a3e3a18 100644 --- a/src/locale/es-ES/welcome.ftl +++ b/src/locale/es-ES/welcome.ftl @@ -1,16 +1,12 @@ welcome_extension_name = Página de inicio predeterminada welcome_extension_description = Muestra una página de inicio predeterminada cuando no hay ninguna configurada. -welcome_page = Página de bienvenida -welcome_title = ¡Hola, mundo! - -welcome_intro = Descubre⚡{ $app } -welcome_powered = Una solución web creada con <strong>PageTop</strong> +welcome_title = Página de bienvenida welcome_status_title = Estado welcome_status_1 = Si puedes ver esta página, es porque el servidor de <strong>PageTop</strong> está funcionando correctamente, pero la aplicación no está completamente configurada. Esto puede deberse a tareas de mantenimiento o a una incidencia temporal. welcome_status_2 = Si el problema persiste, por favor, <strong>contacta con el administrador del sistema</strong>. welcome_support_title = Soporte -welcome_support_1 = Para comunicar incidencias del propio entorno <strong>PageTop</strong>, utiliza <a href="https://git.cillero.es/manuelcillero/pagetop/issues" target="_blank" rel="noreferrer">SoloGit</a>. Recuerda, antes de abrir una nueva incidencia, revisa las existentes para evitar duplicados. +welcome_support_1 = Para comunicar incidencias del propio entorno <strong>PageTop</strong>, utiliza <a href="https://github.com/manuelcillero/pagetop/issues" target="_blank" rel="noopener noreferrer">GitHub</a>. Recuerda, antes de abrir una nueva incidencia, revisa las existentes para evitar duplicados. welcome_support_2 = Para fallos específicos de la aplicación (<strong>{ $app }</strong>), utiliza su repositorio oficial o su canal de soporte. diff --git a/src/prelude.rs b/src/prelude.rs index 484e53c..47fbbf6 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -9,7 +9,7 @@ pub use crate::{AutoDefault, StaticResources, UniqueId, Weight}; // MACROS. // crate::util -pub use crate::{hm, join, join_opt, join_pair, join_strict}; +pub use crate::{hm, join, join_pair}; // crate::config pub use crate::include_config; // crate::locale @@ -28,7 +28,14 @@ pub use crate::global; pub use crate::trace; -pub use crate::html::*; +// No se usa `pub use crate::html::*;` para evitar duplicar alias marcados como obsoletos +// (*deprecated*) porque han sido trasladados a `crate::core::component`. Cuando se retiren estos +// alias obsoletos se volverá a declarar como `pub use crate::html::*;`. +pub use crate::html::{ + display, html_private, Asset, Assets, AttrClasses, AttrId, AttrL10n, AttrName, AttrValue, + ClassesOp, Escaper, Favicon, JavaScript, Markup, PageTopSvg, PreEscaped, PrepareMarkup, + StyleSheet, TargetMedia, UnitValue, DOCTYPE, +}; pub use crate::locale::*; diff --git a/src/response/json.rs b/src/response/json.rs index fee4c12..0878999 100644 --- a/src/response/json.rs +++ b/src/response/json.rs @@ -6,8 +6,7 @@ //! tipo Rust fuertemente tipado, validando el formato y deserializando con *serde*. //! //! ```rust -//! use pagetop::prelude::*; -//! +//! # use pagetop::prelude::*; //! #[derive(serde::Deserialize)] //! struct NuevoUsuario { nombre: String, email: String } //! @@ -25,8 +24,7 @@ //! `application/json; charset=utf-8`, todo con una llamada compacta. //! //! ```rust -//! use pagetop::prelude::*; -//! +//! # use pagetop::prelude::*; //! #[derive(serde::Serialize)] //! struct Usuario { id: u32, nombre: String } //! diff --git a/src/response/page.rs b/src/response/page.rs index 2dc27f9..036c999 100644 --- a/src/response/page.rs +++ b/src/response/page.rs @@ -4,11 +4,10 @@ pub use error::ErrorPage; pub use actix_web::Result as ResultPage; use crate::base::action; -use crate::core::component::{Child, ChildOp, Component}; -use crate::core::theme::{ChildrenInRegions, ThemeRef, REGION_CONTENT}; +use crate::core::component::{Child, ChildOp, Component, Context, ContextOp, Contextual}; +use crate::core::theme::{ThemeRef, REGION_CONTENT}; use crate::html::{html, Markup, DOCTYPE}; use crate::html::{Assets, Favicon, JavaScript, StyleSheet}; -use crate::html::{AssetsOp, Context, Contextual}; use crate::html::{AttrClasses, ClassesOp}; use crate::html::{AttrId, AttrL10n}; use crate::locale::{CharacterDirection, L10n, LangId, LanguageIdentifier}; @@ -30,7 +29,6 @@ pub struct Page { body_id : AttrId, body_classes: AttrClasses, context : Context, - regions : ChildrenInRegions, } impl Page { @@ -48,11 +46,10 @@ impl Page { body_id : AttrId::default(), body_classes: AttrClasses::default(), context : Context::new(Some(request)), - regions : ChildrenInRegions::default(), } } - // Page BUILDER ******************************************************************************** + // **< Page BUILDER >*************************************************************************** /// Establece el título de la página como un valor traducible. #[builder_fn] @@ -96,62 +93,50 @@ impl Page { self } - /// **Obsoleto desde la versión 0.4.0**: usar [`add_component()`](Self::add_component) en su - /// lugar. - #[deprecated(since = "0.4.0", note = "Use `add_component()` instead")] + /// **Obsoleto desde la versión 0.4.0**: usar [`add_child()`](Self::add_child) en su lugar. + #[deprecated(since = "0.4.0", note = "Use `add_child()` instead")] pub fn with_component(self, component: impl Component) -> Self { - self.add_component(component) + self.add_child(component) } - /// **Obsoleto desde la versión 0.4.0**: usar [`add_component_in()`](Self::add_component_in) en - /// su lugar. - #[deprecated(since = "0.4.0", note = "Use `add_component_in()` instead")] - pub fn with_component_in(self, region_name: &'static str, component: impl Component) -> Self { - self.add_component_in(region_name, component) + /// **Obsoleto desde la versión 0.4.0**: usar [`add_child_in()`](Self::add_child_in) en su + /// lugar. + #[deprecated(since = "0.4.0", note = "Use `add_child_in()` instead")] + pub fn with_component_in(self, region_key: &'static str, component: impl Component) -> Self { + self.add_child_in(region_key, component) } - /// Añade un componente a la región de contenido por defecto. - pub fn add_component(mut self, component: impl Component) -> Self { - self.regions + /// Añade un componente hijo a la región de contenido por defecto. + pub fn add_child(mut self, component: impl Component) -> Self { + self.context .alter_child_in(REGION_CONTENT, ChildOp::Add(Child::with(component))); self } - /// Añade un componente en una región (`region_name`) de la página. - pub fn add_component_in( - mut self, - region_name: &'static str, - component: impl Component, - ) -> Self { - self.regions - .alter_child_in(region_name, ChildOp::Add(Child::with(component))); + /// Añade un componente hijo en una región (`region_key`) de la página. + pub fn add_child_in(mut self, region_key: &'static str, component: impl Component) -> Self { + self.context + .alter_child_in(region_key, ChildOp::Add(Child::with(component))); self } /// **Obsoleto desde la versión 0.4.0**: usar [`with_child_in()`](Self::with_child_in) en su /// lugar. #[deprecated(since = "0.4.0", note = "Use `with_child_in()` instead")] - pub fn with_child_in_region(mut self, region_name: &'static str, op: ChildOp) -> Self { - self.alter_child_in(region_name, op); + pub fn with_child_in_region(mut self, region_key: &'static str, op: ChildOp) -> Self { + self.alter_child_in(region_key, op); self } /// **Obsoleto desde la versión 0.4.0**: usar [`alter_child_in()`](Self::alter_child_in) en su /// lugar. #[deprecated(since = "0.4.0", note = "Use `alter_child_in()` instead")] - pub fn alter_child_in_region(&mut self, region_name: &'static str, op: ChildOp) -> &mut Self { - self.alter_child_in(region_name, op); + pub fn alter_child_in_region(&mut self, region_key: &'static str, op: ChildOp) -> &mut Self { + self.alter_child_in(region_key, op); self } - /// Opera con [`ChildOp`] en una región (`region_name`) de la página. - #[builder_fn] - pub fn with_child_in(mut self, region_name: &'static str, op: ChildOp) -> Self { - self.regions.alter_child_in(region_name, op); - self - } - - // Page GETTERS ******************************************************************************** + // **< Page GETTERS >*************************************************************************** /// Devuelve el título traducido para el idioma de la página, si existe. pub fn title(&mut self) -> Option<String> { @@ -192,19 +177,7 @@ impl Page { &mut self.context } - // Page RENDER ********************************************************************************* - - /// Renderiza los componentes de una región (`region_name`) de la página. - pub fn render_region(&mut self, region_name: &'static str) -> Markup { - self.regions - .merge_all_components(self.context.theme(), region_name) - .render(&mut self.context) - } - - /// Renderiza los recursos de la página. - pub fn render_assets(&mut self) -> Markup { - self.context.render_assets() - } + // **< Page RENDER >**************************************************************************** /// Renderiza la página completa en formato HTML. /// @@ -239,8 +212,14 @@ impl Page { Ok(html! { (DOCTYPE) html lang=(lang) dir=(dir) { - (head) - (body) + head { + (head) + } + body id=[self.body_id().get()] class=[self.body_classes().get()] { + (self.context.render_components_of("page-top")) + (body) + (self.context.render_components_of("page-bottom")) + } } }) } @@ -253,7 +232,7 @@ impl LangId for Page { } impl Contextual for Page { - // Contextual BUILDER ************************************************************************** + // **< Contextual BUILDER >********************************************************************* #[builder_fn] fn with_request(mut self, request: Option<HttpRequest>) -> Self { @@ -286,12 +265,18 @@ impl Contextual for Page { } #[builder_fn] - fn with_assets(mut self, op: AssetsOp) -> Self { + fn with_assets(mut self, op: ContextOp) -> Self { self.context.alter_assets(op); self } - // Contextual GETTERS ************************************************************************** + #[builder_fn] + fn with_child_in(mut self, region_key: &'static str, op: ChildOp) -> Self { + self.context.alter_child_in(region_key, op); + self + } + + // **< Contextual GETTERS >********************************************************************* fn request(&self) -> Option<&HttpRequest> { self.context.request() @@ -321,7 +306,7 @@ impl Contextual for Page { self.context.javascripts() } - // Contextual HELPERS ************************************************************************** + // **< Contextual HELPERS >********************************************************************* fn required_id<T>(&mut self, id: Option<String>) -> String { self.context.required_id::<T>(id) diff --git a/src/response/page/error.rs b/src/response/page/error.rs index 2355d23..9945a94 100644 --- a/src/response/page/error.rs +++ b/src/response/page/error.rs @@ -1,5 +1,5 @@ use crate::base::component::Html; -use crate::html::Contextual; +use crate::core::component::Contextual; use crate::locale::L10n; use crate::response::ResponseError; use crate::service::http::{header::ContentType, StatusCode}; @@ -24,9 +24,9 @@ impl Display for ErrorPage { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { // Error 304. - ErrorPage::NotModified(_) => write!(f, "Not Modified"), + ErrorPage::NotModified(_) => f.write_str("Not Modified"), // Error 400. - ErrorPage::BadRequest(_) => write!(f, "Bad Client Data"), + ErrorPage::BadRequest(_) => f.write_str("Bad Client Data"), // Error 403. ErrorPage::AccessDenied(request) => { let mut error_page = Page::new(request.clone()); @@ -34,12 +34,12 @@ impl Display for ErrorPage { if let Ok(page) = error_page .with_title(L10n::n("Error FORBIDDEN")) .with_layout("error") - .add_component(Html::with(move |_| error403.clone())) + .add_child(Html::with(move |_| error403.clone())) .render() { write!(f, "{}", page.into_string()) } else { - write!(f, "Access Denied") + f.write_str("Access Denied") } } // Error 404. @@ -49,20 +49,20 @@ impl Display for ErrorPage { if let Ok(page) = error_page .with_title(L10n::n("Error RESOURCE NOT FOUND")) .with_layout("error") - .add_component(Html::with(move |_| error404.clone())) + .add_child(Html::with(move |_| error404.clone())) .render() { write!(f, "{}", page.into_string()) } else { - write!(f, "Not Found") + f.write_str("Not Found") } } // Error 412. - ErrorPage::PreconditionFailed(_) => write!(f, "Precondition Failed"), + ErrorPage::PreconditionFailed(_) => f.write_str("Precondition Failed"), // Error 500. - ErrorPage::InternalError(_) => write!(f, "Internal Error"), + ErrorPage::InternalError(_) => f.write_str("Internal Error"), // Error 504. - ErrorPage::Timeout(_) => write!(f, "Timeout"), + ErrorPage::Timeout(_) => f.write_str("Timeout"), } } } diff --git a/src/service.rs b/src/service.rs index 09dc618..1b2f766 100644 --- a/src/service.rs +++ b/src/service.rs @@ -93,17 +93,16 @@ macro_rules! include_files_service { /// /// # Argumentos /// -/// * `$scfg` – Instancia de [`ServiceConfig`](crate::service::web::ServiceConfig) donde aplicar la +/// * `$scfg` - Instancia de [`ServiceConfig`](crate::service::web::ServiceConfig) donde aplicar la /// configuración. -/// * `$path` – Ruta al directorio local con los archivos estáticos. -/// * `$bundle` – Nombre del conjunto de recursos que esta macro integra en el binario. -/// * `$route` – Ruta URL base desde la que se servirán los archivos. +/// * `$path` - Ruta al directorio local con los archivos estáticos. +/// * `$bundle` - Nombre del conjunto de recursos que esta macro integra en el binario. +/// * `$route` - Ruta URL base desde la que se servirán los archivos. /// /// # Ejemplos /// /// ```rust,ignore -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// pub struct MyExtension; /// /// impl Extension for MyExtension { diff --git a/src/util.rs b/src/util.rs index cb10176..30b994f 100644 --- a/src/util.rs +++ b/src/util.rs @@ -6,7 +6,7 @@ use std::env; use std::io; use std::path::{Path, PathBuf}; -// MACROS INTEGRADAS ******************************************************************************* +// **< MACROS INTEGRADAS >************************************************************************** #[doc(hidden)] pub use paste::paste; @@ -16,7 +16,7 @@ pub use concat_string::concat_string; pub use indoc::{concatdoc, formatdoc, indoc}; -// MACROS ÚTILES *********************************************************************************** +// **< MACROS ÚTILES >****************************************************************************** #[macro_export] /// Macro para construir una colección de pares clave-valor. @@ -50,8 +50,7 @@ macro_rules! hm { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Concatena todos los fragmentos directamente. /// let result = join!("Hello", " ", "World"); /// assert_eq!(result, "Hello World".to_string()); @@ -66,52 +65,11 @@ macro_rules! hm { /// ``` #[macro_export] macro_rules! join { - ($($arg:tt)*) => { - $crate::util::concat_string!($($arg)*) + ($($arg:expr),+) => { + $crate::util::concat_string!($($arg),+) }; } -/// Concatena los fragmentos no vacíos en un [`Option<String>`] con un separador opcional. -/// -/// Esta macro acepta cualquier número de fragmentos que implementen [`AsRef<str>`] para concatenar -/// todos los fragmentos no vacíos usando opcionalmente un separador. -/// -/// Si todos los fragmentos están vacíos, devuelve [`None`]. -/// -/// # Ejemplo -/// -/// ```rust -/// use pagetop::prelude::*; -/// -/// // Concatena los fragmentos no vacíos con un espacio como separador. -/// let result_with_separator = join_opt!(["Hello", "", "World"]; " "); -/// assert_eq!(result_with_separator, Some("Hello World".to_string())); -/// -/// // Concatena los fragmentos no vacíos sin un separador. -/// let result_without_separator = join_opt!(["Hello", "", "World"]); -/// assert_eq!(result_without_separator, Some("HelloWorld".to_string())); -/// -/// // Devuelve `None` si todos los fragmentos están vacíos. -/// let result_empty = join_opt!(["", "", ""]); -/// assert_eq!(result_empty, None); -/// ``` -#[macro_export] -macro_rules! join_opt { - ([$($arg:expr),* $(,)?]) => {{ - let s = $crate::util::concat_string!($($arg),*); - (!s.is_empty()).then_some(s) - }}; - ([$($arg:expr),* $(,)?]; $separator:expr) => {{ - let s = [$($arg),*] - .iter() - .filter(|&item| !item.is_empty()) - .cloned() - .collect::<Vec<_>>() - .join($separator); - (!s.is_empty()).then_some(s) - }}; -} - /// Concatena dos fragmentos en un [`String`] usando un separador. /// /// Une los dos fragmentos, que deben implementar [`AsRef<str>`], usando el separador proporcionado. @@ -121,8 +79,7 @@ macro_rules! join_opt { /// # Ejemplo /// /// ```rust -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// let first = "Hello"; /// let separator = "-"; /// let second = "World"; @@ -146,59 +103,23 @@ macro_rules! join_opt { #[macro_export] macro_rules! join_pair { ($first:expr, $separator:expr, $second:expr) => {{ - if $first.is_empty() { - String::from($second) - } else if $second.is_empty() { - String::from($first) + let first_val = $first; + let second_val = $second; + let separator_val = $separator; + + let first = AsRef::<str>::as_ref(&first_val); + let second = AsRef::<str>::as_ref(&second_val); + let separator = if first.is_empty() || second.is_empty() { + "" } else { - $crate::util::concat_string!($first, $separator, $second) - } + AsRef::<str>::as_ref(&separator_val) + }; + + $crate::util::concat_string!(first, separator, second) }}; } -/// Concatena varios fragmentos en un [`Option<String>`] si ninguno está vacío. -/// -/// Si alguno de los fragmentos, que deben implementar [`AsRef<str>`], está vacío, devuelve -/// [`None`]. Opcionalmente se puede indicar un separador entre los fragmentos concatenados. -/// -/// # Ejemplo -/// -/// ```rust -/// use pagetop::prelude::*; -/// -/// // Concatena los fragmentos. -/// let result = join_strict!(["Hello", "World"]); -/// assert_eq!(result, Some("HelloWorld".to_string())); -/// -/// // Concatena los fragmentos con un separador. -/// let result_with_separator = join_strict!(["Hello", "World"]; " "); -/// assert_eq!(result_with_separator, Some("Hello World".to_string())); -/// -/// // Devuelve `None` si alguno de los fragmentos está vacío. -/// let result_with_empty = join_strict!(["Hello", "", "World"]); -/// assert_eq!(result_with_empty, None); -/// ``` -#[macro_export] -macro_rules! join_strict { - ([$($arg:expr),* $(,)?]) => {{ - let fragments = [$($arg),*]; - if fragments.iter().any(|&item| item.is_empty()) { - None - } else { - Some(fragments.concat()) - } - }}; - ([$($arg:expr),* $(,)?]; $separator:expr) => {{ - let fragments = [$($arg),*]; - if fragments.iter().any(|&item| item.is_empty()) { - None - } else { - Some(fragments.join($separator)) - } - }}; -} - -// FUNCIONES ÚTILES ******************************************************************************** +// **< FUNCIONES ÚTILES >*************************************************************************** /// Resuelve y valida la ruta de un directorio existente, devolviendo una ruta absoluta. /// @@ -211,8 +132,7 @@ macro_rules! join_strict { /// # Ejemplos /// /// ```rust,no_run -/// use pagetop::prelude::*; -/// +/// # use pagetop::prelude::*; /// // Ruta relativa, se resuelve respecto a CARGO_MANIFEST_DIR o al directorio actual (`cwd`). /// println!("{:#?}", util::resolve_absolute_dir("documents")); /// diff --git a/static/css/basic.css b/static/css/basic.css index 312ddf0..058e173 100644 --- a/static/css/basic.css +++ b/static/css/basic.css @@ -1,11 +1,21 @@ +html { + scroll-behavior: smooth; +} + +body { + margin: 0; + font-family: var(--val-font-family); + font-size: var(--val-fs--base); + font-weight: var(--val-fw--base); + line-height: var(--val-lh--base); + color: var(--val-color--text); + background-color: var(--val-color--bg); + -webkit-text-size-adjust: 100%; + -webkit-tap-highlight-color: transparent; +} + /* Page layout */ .region--footer { padding-bottom: 2rem; } - -/* PoweredBy component */ - -.poweredby { - text-align: center; -} diff --git a/static/css/components.css b/static/css/components.css new file mode 100644 index 0000000..ec5d3f0 --- /dev/null +++ b/static/css/components.css @@ -0,0 +1,12 @@ +/* Icon component */ + +.icon { + width: 1rem; + height: 1rem; +} + +/* PoweredBy component */ + +.poweredby { + text-align: center; +} diff --git a/static/css/intro.css b/static/css/intro.css index 39c9d6a..dbc7225 100644 --- a/static/css/intro.css +++ b/static/css/intro.css @@ -1,37 +1,27 @@ :root { - --bg-img: url('/img/intro-header.jpg'); - --bg-img-set: image-set(url('/img/intro-header.avif') type('image/avif'), url('/img/intro-header.webp') type('image/webp'), var(--bg-img) type('image/jpeg')); - --bg-img-sm: url('/img/intro-header-sm.jpg'); - --bg-img-sm-set: image-set(url('/img/intro-header-sm.avif') type('image/avif'), url('/img/intro-header-sm.webp') type('image/webp'), var(--bg-img-sm) type('image/jpeg')); - --bg-color: #8c5919; - --color: #1a202c; - --color-gray: #e4e4e7; - --color-link: #1e4eae; - --color-block-1: #b689ff; - --color-block-2: #fecaca; - --color-block-3: #e6a9e2; - --color-block-4: #ffedca; - --color-block-5: #ffffff; - --focus-outline: 2px solid var(--color-link); - --focus-outline-offset: 2px; - --shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); + --intro-bg-img: url('/img/intro-header.jpg'); + --intro-bg-img-set: image-set(url('/img/intro-header.avif') type('image/avif'), url('/img/intro-header.webp') type('image/webp'), var(--intro-bg-img) type('image/jpeg')); + --intro-bg-img-sm: url('/img/intro-header-sm.jpg'); + --intro-bg-img-sm-set: image-set(url('/img/intro-header-sm.avif') type('image/avif'), url('/img/intro-header-sm.webp') type('image/webp'), var(--intro-bg-img-sm) type('image/jpeg')); + --intro-bg-color: #8c5919; + --intro-bg-block-1: #b689ff; + --intro-bg-block-2: #fecaca; + --intro-bg-block-3: #e6a9e2; + --intro-bg-block-4: #ffedca; + --intro-bg-block-5: #ffffff; + --intro-color: #1a202c; + --intro-color-gray: #e4e4e7; + --intro-color-link: #1e4eae; + --intro-focus-outline: 2px solid var(--intro-color-link); + --intro-focus-outline-offset: 2px; + --intro-shadow: 0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06); } -html { - min-height: 100%; - background-color: black; -} -body { - margin: auto; +.intro { position: relative; - min-height: 100%; min-width: 350px; - background-color: var(--bg-color); - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; - font-size: 1.125rem; - font-weight: 300; - color: var(--color); - line-height: 1.6; + color: var(--intro-color); + background-color: var(--intro-bg-color); width: 100%; display: flex; @@ -40,23 +30,23 @@ body { align-items: center; } -section { +.intro section { position: relative; text-align: center; } -a { +.intro a { color: currentColor; text-decoration: underline; transition: font-size 0.2s, text-decoration-color 0.2s; } -a:focus-visible { - outline: var(--focus-outline); - outline-offset: var(--focus-outline-offset); +.intro a:focus-visible { + outline: var(--intro-focus-outline); + outline-offset: var(--intro-focus-outline-offset); } -a:hover, -a:hover:visited { - text-decoration-color: var(--color-link); +.intro a:hover, +.intro a:hover:visited { + text-decoration-color: var(--intro-color-link); } /* @@ -69,9 +59,9 @@ a:hover:visited { width: 100%; max-width: 80rem; margin: 0 auto; - padding-bottom: 9rem; - background-image: var(--bg-img-sm); - background-image: var(--bg-img-sm-set); + padding-bottom: 4rem; + background-image: var(--intro-bg-img-sm); + background-image: var(--intro-bg-img-sm-set); background-position: top center; background-position-y: -1rem; background-size: contain; @@ -113,14 +103,15 @@ a:hover:visited { width: 100%; } .intro-header__monster { - margin-right: 12rem; - margin-top: 1rem; + margin: 2rem; flex-shrink: 1; + width: 280px; + height: 280px; } @media (min-width: 64rem) { .intro-header { - background-image: var(--bg-img); - background-image: var(--bg-img-set); + background-image: var(--intro-bg-img); + background-image: var(--intro-bg-img-set); } .intro-header__title { padding: 1.2rem 2rem 2.6rem 2rem; @@ -128,6 +119,9 @@ a:hover:visited { .intro-header__image { justify-content: flex-end; } + .intro-header__monster { + margin-right: 12rem; + } } /* @@ -180,8 +174,7 @@ a:hover:visited { .intro-button { width: 100%; - margin: 0 auto 3rem; - z-index: 10; + margin: 0 auto; } .intro-button__link { background: #7f1d1d; @@ -195,8 +188,8 @@ a:hover:visited { justify-content: space-between; font-size: 1.5rem; line-height: 1.3; - text-decoration: none; - transition: transform 0.3s ease-in-out; + text-decoration: none !important; + transition: transform 0.3s ease-in-out !important; position: relative; overflow: hidden; min-width: 28.875rem; @@ -306,6 +299,9 @@ a:hover:visited { animation-play-state: paused; } @media (max-width: 48rem) { + .intro-header { + padding-bottom: 9rem;; + } .intro-button__link { height: 6.25rem; min-width: auto; @@ -327,7 +323,7 @@ a:hover:visited { } .intro-button__link:hover { transition: all .5s; - transform: rotate(-3deg) scale(1.1); + transform: rotate(-3deg) scale(1.125); } } @@ -342,17 +338,15 @@ a:hover:visited { font-size: 1.3125rem; font-weight: 400; line-height: 1.5; - margin-top: -6rem; margin-bottom: 0; background: #fff; position: relative; +} +.intro-text__children { padding: 2.5rem 1.063rem 0.75rem; overflow: hidden; } -.intro-button + .intro-text { - padding-top: 6rem; -} -.intro-text p { +.intro-text__children p { width: 100%; line-height: 150%; font-weight: 400; @@ -364,31 +358,39 @@ a:hover:visited { font-size: 1.375rem; line-height: 2rem; } - .intro-button + .intro-text { + .intro-button + .intro-text__children { padding-top: 7rem; } } @media (min-width: 64rem) { - .intro-text { + .intro-header { + padding-bottom: 9rem;; + } + .intro-text, + .intro-text__children { border-radius: 0.75rem; - box-shadow: var(--shadow); + } + .intro-text { + box-shadow: var(--intro-shadow); max-width: 60rem; margin: 0 auto 6rem; + } + .intro-text__children { padding-left: 4.5rem; padding-right: 4.5rem; } } -.intro-text .block { +.intro-text__children .block { position: relative; } -.intro-text .block__title { +.intro-text__children .block__title { margin: 1em 0 .8em; } -.intro-text .block__title span { +.intro-text__children .block__title span { display: inline-block; padding: 10px 30px 14px; - margin: 0 0 0 20px; + margin: 30px 0 0 20px; background: white; border: 5px solid; border-radius: 30px; @@ -396,7 +398,7 @@ a:hover:visited { border-color: orangered; transform: rotate(-3deg) translateY(-25%); } -.intro-text .block__title:before { +.intro-text__children .block__title:before { content: ""; height: 5px; position: absolute; @@ -409,7 +411,7 @@ a:hover:visited { transform: rotate(2deg) translateY(-50%); transform-origin: top left; } -.intro-text .block__title:after { +.intro-text__children .block__title:after { content: ""; height: 70rem; position: absolute; @@ -417,23 +419,29 @@ a:hover:visited { left: -15%; width: 130%; z-index: -10; - background: var(--color-block-1); + background: var(--intro-bg-block-1); transform: rotate(2deg); } -.intro-text .block:nth-of-type(5n+1) .block__title:after { - background: var(--color-block-1); +.intro-text__children .block:nth-of-type(5n+1) .block__title:after { + background: var(--intro-bg-block-1); } -.intro-text .block:nth-of-type(5n+2) .block__title:after { - background: var(--color-block-2); +.intro-text__children .block:nth-of-type(5n+2) .block__title:after { + background: var(--intro-bg-block-2); } -.intro-text .block:nth-of-type(5n+3) .block__title:after { - background: var(--color-block-3); +.intro-text__children .block:nth-of-type(5n+3) .block__title:after { + background: var(--intro-bg-block-3); } -.intro-text .block:nth-of-type(5n+4) .block__title:after { - background: var(--color-block-4); +.intro-text__children .block:nth-of-type(5n+4) .block__title:after { + background: var(--intro-bg-block-4); } -.intro-text .block:nth-of-type(5n+5) .block__title:after { - background: var(--color-block-5); +.intro-text__children .block:nth-of-type(5n+5) .block__title:after { + background: var(--intro-bg-block-5); +} + +#intro-badges { + display: none; + margin-bottom: 1.1rem; + text-align: center; } /* @@ -443,7 +451,7 @@ a:hover:visited { .intro-footer { width: 100%; background-color: black; - color: var(--color-gray); + color: var(--intro-color-gray); padding-bottom: 2rem; } @@ -459,7 +467,7 @@ a:hover:visited { line-height: 100%; } .intro-footer__body a:visited { - color: var(--color-gray); + color: var(--intro-color-gray); } .intro-footer__logo, .intro-footer__links { @@ -488,9 +496,3 @@ a:hover:visited { padding: 0 1rem 2rem; } } - -/* PoweredBy component */ - -.poweredby a:visited { - color: var(--color-gray); -} diff --git a/static/css/root.css b/static/css/root.css new file mode 100644 index 0000000..aeab1c6 --- /dev/null +++ b/static/css/root.css @@ -0,0 +1,212 @@ +:root { + --val-font-sans: system-ui,-apple-system,"Segoe UI",Roboto,"Helvetica Neue",Arial,"Noto Sans","Liberation Sans",sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"; + --val-font-serif: "Lora","georgia",serif; + --val-font-monospace: SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace; + --val-font-family: var(--val-font-sans); + + /* Font size */ + --val-fs--x3l: 2.5rem; + --val-fs--x2l: 2rem; + --val-fs--xl: 1.75rem; + --val-fs--l: 1.5rem; + --val-fs--m: 1.25rem; + --val-fs--base: 1rem; + --val-fs--s: 0.875rem; + --val-fs--xs: 0.75rem; + --val-fs--x2s: 0.5625rem; + --val-fs--x3s: 0.375rem; + + /* Font weight */ + --val-fw--light: 300; + --val-fw--base: 400; + --val-fw--bold: 500; + + /* Line height */ + --val-lh--base: 1.5; + --val-lh--header: 1.2; + + --val-max-width: 90rem; +/* + --val-color-rgb: 33,37,41; + --val-main--bg-rgb: 255,255,255; + --val-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0)); + + --line-height-base: 1.6875rem; + --line-height-s: 1.125rem; + --max-bg-color: 98.125rem; +*/ + --val-gap: 1.125rem; +/* + --content-left: 5.625rem; + --site-header-height-wide: var(--val-gap10); + --container-padding: var(--val-gap); +*/ +} +/* +@media (min-width: 75rem) { + :root { + --container-padding:var(--val-gap2); + } +} + +:root { + --scrollbar-width: 0px; + --grid-col-count: 6; + --grid-gap: var(--val-gap); + --grid-gap-count: calc(var(--grid-col-count) - 1); + --grid-full-width: calc(100vw - var(--val-gap2) - var(--scrollbar-width)); + --grid-col-width: calc((var(--grid-full-width) - (var(--grid-gap-count) * var(--grid-gap))) / var(--grid-col-count)); +} + +@media (min-width: 43.75rem) { + :root { + --grid-col-count:14; + --grid-gap: var(--val-gap2); + } +} + +@media (min-width: 62.5rem) { + :root { + --scrollbar-width:0.9375rem; + } +} + +@media (min-width: 75rem) { + :root { + --grid-full-width:calc(100vw - var(--scrollbar-width) - var(--content-left) - var(--val-gap4)); + } +} + +@media (min-width: 90rem) { + :root { + --grid-full-width:calc(var(--max-width) - var(--val-gap4)); + } +} +*/ +:root { + --val-gap-0-15: calc(0.15 * var(--val-gap)); + --val-gap-0-25: calc(0.25 * var(--val-gap)); + --val-gap-0-35: calc(0.35 * var(--val-gap)); + --val-gap-0-5: calc(0.5 * var(--val-gap)); + --val-gap-0-75: calc(0.75 * var(--val-gap)); + --val-gap-1-5: calc(1.5 * var(--val-gap)); + --val-gap-2: calc(2 * var(--val-gap)); + + --primary-hue: 216; + --primary-sat: 60%; + --val-color--primary: hsl(var(--primary-hue), var(--primary-sat), 50%); + --val-color--primary-light: hsl(var(--primary-hue), var(--primary-sat), 60%); + --val-color--primary-dark: hsl(var(--primary-hue), var(--primary-sat), 40%); + --val-color--primary-link: hsl(var(--primary-hue), var(--primary-sat), 55%); + --val-color--primary-link-hover: hsl(var(--primary-hue), var(--primary-sat), 30%); + --val-color--primary-link-active: hsl(var(--primary-hue), var(--primary-sat), 70%); + + --info-hue: 190; + --info-sat: 90%; + --val-color--info: hsl(var(--info-hue), var(--info-sat), 54%); + --val-color--info-light: hsl(var(--info-hue), var(--info-sat), 70%); + --val-color--info-dark: hsl(var(--info-hue), var(--info-sat), 45%); + --val-color--info-link: hsl(var(--info-hue), var(--info-sat), 30%); + --val-color--info-link-hover: hsl(var(--info-hue), var(--info-sat), 20%); + --val-color--info-link-active: hsl(var(--info-hue), var(--info-sat), 40%); + + --success-hue: 150; + --success-sat: 50%; + --val-color--success: hsl(var(--success-hue), var(--success-sat), 50%); + --val-color--success-light: hsl(var(--success-hue), var(--success-sat), 68%); + --val-color--success-dark: hsl(var(--success-hue), var(--success-sat), 38%); + --val-color--success-link: hsl(var(--success-hue), var(--success-sat), 26%); + --val-color--success-link-hover: hsl(var(--success-hue), var(--success-sat), 18%); + --val-color--success-link-active: hsl(var(--success-hue), var(--success-sat), 36%); + + --warning-hue: 44; + --warning-sat: 100%; + --val-color--warning: hsl(var(--warning-hue), var(--warning-sat), 50%); + --val-color--warning-light: hsl(var(--warning-hue), var(--warning-sat), 60%); + --val-color--warning-dark: hsl(var(--warning-hue), var(--warning-sat), 40%); + --val-color--warning-link: hsl(var(--warning-hue), var(--warning-sat), 30%); + --val-color--warning-link-hover: hsl(var(--warning-hue), var(--warning-sat), 20%); + --val-color--warning-link-active: hsl(var(--warning-hue), var(--warning-sat), 38%); + + --danger-hue: 348; + --danger-sat: 86%; + --val-color--danger: hsl(var(--danger-hue), var(--danger-sat), 50%); + --val-color--danger-light: hsl(var(--danger-hue), var(--danger-sat), 60%); + --val-color--danger-dark: hsl(var(--danger-hue), var(--danger-sat), 35%); + --val-color--danger-link: hsl(var(--danger-hue), var(--danger-sat), 25%); + --val-color--danger-link-hover: hsl(var(--danger-hue), var(--danger-sat), 10%); + --val-color--danger-link-active: hsl(var(--danger-hue), var(--danger-sat), 30%); + + --light-hue: 0; + --light-sat: 0%; + --val-color--light: hsl(var(--light-hue), var(--light-sat), 96%); + --val-color--light-light: hsl(var(--light-hue), var(--light-sat), 98%); + --val-color--light-dark: hsl(var(--light-hue), var(--light-sat), 92%); + + --dark-hue: 0; + --dark-sat: 0%; + --val-color--dark: hsl(var(--dark-hue), var(--dark-sat), 25%); + --val-color--dark-light: hsl(var(--dark-hue), var(--dark-sat), 40%); + --val-color--dark-dark: hsl(var(--dark-hue), var(--dark-sat), 8%); + --val-color--dark-link: hsl(var(--dark-hue), var(--dark-sat), 90%); + --val-color--dark-link-hover: hsl(var(--dark-hue), var(--dark-sat), 100%); + --val-color--dark-link-active: hsl(var(--dark-hue), var(--dark-sat), 70%); + + + + + --gray-hue: 201; + --gray-sat: 15%; + --val-color--gray-5: hsl(var(--gray-hue), var(--gray-sat), 5%); + --val-color--gray-10: hsl(var(--gray-hue), var(--gray-sat) ,11%); + --val-color--gray-20: hsl(var(--gray-hue), var(--gray-sat),20%); + --val-color--gray-45: hsl(var(--gray-hue), var(--gray-sat), 44%); + --val-color--gray-60: hsl(var(--gray-hue), var(--gray-sat), 57%); + --val-color--gray-65: hsl(var(--gray-hue), var(--gray-sat), 63%); + --val-color--gray-70: hsl(var(--gray-hue), var(--gray-sat), 72%); + --val-color--gray-90: hsl(var(--gray-hue), var(--gray-sat), 88%); + --val-color--gray-95: hsl(var(--gray-hue), var(--gray-sat), 93%); + --val-color--gray-100: hsl(var(--gray-hue), var(--gray-sat), 97%); + + + + + --val-color--bg: #fafafa; + --val-color--text: #212529; + --val-color--white: #fff; + +/* + + + --color-text-neutral-soft: var(--color--gray-45); + --color-text-neutral-medium: var(--color--gray-20); + --color-text-neutral-loud: var(--color--gray-5); + --color-text-primary-medium: var(--val-color--primary-40); + --color-text-primary-loud: var(--val-color--primary-30); + --color--black: #000; +*/ +/* + --color--red: #e33f1e; + --color--gold: #fdca40; + --color--green: #3fa21c; + --header-height-wide-when-fixed: calc(6 * var(--val-gap)); + --mobile-nav-width: 31.25rem; + + --val-menu--border-radius: 0.625rem; +*/ + --val-border-radius: 0.375rem; + + /* Menu component */ + --val-menu--color-bg: var(--val-color--bg); + --val-menu--color-highlight: #e91e63; + --val-menu--color-border: rgba(0, 0, 0, 0.1); + --val-menu--color-shadow: rgba(0, 0, 0, 0.06); + --val-menu--line-padding: 0.625rem; + --val-menu--line-height: calc(1.875rem + 1px); + --val-menu--item-height: calc(var(--val-menu--line-padding) + var(--val-menu--line-height)); + --val-menu--item-width-min: 14rem; + --val-menu--item-width-max: 20rem; + --val-menu--item-gap: 1rem; + --val-menu--trigger-width: 2.675rem; + --val-menu--side-width: 20rem; +} diff --git a/static/img/monster-pagetop_250.avif b/static/img/monster-pagetop_250.avif deleted file mode 100644 index df864b8..0000000 Binary files a/static/img/monster-pagetop_250.avif and /dev/null differ diff --git a/static/img/monster-pagetop_250.png b/static/img/monster-pagetop_250.png deleted file mode 100644 index baa7d1f..0000000 Binary files a/static/img/monster-pagetop_250.png and /dev/null differ diff --git a/static/img/monster-pagetop_250.webp b/static/img/monster-pagetop_250.webp deleted file mode 100644 index dcc5ef2..0000000 Binary files a/static/img/monster-pagetop_250.webp and /dev/null differ diff --git a/static/img/monster-pagetop_500.avif b/static/img/monster-pagetop_500.avif deleted file mode 100644 index d07f359..0000000 Binary files a/static/img/monster-pagetop_500.avif and /dev/null differ diff --git a/static/img/monster-pagetop_500.png b/static/img/monster-pagetop_500.png deleted file mode 100644 index d0b9e0b..0000000 Binary files a/static/img/monster-pagetop_500.png and /dev/null differ diff --git a/static/img/monster-pagetop_500.webp b/static/img/monster-pagetop_500.webp deleted file mode 100644 index 18896fe..0000000 Binary files a/static/img/monster-pagetop_500.webp and /dev/null differ diff --git a/tests/component_html.rs b/tests/component_html.rs index 851315a..06d77ec 100644 --- a/tests/component_html.rs +++ b/tests/component_html.rs @@ -2,32 +2,28 @@ use pagetop::prelude::*; #[pagetop::test] async fn component_html_renders_static_markup() { - let component = Html::with(|_| { + let mut component = Html::with(|_| { html! { p { "Test" } } }); - let markup = component - .prepare_component(&mut Context::new(None)) - .render(); - + let markup = component.render(&mut Context::default()); assert_eq!(markup.0, "<p>Test</p>"); } #[pagetop::test] async fn component_html_renders_using_context_param() { - let mut cx = Context::new(None).with_param("username", "Alice".to_string()); + let mut cx = Context::default().with_param("username", "Alice".to_string()); - let component = Html::with(|cx| { + let mut component = Html::with(|cx| { let name = cx.param::<String>("username").cloned().unwrap_or_default(); html! { span { (name) } } }); - let markup = component.prepare_component(&mut cx).render(); - + let markup = component.render(&mut cx); assert_eq!(markup.0, "<span>Alice</span>"); } @@ -37,21 +33,15 @@ async fn component_html_allows_replacing_render_function() { component.alter_fn(|_| html! { div { "Modified" } }); - let markup = component - .prepare_component(&mut Context::new(None)) - .render(); - + let markup = component.render(&mut Context::default()); assert_eq!(markup.0, "<div>Modified</div>"); } #[pagetop::test] async fn component_html_default_renders_empty_markup() { - let component = Html::default(); - - let markup = component - .prepare_component(&mut Context::new(None)) - .render(); + let mut component = Html::default(); + let markup = component.render(&mut Context::default()); assert_eq!(markup.0, ""); } @@ -60,7 +50,7 @@ async fn component_html_can_access_http_method() { let req = service::test::TestRequest::with_uri("/").to_http_request(); let mut cx = Context::new(Some(req)); - let component = Html::with(|cx| { + let mut component = Html::with(|cx| { let method = cx .request() .map(|r| r.method().to_string()) @@ -68,7 +58,6 @@ async fn component_html_can_access_http_method() { html! { span { (method) } } }); - let markup = component.prepare_component(&mut cx).render(); - + let markup = component.render(&mut cx); assert_eq!(markup.0, "<span>GET</span>"); } diff --git a/tests/component_poweredby.rs b/tests/component_poweredby.rs index e4551d1..7e5a062 100644 --- a/tests/component_poweredby.rs +++ b/tests/component_poweredby.rs @@ -4,8 +4,8 @@ use pagetop::prelude::*; async fn poweredby_default_shows_only_pagetop_recognition() { let _app = service::test::init_service(Application::new().test()).await; - let p = PoweredBy::default(); - let html = render_component(&p); + let mut p = PoweredBy::default(); + let html = p.render(&mut Context::default()); // Debe mostrar el bloque de reconocimiento a PageTop. assert!(html.as_str().contains("poweredby__pagetop")); @@ -18,8 +18,8 @@ async fn poweredby_default_shows_only_pagetop_recognition() { async fn poweredby_new_includes_current_year_and_app_name() { let _app = service::test::init_service(Application::new().test()).await; - let p = PoweredBy::new(); - let html = render_component(&p); + let mut p = PoweredBy::new(); + let html = p.render(&mut Context::default()); let year = Utc::now().format("%Y").to_string(); assert!( @@ -43,8 +43,8 @@ async fn poweredby_with_copyright_overrides_text() { let _app = service::test::init_service(Application::new().test()).await; let custom = "2001 © FooBar Inc."; - let p = PoweredBy::default().with_copyright(Some(custom)); - let html = render_component(&p); + let mut p = PoweredBy::default().with_copyright(Some(custom)); + let html = p.render(&mut Context::default()); assert!(html.as_str().contains(custom)); assert!(html.as_str().contains("poweredby__copyright")); @@ -54,8 +54,8 @@ async fn poweredby_with_copyright_overrides_text() { async fn poweredby_with_copyright_none_hides_text() { let _app = service::test::init_service(Application::new().test()).await; - let p = PoweredBy::new().with_copyright(None::<String>); - let html = render_component(&p); + let mut p = PoweredBy::new().with_copyright(None::<String>); + let html = p.render(&mut Context::default()); assert!(!html.as_str().contains("poweredby__copyright")); // El reconocimiento a PageTop siempre debe aparecer. @@ -66,8 +66,8 @@ async fn poweredby_with_copyright_none_hides_text() { async fn poweredby_link_points_to_crates_io() { let _app = service::test::init_service(Application::new().test()).await; - let p = PoweredBy::default(); - let html = render_component(&p); + let mut p = PoweredBy::default(); + let html = p.render(&mut Context::default()); assert!( html.as_str().contains("https://pagetop.cillero.es"), @@ -89,11 +89,3 @@ async fn poweredby_getter_reflects_internal_state() { assert!(c1.contains(&Utc::now().format("%Y").to_string())); assert!(c1.contains(&global::SETTINGS.app.name)); } - -// HELPERS ***************************************************************************************** - -fn render_component<C: Component>(c: &C) -> Markup { - let mut cx = Context::default(); - let pm = c.prepare_component(&mut cx); - pm.render() -} diff --git a/tests/html.rs b/tests/html.rs deleted file mode 100644 index ae4517b..0000000 --- a/tests/html.rs +++ /dev/null @@ -1,108 +0,0 @@ -use pagetop::prelude::*; - -#[pagetop::test] -async fn prepare_markup_render_none_is_empty_string() { - assert_eq!(PrepareMarkup::None.render().as_str(), ""); -} - -#[pagetop::test] -async fn prepare_markup_render_escaped_escapes_html_and_ampersands() { - let pm = PrepareMarkup::Escaped("<b>& \" ' </b>".to_string()); - assert_eq!(pm.render().as_str(), "&lt;b&gt;&amp; &quot; ' &lt;/b&gt;"); -} - -#[pagetop::test] -async fn prepare_markup_render_raw_is_inserted_verbatim() { - let pm = PrepareMarkup::Raw("<b>bold</b><script>1<2</script>".to_string()); - assert_eq!(pm.render().as_str(), "<b>bold</b><script>1<2</script>"); -} - -#[pagetop::test] -async fn prepare_markup_render_with_keeps_structure() { - let pm = PrepareMarkup::With(html! { - h2 { "Sample title" } - p { "This is a paragraph." } - }); - assert_eq!( - pm.render().as_str(), - "<h2>Sample title</h2><p>This is a paragraph.</p>" - ); -} - -#[pagetop::test] -async fn prepare_markup_does_not_double_escape_when_wrapped_in_html_macro() { - // Escaped: dentro de `html!` no debe volver a escaparse. - let escaped = PrepareMarkup::Escaped("<i>x</i>".into()); - let wrapped_escaped = html! { div { (escaped.render()) } }; - assert_eq!( - wrapped_escaped.into_string(), - "<div>&lt;i&gt;x&lt;/i&gt;</div>" - ); - - // Raw: tampoco debe escaparse al integrarlo. - let raw = PrepareMarkup::Raw("<i>x</i>".into()); - let wrapped_raw = html! { div { (raw.render()) } }; - assert_eq!(wrapped_raw.into_string(), "<div><i>x</i></div>"); - - // With: debe incrustar el Markup tal cual. - let with = PrepareMarkup::With(html! { span.title { "ok" } }); - let wrapped_with = html! { div { (with.render()) } }; - assert_eq!( - wrapped_with.into_string(), - "<div><span class=\"title\">ok</span></div>" - ); -} - -#[pagetop::test] -async fn prepare_markup_unicode_is_preserved() { - // Texto con acentos y emojis debe conservarse (salvo el escape HTML de signos). - let esc = PrepareMarkup::Escaped("Hello, tomorrow coffee ☕ & donuts!".into()); - assert_eq!( - esc.render().as_str(), - "Hello, tomorrow coffee ☕ &amp; donuts!" - ); - - // Raw debe pasar íntegro. - let raw = PrepareMarkup::Raw("Title — section © 2025".into()); - assert_eq!(raw.render().as_str(), "Title — section © 2025"); -} - -#[pagetop::test] -async fn prepare_markup_is_empty_semantics() { - assert!(PrepareMarkup::None.is_empty()); - - assert!(PrepareMarkup::Escaped(String::new()).is_empty()); - assert!(PrepareMarkup::Escaped("".to_string()).is_empty()); - assert!(!PrepareMarkup::Escaped("x".to_string()).is_empty()); - - assert!(PrepareMarkup::Raw(String::new()).is_empty()); - assert!(PrepareMarkup::Raw("".to_string()).is_empty()); - assert!(!PrepareMarkup::Raw("a".into()).is_empty()); - - assert!(PrepareMarkup::With(html! {}).is_empty()); - assert!(!PrepareMarkup::With(html! { span { "!" } }).is_empty()); - - // Ojo: espacios NO deberían considerarse vacíos (comportamiento actual). - assert!(!PrepareMarkup::Escaped(" ".into()).is_empty()); - assert!(!PrepareMarkup::Raw(" ".into()).is_empty()); -} - -#[pagetop::test] -async fn prepare_markup_equivalence_between_render_and_inline_in_html_macro() { - let cases = [ - PrepareMarkup::None, - PrepareMarkup::Escaped("<b>x</b>".into()), - PrepareMarkup::Raw("<b>x</b>".into()), - PrepareMarkup::With(html! { b { "x" } }), - ]; - - for pm in cases { - let rendered = pm.render(); - let in_macro = html! { (rendered) }.into_string(); - assert_eq!( - rendered.as_str(), - in_macro, - "The output of Render and (pm) inside html! must match" - ); - } -} diff --git a/tests/html_pm.rs b/tests/html_pm.rs new file mode 100644 index 0000000..615ea47 --- /dev/null +++ b/tests/html_pm.rs @@ -0,0 +1,144 @@ +use pagetop::prelude::*; + +/// Componente mínimo para probar `PrepareMarkup` pasando por el ciclo real +/// de renderizado de componentes (`ComponentRender`). +#[derive(AutoDefault)] +struct TestPrepareComponent { + pm: PrepareMarkup, +} + +impl Component for TestPrepareComponent { + fn new() -> Self { + Self { + pm: PrepareMarkup::None, + } + } + + fn prepare_component(&self, _cx: &mut Context) -> PrepareMarkup { + self.pm.clone() + } +} + +impl TestPrepareComponent { + fn render_pm(pm: PrepareMarkup) -> String { + let mut c = TestPrepareComponent { pm }; + c.render(&mut Context::default()).into_string() + } +} + +#[pagetop::test] +async fn prepare_markup_none_is_empty_string() { + assert_eq!(PrepareMarkup::None.into_string(), ""); +} + +#[pagetop::test] +async fn prepare_markup_escaped_escapes_html_and_ampersands() { + let pm = PrepareMarkup::Escaped("<b>& \" ' </b>".to_string()); + assert_eq!(pm.into_string(), "&lt;b&gt;&amp; &quot; ' &lt;/b&gt;"); +} + +#[pagetop::test] +async fn prepare_markup_raw_is_inserted_verbatim() { + let pm = PrepareMarkup::Raw("<b>bold</b><script>1<2</script>".to_string()); + assert_eq!(pm.into_string(), "<b>bold</b><script>1<2</script>"); +} + +#[pagetop::test] +async fn prepare_markup_with_keeps_structure() { + let pm = PrepareMarkup::With(html! { + h2 { "Sample title" } + p { "This is a paragraph." } + }); + assert_eq!( + pm.into_string(), + "<h2>Sample title</h2><p>This is a paragraph.</p>" + ); +} + +#[pagetop::test] +async fn prepare_markup_unicode_is_preserved() { + // Texto con acentos y emojis debe conservarse (salvo el escape HTML de signos). + let esc = PrepareMarkup::Escaped("Hello, tomorrow coffee ☕ & donuts!".into()); + assert_eq!(esc.into_string(), "Hello, tomorrow coffee ☕ &amp; donuts!"); + + // Raw debe pasar íntegro. + let raw = PrepareMarkup::Raw("Title — section © 2025".into()); + assert_eq!(raw.into_string(), "Title — section © 2025"); +} + +#[pagetop::test] +async fn prepare_markup_is_empty_semantics() { + assert!(PrepareMarkup::None.is_empty()); + + assert!(PrepareMarkup::Escaped(String::new()).is_empty()); + assert!(PrepareMarkup::Escaped("".to_string()).is_empty()); + assert!(!PrepareMarkup::Escaped("x".to_string()).is_empty()); + + assert!(PrepareMarkup::Raw(String::new()).is_empty()); + assert!(PrepareMarkup::Raw("".to_string()).is_empty()); + assert!(!PrepareMarkup::Raw("a".into()).is_empty()); + + assert!(PrepareMarkup::With(html! {}).is_empty()); + assert!(!PrepareMarkup::With(html! { span { "!" } }).is_empty()); + + // Ojo: espacios NO deberían considerarse vacíos (comportamiento actual). + assert!(!PrepareMarkup::Escaped(" ".into()).is_empty()); + assert!(!PrepareMarkup::Raw(" ".into()).is_empty()); +} + +#[pagetop::test] +async fn prepare_markup_does_not_double_escape_when_markup_is_reinjected_in_html_macro() { + let mut cx = Context::default(); + + // Escaped: dentro de `html!` no debe volver a escaparse. + let mut comp = TestPrepareComponent { + pm: PrepareMarkup::Escaped("<i>x</i>".into()), + }; + let markup = comp.render(&mut cx); // Markup + let wrapped_escaped = html! { div { (markup) } }.into_string(); + assert_eq!(wrapped_escaped, "<div>&lt;i&gt;x&lt;/i&gt;</div>"); + + // Raw: tampoco debe escaparse al integrarlo. + let mut comp = TestPrepareComponent { + pm: PrepareMarkup::Raw("<i>x</i>".into()), + }; + let markup = comp.render(&mut cx); + let wrapped_raw = html! { div { (markup) } }.into_string(); + assert_eq!(wrapped_raw, "<div><i>x</i></div>"); + + // With: debe incrustar el Markup tal cual. + let mut comp = TestPrepareComponent { + pm: PrepareMarkup::With(html! { span.title { "ok" } }), + }; + let markup = comp.render(&mut cx); + let wrapped_with = html! { div { (markup) } }.into_string(); + assert_eq!(wrapped_with, "<div><span class=\"title\">ok</span></div>"); +} + +#[pagetop::test] +async fn prepare_markup_equivalence_between_component_render_and_markup_reinjected_in_html_macro() { + let cases = [ + PrepareMarkup::None, + PrepareMarkup::Escaped("<b>x</b>".into()), + PrepareMarkup::Raw("<b>x</b>".into()), + PrepareMarkup::With(html! { b { "x" } }), + ]; + + for pm in cases { + // Vía 1: renderizamos y obtenemos directamente el String. + let via_component = TestPrepareComponent::render_pm(pm.clone()); + + // Vía 2: renderizamos, reinyectamos el Markup en `html!` y volvemos a obtener String. + let via_macro = { + let mut cx = Context::default(); + let mut comp = TestPrepareComponent { pm }; + let markup = comp.render(&mut cx); + html! { (markup) }.into_string() + }; + + assert_eq!( + via_component, via_macro, + "The output of component render and (Markup) inside html! must match" + ); + } +} diff --git a/tests/html_unit.rs b/tests/html_unit.rs new file mode 100644 index 0000000..6acae93 --- /dev/null +++ b/tests/html_unit.rs @@ -0,0 +1,223 @@ +use pagetop::prelude::*; + +use std::str::FromStr; + +#[pagetop::test] +async fn unit_value_empty_and_auto_and_zero_without_unit() { + assert_eq!(UnitValue::from_str("").unwrap(), UnitValue::None); + assert_eq!(UnitValue::from_str("auto").unwrap(), UnitValue::Auto); + assert_eq!(UnitValue::from_str("AUTO").unwrap(), UnitValue::Auto); + + // Cero sin unidad. + assert_eq!(UnitValue::from_str("0").unwrap(), UnitValue::Zero); + assert_eq!(UnitValue::from_str("+0").unwrap(), UnitValue::Zero); + assert_eq!(UnitValue::from_str("-0").unwrap(), UnitValue::Zero); +} + +#[pagetop::test] +async fn unit_value_absolute_integers_with_signs_and_spaces_and_case() { + // Positivos, negativos y con espacios. + assert_eq!(UnitValue::from_str("12px").unwrap(), UnitValue::Px(12)); + assert_eq!(UnitValue::from_str("-5pt").unwrap(), UnitValue::Pt(-5)); + assert_eq!(UnitValue::from_str(" 7 cm ").unwrap(), UnitValue::Cm(7)); + assert_eq!(UnitValue::from_str("+9 in").unwrap(), UnitValue::In(9)); + assert_eq!(UnitValue::from_str(" 13 mm ").unwrap(), UnitValue::Mm(13)); + assert_eq!(UnitValue::from_str("4 pc").unwrap(), UnitValue::Pc(4)); + + // Insensibilidad a mayúsculas. + assert_eq!(UnitValue::from_str("10PX").unwrap(), UnitValue::Px(10)); + assert_eq!(UnitValue::from_str("15Pt").unwrap(), UnitValue::Pt(15)); +} + +#[pagetop::test] +async fn unit_value_relative_floats_with_signs_and_spaces_and_case() { + assert_eq!( + UnitValue::from_str("1.25rem").unwrap(), + UnitValue::RelRem(1.25) + ); + assert_eq!( + UnitValue::from_str("-0.5em").unwrap(), + UnitValue::RelEm(-0.5) + ); + assert_eq!( + UnitValue::from_str(" 33% ").unwrap(), + UnitValue::RelPct(33.0) + ); + assert_eq!( + UnitValue::from_str(" -12.5 vh").unwrap(), + UnitValue::RelVh(-12.5) + ); + assert_eq!( + UnitValue::from_str(" 8.0 VW ").unwrap(), + UnitValue::RelVw(8.0) + ); +} + +#[pagetop::test] +async fn unit_value_whitespace_between_number_and_unit_is_allowed() { + // Hay espacio entre número y unidad (la implementación actual lo admite). + assert_eq!(UnitValue::from_str("12 px").unwrap(), UnitValue::Px(12)); + assert_eq!( + UnitValue::from_str("1.5 rem").unwrap(), + UnitValue::RelRem(1.5) + ); + assert_eq!( + UnitValue::from_str("25 %").unwrap(), + UnitValue::RelPct(25.0) + ); +} + +#[pagetop::test] +async fn unit_value_roundtrip_display_keeps_expected_format() { + let cases = [ + ("", UnitValue::None, ""), + ("auto", UnitValue::Auto, "auto"), + ("0", UnitValue::Zero, "0"), + ("12px", UnitValue::Px(12), "12px"), + ("-5pt", UnitValue::Pt(-5), "-5pt"), + ("7cm", UnitValue::Cm(7), "7cm"), + ("33%", UnitValue::RelPct(33.0), "33%"), + ("1.25rem", UnitValue::RelRem(1.25), "1.25rem"), + ("2em", UnitValue::RelEm(2.0), "2em"), + ("-0.5vh", UnitValue::RelVh(-0.5), "-0.5vh"), + ("8vw", UnitValue::RelVw(8.0), "8vw"), + ]; + + for (input, expected_value, expected_display) in cases { + let parsed = UnitValue::from_str(input).unwrap(); + assert_eq!( + parsed, expected_value, + "parsed mismatch for input `{input}`" + ); + assert_eq!( + parsed.to_string(), + expected_display, + "display mismatch for input `{input}`" + ); + } +} + +#[pagetop::test] +async fn unit_value_percentage_trimming_and_signs() { + assert_eq!( + UnitValue::from_str(" 12.5 % ").unwrap(), + UnitValue::RelPct(12.5) + ); + assert_eq!( + UnitValue::from_str("-0.0%").unwrap(), + UnitValue::RelPct(-0.0) + ); + assert_eq!( + UnitValue::from_str("+15%").unwrap(), + UnitValue::RelPct(15.0) + ); +} + +// ERRORES ESPERADOS (no cambiar los mensajes; con is_err() basta). + +#[pagetop::test] +async fn unit_value_errors_missing_unit_for_non_zero() { + assert!( + UnitValue::from_str("12").is_err(), + "non-zero without unit must error" + ); + assert!( + UnitValue::from_str(" -3 ").is_err(), + "non-zero without unit must error" + ); +} + +#[pagetop::test] +async fn unit_value_errors_decimals_in_absolute_units() { + assert!(UnitValue::from_str("1.5px").is_err()); + assert!(UnitValue::from_str("-2.0pt").is_err()); + assert!(UnitValue::from_str("+0.1cm").is_err()); +} + +#[pagetop::test] +async fn unit_value_errors_unknown_units_or_bad_percentages() { + // Unidad no soportada. + assert!(UnitValue::from_str("10ch").is_err()); + assert!(UnitValue::from_str("2q").is_err()); + // Falta número. + assert!(UnitValue::from_str("%").is_err()); + assert!(UnitValue::from_str(" % ").is_err()); +} + +#[pagetop::test] +async fn unit_value_errors_non_numeric_numbers() { + assert!(UnitValue::from_str("NaNem").is_err()); + // Decimal no permitido por FromStr. + assert!(UnitValue::from_str("1,5rem").is_err()); +} + +#[pagetop::test] +async fn unit_value_serde_deserialize_struct_and_array() { + use serde::Deserialize; + + #[derive(Deserialize, Debug, PartialEq)] + struct BoxStyle { + width: UnitValue, + height: UnitValue, + margin: UnitValue, + } + + let json = r#"{ "width": "12px", "height": "1.5rem", "margin": "0" }"#; + let s: BoxStyle = serde_json::from_str(json).unwrap(); + assert_eq!(s.width, UnitValue::Px(12)); + assert_eq!(s.height, UnitValue::RelRem(1.5)); + assert_eq!(s.margin, UnitValue::Zero); + + #[derive(Deserialize, Debug, PartialEq)] + struct Many { + values: Vec<UnitValue>, + } + + let json_arr = r#"{ "values": ["", "auto", "33%", "8vw", "7 cm", "-5pt"] }"#; + let m: Many = serde_json::from_str(json_arr).unwrap(); + assert_eq!( + m.values, + vec![ + UnitValue::None, + UnitValue::Auto, + UnitValue::RelPct(33.0), + UnitValue::RelVw(8.0), + UnitValue::Cm(7), + UnitValue::Pt(-5), + ] + ); +} + +#[pagetop::test] +async fn unit_value_accepts_dot5_and_1dot_shorthand_for_relatives() { + // `.5` y `1.` se parsean correctamente en relativas. + assert_eq!(UnitValue::from_str(".5em").unwrap(), UnitValue::RelEm(0.5)); + assert_eq!( + UnitValue::from_str("1.rem").unwrap(), + UnitValue::RelRem(1.0) + ); + assert_eq!(UnitValue::from_str("1.vh").unwrap(), UnitValue::RelVh(1.0)); + // Sin unidad debe seguir fallando. + assert!(UnitValue::from_str("1.").is_err()); +} + +#[pagetop::test] +async fn unit_value_display_keeps_minus_zero_for_relatives() { + // Comportamiento actual: f32 Display muestra "-0" si el valor es -0.0. + let v = UnitValue::RelEm(-0.0); + // Se acepta cualquiera de los dos formatos como válidos. + let s = v.to_string(); + assert!( + s == "-0em" || s == "0em", + "current Display prints `{s}` for -0.0; both are acceptable in tests" + ); +} + +#[pagetop::test] +async fn unit_value_rejects_non_decimal_notations() { + // Octal, los ceros a la izquierda (p. ej. `"020px"`) se interpretan en **base 10** (`20px`). + assert_eq!(UnitValue::from_str("020px").unwrap(), UnitValue::Px(20)); + // Notación científica y bases no decimales (p. ej., `"1e3vw"`, `"0x10px"`) no están soportadas. + assert!(UnitValue::from_str("1e3vw").is_err()); + assert!(UnitValue::from_str("0x10px").is_err()); +} diff --git a/tools/changelog.sh b/tools/changelog.sh index 722cdb7..bd5f20b 100755 --- a/tools/changelog.sh +++ b/tools/changelog.sh @@ -50,11 +50,23 @@ case "$CRATE" in pagetop) CHANGELOG_FILE="CHANGELOG.md" PATH_FLAGS=( + # Helpers --exclude-path "helpers/pagetop-statics/**/*" --exclude-path "helpers/pagetop-build/**/*" --exclude-path "helpers/pagetop-macros/**/*" + # Extensions + --exclude-path "extensions/pagetop-aliner/**/*" + --exclude-path "extensions/pagetop-bootsier/**/*" ) ;; + pagetop-aliner) + CHANGELOG_FILE="extensions/pagetop-aliner/CHANGELOG.md" + PATH_FLAGS=(--include-path "extensions/pagetop-aliner/**/*") + ;; + pagetop-bootsier) + CHANGELOG_FILE="extensions/pagetop-bootsier/CHANGELOG.md" + PATH_FLAGS=(--include-path "extensions/pagetop-bootsier/**/*") + ;; *) echo "Error: unsupported crate '$CRATE'" >&2 exit 1