diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..8ddbc0c6 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v18.16.0 diff --git a/README.md b/README.md index 586bd109..79270c4d 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,9 @@ With Rails UI, you can easily bring professional-grade design to your Ruby on Ra ## Installation +Before installing the gem, ensure both your node and [yarn](https://yarnpkg.com/) versions are up to date for best results. Using something like [nvm](https://github.com/nvm-sh/nvm) helps with node versions. I like to use [homebrew](https://brew.sh/) for yarn and periodically run `brew upgrade yarn`. + + ```ruby # Gemfile gem "railsui", github: "getrailsui/railsui" diff --git a/app/assets/builds/application.css b/app/assets/builds/application.css new file mode 100644 index 00000000..fa71c0d2 --- /dev/null +++ b/app/assets/builds/application.css @@ -0,0 +1,1355 @@ +/* +! tailwindcss v3.0.22 | MIT License | https://tailwindcss.com +*/ + +/* +1. Prevent padding and border from affecting element width. (https://github.com/mozdevs/cssremedy/issues/4) +2. Allow adding a border to an element by just adding a border-width. (https://github.com/tailwindcss/tailwindcss/pull/116) +*/ + +*, +::before, +::after { + box-sizing: border-box; + /* 1 */ + border-width: 0; + /* 2 */ + border-style: solid; + /* 2 */ + border-color: #e5e7eb; + /* 2 */ +} + +::before, +::after { + --tw-content: ''; +} + +/* +1. Use a consistent sensible line-height in all browsers. +2. Prevent adjustments of font size after orientation changes in iOS. +3. Use a more readable tab size. +4. Use the user's configured `sans` font-family by default. +*/ + +html { + line-height: 1.5; + /* 1 */ + -webkit-text-size-adjust: 100%; + /* 2 */ + -moz-tab-size: 4; + /* 3 */ + -o-tab-size: 4; + tab-size: 4; + /* 3 */ + font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; + /* 4 */ +} + +/* +1. Remove the margin in all browsers. +2. Inherit line-height from `html` so users can set them as a class directly on the `html` element. +*/ + +body { + margin: 0; + /* 1 */ + line-height: inherit; + /* 2 */ +} + +/* +1. Add the correct height in Firefox. +2. Correct the inheritance of border color in Firefox. (https://bugzilla.mozilla.org/show_bug.cgi?id=190655) +3. Ensure horizontal rules are visible by default. +*/ + +hr { + height: 0; + /* 1 */ + color: inherit; + /* 2 */ + border-top-width: 1px; + /* 3 */ +} + +/* +Add the correct text decoration in Chrome, Edge, and Safari. +*/ + +abbr:where([title]) { + -webkit-text-decoration: underline dotted; + text-decoration: underline dotted; +} + +/* +Remove the default font size and weight for headings. +*/ + +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: inherit; + font-weight: inherit; +} + +/* +Reset links to optimize for opt-in styling instead of opt-out. +*/ + +a { + color: inherit; + text-decoration: inherit; +} + +/* +Add the correct font weight in Edge and Safari. +*/ + +b, +strong { + font-weight: bolder; +} + +/* +1. Use the user's configured `mono` font family by default. +2. Correct the odd `em` font sizing in all browsers. +*/ + +code, +kbd, +samp, +pre { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; + /* 1 */ + font-size: 1em; + /* 2 */ +} + +/* +Add the correct font size in all browsers. +*/ + +small { + font-size: 80%; +} + +/* +Prevent `sub` and `sup` elements from affecting the line height in all browsers. +*/ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* +1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) +2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) +3. Remove gaps between table borders by default. +*/ + +table { + text-indent: 0; + /* 1 */ + border-color: inherit; + /* 2 */ + border-collapse: collapse; + /* 3 */ +} + +/* +1. Change the font styles in all browsers. +2. Remove the margin in Firefox and Safari. +3. Remove default padding in all browsers. +*/ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; + /* 1 */ + font-size: 100%; + /* 1 */ + line-height: inherit; + /* 1 */ + color: inherit; + /* 1 */ + margin: 0; + /* 2 */ + padding: 0; + /* 3 */ +} + +/* +Remove the inheritance of text transform in Edge and Firefox. +*/ + +button, +select { + text-transform: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Remove default button styles. +*/ + +button, +[type='button'], +[type='reset'], +[type='submit'] { + -webkit-appearance: button; + /* 1 */ + background-color: transparent; + /* 2 */ + background-image: none; + /* 2 */ +} + +/* +Use the modern Firefox focus style for all focusable elements. +*/ + +:-moz-focusring { + outline: auto; +} + +/* +Remove the additional `:invalid` styles in Firefox. (https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d494c9be1/layout/style/res/forms.css#L728-L737) +*/ + +:-moz-ui-invalid { + box-shadow: none; +} + +/* +Add the correct vertical alignment in Chrome and Firefox. +*/ + +progress { + vertical-align: baseline; +} + +/* +Correct the cursor style of increment and decrement buttons in Safari. +*/ + +::-webkit-inner-spin-button, +::-webkit-outer-spin-button { + height: auto; +} + +/* +1. Correct the odd appearance in Chrome and Safari. +2. Correct the outline style in Safari. +*/ + +[type='search'] { + -webkit-appearance: textfield; + /* 1 */ + outline-offset: -2px; + /* 2 */ +} + +/* +Remove the inner padding in Chrome and Safari on macOS. +*/ + +::-webkit-search-decoration { + -webkit-appearance: none; +} + +/* +1. Correct the inability to style clickable types in iOS and Safari. +2. Change font properties to `inherit` in Safari. +*/ + +::-webkit-file-upload-button { + -webkit-appearance: button; + /* 1 */ + font: inherit; + /* 2 */ +} + +/* +Add the correct display in Chrome and Safari. +*/ + +summary { + display: list-item; +} + +/* +Removes the default spacing and border for appropriate elements. +*/ + +blockquote, +dl, +dd, +h1, +h2, +h3, +h4, +h5, +h6, +hr, +figure, +p, +pre { + margin: 0; +} + +fieldset { + margin: 0; + padding: 0; +} + +legend { + padding: 0; +} + +ol, +ul, +menu { + list-style: none; + margin: 0; + padding: 0; +} + +/* +Prevent resizing textareas horizontally by default. +*/ + +textarea { + resize: vertical; +} + +/* +1. Reset the default placeholder opacity in Firefox. (https://github.com/tailwindlabs/tailwindcss/issues/3300) +2. Set the default placeholder color to the user's configured gray 400 color. +*/ + +input::-moz-placeholder, textarea::-moz-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input:-ms-input-placeholder, textarea:-ms-input-placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +input::placeholder, +textarea::placeholder { + opacity: 1; + /* 1 */ + color: #9ca3af; + /* 2 */ +} + +/* +Set the default cursor for buttons. +*/ + +button, +[role="button"] { + cursor: pointer; +} + +/* +Make sure disabled buttons don't get the pointer cursor. +*/ + +:disabled { + cursor: default; +} + +/* +1. Make replaced elements `display: block` by default. (https://github.com/mozdevs/cssremedy/issues/14) +2. Add `vertical-align: middle` to align replaced elements more sensibly by default. (https://github.com/jensimmons/cssremedy/issues/14#issuecomment-634934210) + This can trigger a poorly considered lint error in some tools but is included by design. +*/ + +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; + /* 1 */ + vertical-align: middle; + /* 2 */ +} + +/* +Constrain images and videos to the parent width and preserve their intrinsic aspect ratio. (https://github.com/mozdevs/cssremedy/issues/14) +*/ + +img, +video { + max-width: 100%; + height: auto; +} + +/* +Ensure the default browser behavior of the `hidden` attribute. +*/ + +[hidden] { + display: none; +} + +.form-input,.form-textarea,.form-select,.form-multiselect { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #6b7280; + border-width: 1px; + border-radius: 0px; + padding-top: 0.5rem; + padding-right: 0.75rem; + padding-bottom: 0.5rem; + padding-left: 0.75rem; + font-size: 1rem; + line-height: 1.5rem; + --tw-shadow: 0 0 #0000; +} + +.form-input:focus, .form-textarea:focus, .form-select:focus, .form-multiselect:focus { + outline: 2px solid transparent; + outline-offset: 2px; + --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #2563eb; + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); + border-color: #2563eb; +} + +.form-input::-moz-placeholder, .form-textarea::-moz-placeholder { + color: #6b7280; + opacity: 1; +} + +.form-input:-ms-input-placeholder, .form-textarea:-ms-input-placeholder { + color: #6b7280; + opacity: 1; +} + +.form-input::placeholder,.form-textarea::placeholder { + color: #6b7280; + opacity: 1; +} + +.form-input::-webkit-datetime-edit-fields-wrapper { + padding: 0; +} + +.form-input::-webkit-date-and-time-value { + min-height: 1.5em; +} + +.form-select { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e"); + background-position: right 0.5rem center; + background-repeat: no-repeat; + background-size: 1.5em 1.5em; + padding-right: 2.5rem; + -webkit-print-color-adjust: exact; + color-adjust: exact; +} + +.form-checkbox,.form-radio { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + padding: 0; + -webkit-print-color-adjust: exact; + color-adjust: exact; + display: inline-block; + vertical-align: middle; + background-origin: border-box; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + flex-shrink: 0; + height: 1rem; + width: 1rem; + color: #2563eb; + background-color: #fff; + border-color: #6b7280; + border-width: 1px; + --tw-shadow: 0 0 #0000; +} + +.form-checkbox { + border-radius: 0px; +} + +.form-checkbox:focus,.form-radio:focus { + outline: 2px solid transparent; + outline-offset: 2px; + --tw-ring-inset: var(--tw-empty,/*!*/ /*!*/); + --tw-ring-offset-width: 2px; + --tw-ring-offset-color: #fff; + --tw-ring-color: #2563eb; + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow); +} + +.form-checkbox:checked,.form-radio:checked { + border-color: transparent; + background-color: currentColor; + background-size: 100% 100%; + background-position: center; + background-repeat: no-repeat; +} + +.form-checkbox:checked { + background-image: url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e"); +} + +.form-checkbox:checked:hover,.form-checkbox:checked:focus,.form-radio:checked:hover,.form-radio:checked:focus { + border-color: transparent; + background-color: currentColor; +} + +.form-checkbox:indeterminate { + background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e"); + border-color: transparent; + background-color: currentColor; + background-size: 100% 100%; + background-position: center; + background-repeat: no-repeat; +} + +.form-checkbox:indeterminate:hover,.form-checkbox:indeterminate:focus { + border-color: transparent; + background-color: currentColor; +} + +*, ::before, ::after { + --tw-translate-x: 0; + --tw-translate-y: 0; + --tw-rotate: 0; + --tw-skew-x: 0; + --tw-skew-y: 0; + --tw-scale-x: 1; + --tw-scale-y: 1; + --tw-pan-x: ; + --tw-pan-y: ; + --tw-pinch-zoom: ; + --tw-scroll-snap-strictness: proximity; + --tw-ordinal: ; + --tw-slashed-zero: ; + --tw-numeric-figure: ; + --tw-numeric-spacing: ; + --tw-numeric-fraction: ; + --tw-ring-inset: ; + --tw-ring-offset-width: 0px; + --tw-ring-offset-color: #fff; + --tw-ring-color: rgb(59 130 246 / 0.5); + --tw-ring-offset-shadow: 0 0 #0000; + --tw-ring-shadow: 0 0 #0000; + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + --tw-blur: ; + --tw-brightness: ; + --tw-contrast: ; + --tw-grayscale: ; + --tw-hue-rotate: ; + --tw-invert: ; + --tw-saturate: ; + --tw-sepia: ; + --tw-drop-shadow: ; + --tw-backdrop-blur: ; + --tw-backdrop-brightness: ; + --tw-backdrop-contrast: ; + --tw-backdrop-grayscale: ; + --tw-backdrop-hue-rotate: ; + --tw-backdrop-invert: ; + --tw-backdrop-opacity: ; + --tw-backdrop-saturate: ; + --tw-backdrop-sepia: ; +} + +.sr-only { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border-width: 0; +} + +.pointer-events-none { + pointer-events: none; +} + +.absolute { + position: absolute; +} + +.relative { + position: relative; +} + +.bottom-px { + bottom: 1px; +} + +.left-px { + left: 1px; +} + +.col-span-1 { + grid-column: span 1 / span 1; +} + +.col-span-3 { + grid-column: span 3 / span 3; +} + +.col-span-9 { + grid-column: span 9 / span 9; +} + +.mx-auto { + margin-left: auto; + margin-right: auto; +} + +.mb-3 { + margin-bottom: 0.75rem; +} + +.mb-6 { + margin-bottom: 1.5rem; +} + +.mb-1 { + margin-bottom: 0.25rem; +} + +.mb-10 { + margin-bottom: 2.5rem; +} + +.mb-2 { + margin-bottom: 0.5rem; +} + +.mr-2 { + margin-right: 0.5rem; +} + +.mt-2 { + margin-top: 0.5rem; +} + +.mb-8 { + margin-bottom: 2rem; +} + +.mb-16 { + margin-bottom: 4rem; +} + +.mb-24 { + margin-bottom: 6rem; +} + +.mt-3 { + margin-top: 0.75rem; +} + +.mt-6 { + margin-top: 1.5rem; +} + +.block { + display: block; +} + +.inline { + display: inline; +} + +.flex { + display: flex; +} + +.grid { + display: grid; +} + +.h-full { + height: 100%; +} + +.h-\[120px\] { + height: 120px; +} + +.h-\[36px\] { + height: 36px; +} + +.h-4 { + height: 1rem; +} + +.h-\[140px\] { + height: 140px; +} + +.h-\[160px\] { + height: 160px; +} + +.h-\[170px\] { + height: 170px; +} + +.h-8 { + height: 2rem; +} + +.h-6 { + height: 1.5rem; +} + +.h-5 { + height: 1.25rem; +} + +.w-full { + width: 100%; +} + +.w-\[120px\] { + width: 120px; +} + +.w-8 { + width: 2rem; +} + +.w-4 { + width: 1rem; +} + +.w-\[140px\] { + width: 140px; +} + +.w-\[160px\] { + width: 160px; +} + +.w-\[170px\] { + width: 170px; +} + +.w-6 { + width: 1.5rem; +} + +.w-5 { + width: 1.25rem; +} + +.max-w-4xl { + max-width: 56rem; +} + +.max-w-2xl { + max-width: 42rem; +} + +.max-w-3xl { + max-width: 48rem; +} + +.max-w-xl { + max-width: 36rem; +} + +.flex-1 { + flex: 1 1 0%; +} + +.transform { + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.grid-cols-3 { + grid-template-columns: repeat(3, minmax(0, 1fr)); +} + +.flex-col { + flex-direction: column; +} + +.flex-wrap { + flex-wrap: wrap; +} + +.items-center { + align-items: center; +} + +.justify-center { + justify-content: center; +} + +.gap-6 { + gap: 1.5rem; +} + +.overflow-x-hidden { + overflow-x: hidden; +} + +.rounded-lg { + border-radius: 0.5rem; +} + +.rounded { + border-radius: 0.25rem; +} + +.rounded-full { + border-radius: 9999px; +} + +.rounded-xl { + border-radius: 0.75rem; +} + +.rounded-l { + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; +} + +.rounded-l-sm { + border-top-left-radius: 0.125rem; + border-bottom-left-radius: 0.125rem; +} + +.border-b { + border-bottom-width: 1px; +} + +.border-r { + border-right-width: 1px; +} + +.border-neutral-100 { + --tw-border-opacity: 1; + border-color: rgb(245 245 245 / var(--tw-border-opacity)); +} + +.border-gray-300 { + --tw-border-opacity: 1; + border-color: rgb(209 213 219 / var(--tw-border-opacity)); +} + +.border-neutral-200 { + --tw-border-opacity: 1; + border-color: rgb(229 229 229 / var(--tw-border-opacity)); +} + +.border-neutral-500 { + --tw-border-opacity: 1; + border-color: rgb(115 115 115 / var(--tw-border-opacity)); +} + +.bg-gray-50 { + --tw-bg-opacity: 1; + background-color: rgb(249 250 251 / var(--tw-bg-opacity)); +} + +.bg-white { + --tw-bg-opacity: 1; + background-color: rgb(255 255 255 / var(--tw-bg-opacity)); +} + +.bg-neutral-800 { + --tw-bg-opacity: 1; + background-color: rgb(38 38 38 / var(--tw-bg-opacity)); +} + +.fill-current { + fill: currentColor; +} + +.stroke-current { + stroke: currentColor; +} + +.p-6 { + padding: 1.5rem; +} + +.p-8 { + padding: 2rem; +} + +.py-2 { + padding-top: 0.5rem; + padding-bottom: 0.5rem; +} + +.px-6 { + padding-left: 1.5rem; + padding-right: 1.5rem; +} + +.px-4 { + padding-left: 1rem; + padding-right: 1rem; +} + +.py-3 { + padding-top: 0.75rem; + padding-bottom: 0.75rem; +} + +.px-20 { + padding-left: 5rem; + padding-right: 5rem; +} + +.py-1 { + padding-top: 0.25rem; + padding-bottom: 0.25rem; +} + +.text-center { + text-align: center; +} + +.font-sans { + font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"; +} + +.font-mono { + font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +.text-xl { + font-size: 1.25rem; + line-height: 1.75rem; +} + +.text-\[15px\] { + font-size: 15px; +} + +.text-2xl { + font-size: 1.5rem; + line-height: 2rem; +} + +.text-sm { + font-size: 0.875rem; + line-height: 1.25rem; +} + +.text-lg { + font-size: 1.125rem; + line-height: 1.75rem; +} + +.font-normal { + font-weight: 400; +} + +.font-black { + font-weight: 900; +} + +.font-medium { + font-weight: 500; +} + +.font-bold { + font-weight: 700; +} + +.capitalize { + text-transform: capitalize; +} + +.leading-normal { + line-height: 1.5; +} + +.leading-loose { + line-height: 2; +} + +.tracking-tight { + letter-spacing: -0.025em; +} + +.text-neutral-500 { + --tw-text-opacity: 1; + color: rgb(115 115 115 / var(--tw-text-opacity)); +} + +.text-neutral-800 { + --tw-text-opacity: 1; + color: rgb(38 38 38 / var(--tw-text-opacity)); +} + +.text-gray-500 { + --tw-text-opacity: 1; + color: rgb(107 114 128 / var(--tw-text-opacity)); +} + +.text-indigo-600 { + --tw-text-opacity: 1; + color: rgb(79 70 229 / var(--tw-text-opacity)); +} + +.text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); +} + +.text-red-400 { + --tw-text-opacity: 1; + color: rgb(248 113 113 / var(--tw-text-opacity)); +} + +.antialiased { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.opacity-50 { + opacity: 0.5; +} + +.ring-2 { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.ring-transparent { + --tw-ring-color: transparent; +} + +.transition { + transition-property: color, background-color, border-color, fill, stroke, opacity, box-shadow, transform, filter, -webkit-text-decoration-color, -webkit-backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter; + transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform, filter, backdrop-filter, -webkit-text-decoration-color, -webkit-backdrop-filter; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 150ms; +} + +.duration-300 { + transition-duration: 300ms; +} + +.ease-in-out { + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); +} + +.hover\:-rotate-2:hover { + --tw-rotate: -2deg; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.hover\:scale-105:hover { + --tw-scale-x: 1.05; + --tw-scale-y: 1.05; + transform: translate(var(--tw-translate-x), var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y)); +} + +.hover\:bg-indigo-50:hover { + --tw-bg-opacity: 1; + background-color: rgb(238 242 255 / var(--tw-bg-opacity)); +} + +.hover\:bg-black:hover { + --tw-bg-opacity: 1; + background-color: rgb(0 0 0 / var(--tw-bg-opacity)); +} + +.hover\:bg-opacity-50:hover { + --tw-bg-opacity: 0.5; +} + +.focus\:border-indigo-300:focus { + --tw-border-opacity: 1; + border-color: rgb(165 180 252 / var(--tw-border-opacity)); +} + +.focus\:shadow-none:focus { + --tw-shadow: 0 0 #0000; + --tw-shadow-colored: 0 0 #0000; + box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); +} + +.focus\:outline-none:focus { + outline: 2px solid transparent; + outline-offset: 2px; +} + +.focus\:ring-4:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(4px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-2:focus { + --tw-ring-offset-shadow: var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color); + --tw-ring-shadow: var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color); + box-shadow: var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow, 0 0 #0000); +} + +.focus\:ring-indigo-50:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(238 242 255 / var(--tw-ring-opacity)); +} + +.focus\:ring-neutral-100:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(245 245 245 / var(--tw-ring-opacity)); +} + +@-webkit-keyframes pulse { + 50% { + opacity: .5; + } +} + +@keyframes pulse { + 50% { + opacity: .5; + } +} + +.group:hover .group-hover\:animate-pulse { + -webkit-animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; + animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; +} + +.group:hover .group-hover\:text-orange-600 { + --tw-text-opacity: 1; + color: rgb(234 88 12 / var(--tw-text-opacity)); +} + +@media (prefers-color-scheme: dark) { + .dark\:border-gray-100 { + --tw-border-opacity: 1; + border-color: rgb(243 244 246 / var(--tw-border-opacity)); + } + + .dark\:border-gray-800 { + --tw-border-opacity: 1; + border-color: rgb(31 41 55 / var(--tw-border-opacity)); + } + + .dark\:border-neutral-800 { + --tw-border-opacity: 1; + border-color: rgb(38 38 38 / var(--tw-border-opacity)); + } + + .dark\:border-neutral-700 { + --tw-border-opacity: 1; + border-color: rgb(64 64 64 / var(--tw-border-opacity)); + } + + .dark\:border-neutral-400 { + --tw-border-opacity: 1; + border-color: rgb(163 163 163 / var(--tw-border-opacity)); + } + + .dark\:border-neutral-500 { + --tw-border-opacity: 1; + border-color: rgb(115 115 115 / var(--tw-border-opacity)); + } + + .dark\:bg-neutral-900 { + --tw-bg-opacity: 1; + background-color: rgb(23 23 23 / var(--tw-bg-opacity)); + } + + .dark\:bg-neutral-600 { + --tw-bg-opacity: 1; + background-color: rgb(82 82 82 / var(--tw-bg-opacity)); + } + + .dark\:bg-neutral-800 { + --tw-bg-opacity: 1; + background-color: rgb(38 38 38 / var(--tw-bg-opacity)); + } + + .dark\:bg-neutral-700 { + --tw-bg-opacity: 1; + background-color: rgb(64 64 64 / var(--tw-bg-opacity)); + } + + .dark\:text-white { + --tw-text-opacity: 1; + color: rgb(255 255 255 / var(--tw-text-opacity)); + } + + .dark\:text-neutral-900 { + --tw-text-opacity: 1; + color: rgb(23 23 23 / var(--tw-text-opacity)); + } + + .dark\:text-neutral-200 { + --tw-text-opacity: 1; + color: rgb(229 229 229 / var(--tw-text-opacity)); + } + + .dark\:text-neutral-100 { + --tw-text-opacity: 1; + color: rgb(245 245 245 / var(--tw-text-opacity)); + } + + .dark\:text-gray-300 { + --tw-text-opacity: 1; + color: rgb(209 213 219 / var(--tw-text-opacity)); + } + + .dark\:text-neutral-500 { + --tw-text-opacity: 1; + color: rgb(115 115 115 / var(--tw-text-opacity)); + } + + .dark\:text-neutral-400 { + --tw-text-opacity: 1; + color: rgb(163 163 163 / var(--tw-text-opacity)); + } + + .dark\:text-yellow-500 { + --tw-text-opacity: 1; + color: rgb(234 179 8 / var(--tw-text-opacity)); + } + + .dark\:hover\:bg-neutral-700:hover { + --tw-bg-opacity: 1; + background-color: rgb(64 64 64 / var(--tw-bg-opacity)); + } + + .dark\:hover\:bg-neutral-800:hover { + --tw-bg-opacity: 1; + background-color: rgb(38 38 38 / var(--tw-bg-opacity)); + } + + .dark\:focus\:border-neutral-300:focus { + --tw-border-opacity: 1; + border-color: rgb(212 212 212 / var(--tw-border-opacity)); + } + + .dark\:focus\:ring-neutral-50:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(250 250 250 / var(--tw-ring-opacity)); + } + + .focus\:dark\:ring-neutral-50:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(250 250 250 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-gray-50:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(249 250 251 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-neutral-800:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(38 38 38 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-neutral-700:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(64 64 64 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-neutral-600:focus { + --tw-ring-opacity: 1; + --tw-ring-color: rgb(82 82 82 / var(--tw-ring-opacity)); + } + + .dark\:focus\:ring-opacity-50:focus { + --tw-ring-opacity: 0.5; + } + + .dark\:focus\:ring-opacity-25:focus { + --tw-ring-opacity: 0.25; + } + + .dark\:focus\:ring-opacity-20:focus { + --tw-ring-opacity: 0.2; + } +} + +@media (min-width: 1024px) { + .lg\:h-full { + height: 100%; + } + + .lg\:w-1\/2 { + width: 50%; + } + + .lg\:grid-cols-12 { + grid-template-columns: repeat(12, minmax(0, 1fr)); + } + + .lg\:px-20 { + padding-left: 5rem; + padding-right: 5rem; + } + + .lg\:py-20 { + padding-top: 5rem; + padding-bottom: 5rem; + } + + .lg\:py-16 { + padding-top: 4rem; + padding-bottom: 4rem; + } +} diff --git a/app/assets/builds/application.js b/app/assets/builds/application.js new file mode 100644 index 00000000..9311c3ae --- /dev/null +++ b/app/assets/builds/application.js @@ -0,0 +1,5678 @@ +(() => { + var __defProp = Object.defineProperty; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __esm = (fn, res) => function __init() { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; + }; + var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); + }; + + // node_modules/@rails/actioncable/src/adapters.js + var adapters_default; + var init_adapters = __esm({ + "node_modules/@rails/actioncable/src/adapters.js"() { + adapters_default = { + logger: self.console, + WebSocket: self.WebSocket + }; + } + }); + + // node_modules/@rails/actioncable/src/logger.js + var logger_default; + var init_logger = __esm({ + "node_modules/@rails/actioncable/src/logger.js"() { + init_adapters(); + logger_default = { + log(...messages) { + if (this.enabled) { + messages.push(Date.now()); + adapters_default.logger.log("[ActionCable]", ...messages); + } + } + }; + } + }); + + // node_modules/@rails/actioncable/src/connection_monitor.js + var now, secondsSince, ConnectionMonitor, connection_monitor_default; + var init_connection_monitor = __esm({ + "node_modules/@rails/actioncable/src/connection_monitor.js"() { + init_logger(); + now = () => new Date().getTime(); + secondsSince = (time) => (now() - time) / 1e3; + ConnectionMonitor = class { + constructor(connection) { + this.visibilityDidChange = this.visibilityDidChange.bind(this); + this.connection = connection; + this.reconnectAttempts = 0; + } + start() { + if (!this.isRunning()) { + this.startedAt = now(); + delete this.stoppedAt; + this.startPolling(); + addEventListener("visibilitychange", this.visibilityDidChange); + logger_default.log(`ConnectionMonitor started. stale threshold = ${this.constructor.staleThreshold} s`); + } + } + stop() { + if (this.isRunning()) { + this.stoppedAt = now(); + this.stopPolling(); + removeEventListener("visibilitychange", this.visibilityDidChange); + logger_default.log("ConnectionMonitor stopped"); + } + } + isRunning() { + return this.startedAt && !this.stoppedAt; + } + recordPing() { + this.pingedAt = now(); + } + recordConnect() { + this.reconnectAttempts = 0; + this.recordPing(); + delete this.disconnectedAt; + logger_default.log("ConnectionMonitor recorded connect"); + } + recordDisconnect() { + this.disconnectedAt = now(); + logger_default.log("ConnectionMonitor recorded disconnect"); + } + startPolling() { + this.stopPolling(); + this.poll(); + } + stopPolling() { + clearTimeout(this.pollTimeout); + } + poll() { + this.pollTimeout = setTimeout(() => { + this.reconnectIfStale(); + this.poll(); + }, this.getPollInterval()); + } + getPollInterval() { + const { staleThreshold, reconnectionBackoffRate } = this.constructor; + const backoff = Math.pow(1 + reconnectionBackoffRate, Math.min(this.reconnectAttempts, 10)); + const jitterMax = this.reconnectAttempts === 0 ? 1 : reconnectionBackoffRate; + const jitter = jitterMax * Math.random(); + return staleThreshold * 1e3 * backoff * (1 + jitter); + } + reconnectIfStale() { + if (this.connectionIsStale()) { + logger_default.log(`ConnectionMonitor detected stale connection. reconnectAttempts = ${this.reconnectAttempts}, time stale = ${secondsSince(this.refreshedAt)} s, stale threshold = ${this.constructor.staleThreshold} s`); + this.reconnectAttempts++; + if (this.disconnectedRecently()) { + logger_default.log(`ConnectionMonitor skipping reopening recent disconnect. time disconnected = ${secondsSince(this.disconnectedAt)} s`); + } else { + logger_default.log("ConnectionMonitor reopening"); + this.connection.reopen(); + } + } + } + get refreshedAt() { + return this.pingedAt ? this.pingedAt : this.startedAt; + } + connectionIsStale() { + return secondsSince(this.refreshedAt) > this.constructor.staleThreshold; + } + disconnectedRecently() { + return this.disconnectedAt && secondsSince(this.disconnectedAt) < this.constructor.staleThreshold; + } + visibilityDidChange() { + if (document.visibilityState === "visible") { + setTimeout(() => { + if (this.connectionIsStale() || !this.connection.isOpen()) { + logger_default.log(`ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = ${document.visibilityState}`); + this.connection.reopen(); + } + }, 200); + } + } + }; + ConnectionMonitor.staleThreshold = 6; + ConnectionMonitor.reconnectionBackoffRate = 0.15; + connection_monitor_default = ConnectionMonitor; + } + }); + + // node_modules/@rails/actioncable/src/internal.js + var internal_default; + var init_internal = __esm({ + "node_modules/@rails/actioncable/src/internal.js"() { + internal_default = { + "message_types": { + "welcome": "welcome", + "disconnect": "disconnect", + "ping": "ping", + "confirmation": "confirm_subscription", + "rejection": "reject_subscription" + }, + "disconnect_reasons": { + "unauthorized": "unauthorized", + "invalid_request": "invalid_request", + "server_restart": "server_restart" + }, + "default_mount_path": "/cable", + "protocols": [ + "actioncable-v1-json", + "actioncable-unsupported" + ] + }; + } + }); + + // node_modules/@rails/actioncable/src/connection.js + var message_types, protocols, supportedProtocols, indexOf, Connection, connection_default; + var init_connection = __esm({ + "node_modules/@rails/actioncable/src/connection.js"() { + init_adapters(); + init_connection_monitor(); + init_internal(); + init_logger(); + ({ message_types, protocols } = internal_default); + supportedProtocols = protocols.slice(0, protocols.length - 1); + indexOf = [].indexOf; + Connection = class { + constructor(consumer2) { + this.open = this.open.bind(this); + this.consumer = consumer2; + this.subscriptions = this.consumer.subscriptions; + this.monitor = new connection_monitor_default(this); + this.disconnected = true; + } + send(data) { + if (this.isOpen()) { + this.webSocket.send(JSON.stringify(data)); + return true; + } else { + return false; + } + } + open() { + if (this.isActive()) { + logger_default.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`); + return false; + } else { + logger_default.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${protocols}`); + if (this.webSocket) { + this.uninstallEventHandlers(); + } + this.webSocket = new adapters_default.WebSocket(this.consumer.url, protocols); + this.installEventHandlers(); + this.monitor.start(); + return true; + } + } + close({ allowReconnect } = { allowReconnect: true }) { + if (!allowReconnect) { + this.monitor.stop(); + } + if (this.isActive()) { + return this.webSocket.close(); + } + } + reopen() { + logger_default.log(`Reopening WebSocket, current state is ${this.getState()}`); + if (this.isActive()) { + try { + return this.close(); + } catch (error2) { + logger_default.log("Failed to reopen WebSocket", error2); + } finally { + logger_default.log(`Reopening WebSocket in ${this.constructor.reopenDelay}ms`); + setTimeout(this.open, this.constructor.reopenDelay); + } + } else { + return this.open(); + } + } + getProtocol() { + if (this.webSocket) { + return this.webSocket.protocol; + } + } + isOpen() { + return this.isState("open"); + } + isActive() { + return this.isState("open", "connecting"); + } + isProtocolSupported() { + return indexOf.call(supportedProtocols, this.getProtocol()) >= 0; + } + isState(...states) { + return indexOf.call(states, this.getState()) >= 0; + } + getState() { + if (this.webSocket) { + for (let state in adapters_default.WebSocket) { + if (adapters_default.WebSocket[state] === this.webSocket.readyState) { + return state.toLowerCase(); + } + } + } + return null; + } + installEventHandlers() { + for (let eventName in this.events) { + const handler = this.events[eventName].bind(this); + this.webSocket[`on${eventName}`] = handler; + } + } + uninstallEventHandlers() { + for (let eventName in this.events) { + this.webSocket[`on${eventName}`] = function() { + }; + } + } + }; + Connection.reopenDelay = 500; + Connection.prototype.events = { + message(event) { + if (!this.isProtocolSupported()) { + return; + } + const { identifier, message, reason, reconnect, type } = JSON.parse(event.data); + switch (type) { + case message_types.welcome: + this.monitor.recordConnect(); + return this.subscriptions.reload(); + case message_types.disconnect: + logger_default.log(`Disconnecting. Reason: ${reason}`); + return this.close({ allowReconnect: reconnect }); + case message_types.ping: + return this.monitor.recordPing(); + case message_types.confirmation: + this.subscriptions.confirmSubscription(identifier); + return this.subscriptions.notify(identifier, "connected"); + case message_types.rejection: + return this.subscriptions.reject(identifier); + default: + return this.subscriptions.notify(identifier, "received", message); + } + }, + open() { + logger_default.log(`WebSocket onopen event, using '${this.getProtocol()}' subprotocol`); + this.disconnected = false; + if (!this.isProtocolSupported()) { + logger_default.log("Protocol is unsupported. Stopping monitor and disconnecting."); + return this.close({ allowReconnect: false }); + } + }, + close(event) { + logger_default.log("WebSocket onclose event"); + if (this.disconnected) { + return; + } + this.disconnected = true; + this.monitor.recordDisconnect(); + return this.subscriptions.notifyAll("disconnected", { willAttemptReconnect: this.monitor.isRunning() }); + }, + error() { + logger_default.log("WebSocket onerror event"); + } + }; + connection_default = Connection; + } + }); + + // node_modules/@rails/actioncable/src/subscription.js + var extend, Subscription; + var init_subscription = __esm({ + "node_modules/@rails/actioncable/src/subscription.js"() { + extend = function(object, properties) { + if (properties != null) { + for (let key in properties) { + const value = properties[key]; + object[key] = value; + } + } + return object; + }; + Subscription = class { + constructor(consumer2, params = {}, mixin) { + this.consumer = consumer2; + this.identifier = JSON.stringify(params); + extend(this, mixin); + } + perform(action, data = {}) { + data.action = action; + return this.send(data); + } + send(data) { + return this.consumer.send({ command: "message", identifier: this.identifier, data: JSON.stringify(data) }); + } + unsubscribe() { + return this.consumer.subscriptions.remove(this); + } + }; + } + }); + + // node_modules/@rails/actioncable/src/subscription_guarantor.js + var SubscriptionGuarantor, subscription_guarantor_default; + var init_subscription_guarantor = __esm({ + "node_modules/@rails/actioncable/src/subscription_guarantor.js"() { + init_logger(); + SubscriptionGuarantor = class { + constructor(subscriptions) { + this.subscriptions = subscriptions; + this.pendingSubscriptions = []; + } + guarantee(subscription) { + if (this.pendingSubscriptions.indexOf(subscription) == -1) { + logger_default.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`); + this.pendingSubscriptions.push(subscription); + } else { + logger_default.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`); + } + this.startGuaranteeing(); + } + forget(subscription) { + logger_default.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`); + this.pendingSubscriptions = this.pendingSubscriptions.filter((s) => s !== subscription); + } + startGuaranteeing() { + this.stopGuaranteeing(); + this.retrySubscribing(); + } + stopGuaranteeing() { + clearTimeout(this.retryTimeout); + } + retrySubscribing() { + this.retryTimeout = setTimeout(() => { + if (this.subscriptions && typeof this.subscriptions.subscribe === "function") { + this.pendingSubscriptions.map((subscription) => { + logger_default.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`); + this.subscriptions.subscribe(subscription); + }); + } + }, 500); + } + }; + subscription_guarantor_default = SubscriptionGuarantor; + } + }); + + // node_modules/@rails/actioncable/src/subscriptions.js + var Subscriptions; + var init_subscriptions = __esm({ + "node_modules/@rails/actioncable/src/subscriptions.js"() { + init_subscription(); + init_subscription_guarantor(); + init_logger(); + Subscriptions = class { + constructor(consumer2) { + this.consumer = consumer2; + this.guarantor = new subscription_guarantor_default(this); + this.subscriptions = []; + } + create(channelName, mixin) { + const channel = channelName; + const params = typeof channel === "object" ? channel : { channel }; + const subscription = new Subscription(this.consumer, params, mixin); + return this.add(subscription); + } + add(subscription) { + this.subscriptions.push(subscription); + this.consumer.ensureActiveConnection(); + this.notify(subscription, "initialized"); + this.subscribe(subscription); + return subscription; + } + remove(subscription) { + this.forget(subscription); + if (!this.findAll(subscription.identifier).length) { + this.sendCommand(subscription, "unsubscribe"); + } + return subscription; + } + reject(identifier) { + return this.findAll(identifier).map((subscription) => { + this.forget(subscription); + this.notify(subscription, "rejected"); + return subscription; + }); + } + forget(subscription) { + this.guarantor.forget(subscription); + this.subscriptions = this.subscriptions.filter((s) => s !== subscription); + return subscription; + } + findAll(identifier) { + return this.subscriptions.filter((s) => s.identifier === identifier); + } + reload() { + return this.subscriptions.map((subscription) => this.subscribe(subscription)); + } + notifyAll(callbackName, ...args) { + return this.subscriptions.map((subscription) => this.notify(subscription, callbackName, ...args)); + } + notify(subscription, callbackName, ...args) { + let subscriptions; + if (typeof subscription === "string") { + subscriptions = this.findAll(subscription); + } else { + subscriptions = [subscription]; + } + return subscriptions.map((subscription2) => typeof subscription2[callbackName] === "function" ? subscription2[callbackName](...args) : void 0); + } + subscribe(subscription) { + if (this.sendCommand(subscription, "subscribe")) { + this.guarantor.guarantee(subscription); + } + } + confirmSubscription(identifier) { + logger_default.log(`Subscription confirmed ${identifier}`); + this.findAll(identifier).map((subscription) => this.guarantor.forget(subscription)); + } + sendCommand(subscription, command) { + const { identifier } = subscription; + return this.consumer.send({ command, identifier }); + } + }; + } + }); + + // node_modules/@rails/actioncable/src/consumer.js + function createWebSocketURL(url) { + if (typeof url === "function") { + url = url(); + } + if (url && !/^wss?:/i.test(url)) { + const a = document.createElement("a"); + a.href = url; + a.href = a.href; + a.protocol = a.protocol.replace("http", "ws"); + return a.href; + } else { + return url; + } + } + var Consumer; + var init_consumer = __esm({ + "node_modules/@rails/actioncable/src/consumer.js"() { + init_connection(); + init_subscriptions(); + Consumer = class { + constructor(url) { + this._url = url; + this.subscriptions = new Subscriptions(this); + this.connection = new connection_default(this); + } + get url() { + return createWebSocketURL(this._url); + } + send(data) { + return this.connection.send(data); + } + connect() { + return this.connection.open(); + } + disconnect() { + return this.connection.close({ allowReconnect: false }); + } + ensureActiveConnection() { + if (!this.connection.isActive()) { + return this.connection.open(); + } + } + }; + } + }); + + // node_modules/@rails/actioncable/src/index.js + var src_exports = {}; + __export(src_exports, { + Connection: () => connection_default, + ConnectionMonitor: () => connection_monitor_default, + Consumer: () => Consumer, + INTERNAL: () => internal_default, + Subscription: () => Subscription, + SubscriptionGuarantor: () => subscription_guarantor_default, + Subscriptions: () => Subscriptions, + adapters: () => adapters_default, + createConsumer: () => createConsumer, + createWebSocketURL: () => createWebSocketURL, + getConfig: () => getConfig, + logger: () => logger_default + }); + function createConsumer(url = getConfig("url") || internal_default.default_mount_path) { + return new Consumer(url); + } + function getConfig(name) { + const element = document.head.querySelector(`meta[name='action-cable-${name}']`); + if (element) { + return element.getAttribute("content"); + } + } + var init_src = __esm({ + "node_modules/@rails/actioncable/src/index.js"() { + init_connection(); + init_connection_monitor(); + init_consumer(); + init_internal(); + init_subscription(); + init_subscriptions(); + init_subscription_guarantor(); + init_adapters(); + init_logger(); + } + }); + + // node_modules/@hotwired/turbo/dist/turbo.es2017-esm.js + (function() { + if (window.Reflect === void 0 || window.customElements === void 0 || window.customElements.polyfillWrapFlushCallback) { + return; + } + const BuiltInHTMLElement = HTMLElement; + const wrapperForTheName = { + "HTMLElement": function HTMLElement2() { + return Reflect.construct(BuiltInHTMLElement, [], this.constructor); + } + }; + window.HTMLElement = wrapperForTheName["HTMLElement"]; + HTMLElement.prototype = BuiltInHTMLElement.prototype; + HTMLElement.prototype.constructor = HTMLElement; + Object.setPrototypeOf(HTMLElement, BuiltInHTMLElement); + })(); + (function(prototype) { + if (typeof prototype.requestSubmit == "function") + return; + prototype.requestSubmit = function(submitter) { + if (submitter) { + validateSubmitter(submitter, this); + submitter.click(); + } else { + submitter = document.createElement("input"); + submitter.type = "submit"; + submitter.hidden = true; + this.appendChild(submitter); + submitter.click(); + this.removeChild(submitter); + } + }; + function validateSubmitter(submitter, form) { + submitter instanceof HTMLElement || raise(TypeError, "parameter 1 is not of type 'HTMLElement'"); + submitter.type == "submit" || raise(TypeError, "The specified element is not a submit button"); + submitter.form == form || raise(DOMException, "The specified element is not owned by this form element", "NotFoundError"); + } + function raise(errorConstructor, message, name) { + throw new errorConstructor("Failed to execute 'requestSubmit' on 'HTMLFormElement': " + message + ".", name); + } + })(HTMLFormElement.prototype); + var submittersByForm = /* @__PURE__ */ new WeakMap(); + function findSubmitterFromClickTarget(target) { + const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null; + const candidate = element ? element.closest("input, button") : null; + return (candidate === null || candidate === void 0 ? void 0 : candidate.type) == "submit" ? candidate : null; + } + function clickCaptured(event) { + const submitter = findSubmitterFromClickTarget(event.target); + if (submitter && submitter.form) { + submittersByForm.set(submitter.form, submitter); + } + } + (function() { + if ("submitter" in Event.prototype) + return; + let prototype; + if ("SubmitEvent" in window && /Apple Computer/.test(navigator.vendor)) { + prototype = window.SubmitEvent.prototype; + } else if ("SubmitEvent" in window) { + return; + } else { + prototype = window.Event.prototype; + } + addEventListener("click", clickCaptured, true); + Object.defineProperty(prototype, "submitter", { + get() { + if (this.type == "submit" && this.target instanceof HTMLFormElement) { + return submittersByForm.get(this.target); + } + } + }); + })(); + var FrameLoadingStyle; + (function(FrameLoadingStyle2) { + FrameLoadingStyle2["eager"] = "eager"; + FrameLoadingStyle2["lazy"] = "lazy"; + })(FrameLoadingStyle || (FrameLoadingStyle = {})); + var FrameElement = class extends HTMLElement { + constructor() { + super(); + this.loaded = Promise.resolve(); + this.delegate = new FrameElement.delegateConstructor(this); + } + static get observedAttributes() { + return ["disabled", "loading", "src"]; + } + connectedCallback() { + this.delegate.connect(); + } + disconnectedCallback() { + this.delegate.disconnect(); + } + reload() { + const { src } = this; + this.src = null; + this.src = src; + } + attributeChangedCallback(name) { + if (name == "loading") { + this.delegate.loadingStyleChanged(); + } else if (name == "src") { + this.delegate.sourceURLChanged(); + } else { + this.delegate.disabledChanged(); + } + } + get src() { + return this.getAttribute("src"); + } + set src(value) { + if (value) { + this.setAttribute("src", value); + } else { + this.removeAttribute("src"); + } + } + get loading() { + return frameLoadingStyleFromString(this.getAttribute("loading") || ""); + } + set loading(value) { + if (value) { + this.setAttribute("loading", value); + } else { + this.removeAttribute("loading"); + } + } + get disabled() { + return this.hasAttribute("disabled"); + } + set disabled(value) { + if (value) { + this.setAttribute("disabled", ""); + } else { + this.removeAttribute("disabled"); + } + } + get autoscroll() { + return this.hasAttribute("autoscroll"); + } + set autoscroll(value) { + if (value) { + this.setAttribute("autoscroll", ""); + } else { + this.removeAttribute("autoscroll"); + } + } + get complete() { + return !this.delegate.isLoading; + } + get isActive() { + return this.ownerDocument === document && !this.isPreview; + } + get isPreview() { + var _a, _b; + return (_b = (_a = this.ownerDocument) === null || _a === void 0 ? void 0 : _a.documentElement) === null || _b === void 0 ? void 0 : _b.hasAttribute("data-turbo-preview"); + } + }; + function frameLoadingStyleFromString(style) { + switch (style.toLowerCase()) { + case "lazy": + return FrameLoadingStyle.lazy; + default: + return FrameLoadingStyle.eager; + } + } + function expandURL(locatable) { + return new URL(locatable.toString(), document.baseURI); + } + function getAnchor(url) { + let anchorMatch; + if (url.hash) { + return url.hash.slice(1); + } else if (anchorMatch = url.href.match(/#(.*)$/)) { + return anchorMatch[1]; + } + } + function getAction(form, submitter) { + const action = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formaction")) || form.getAttribute("action") || form.action; + return expandURL(action); + } + function getExtension(url) { + return (getLastPathComponent(url).match(/\.[^.]*$/) || [])[0] || ""; + } + function isHTML(url) { + return !!getExtension(url).match(/^(?:|\.(?:htm|html|xhtml))$/); + } + function isPrefixedBy(baseURL, url) { + const prefix = getPrefix(url); + return baseURL.href === expandURL(prefix).href || baseURL.href.startsWith(prefix); + } + function locationIsVisitable(location2, rootLocation) { + return isPrefixedBy(location2, rootLocation) && isHTML(location2); + } + function getRequestURL(url) { + const anchor = getAnchor(url); + return anchor != null ? url.href.slice(0, -(anchor.length + 1)) : url.href; + } + function toCacheKey(url) { + return getRequestURL(url); + } + function urlsAreEqual(left, right) { + return expandURL(left).href == expandURL(right).href; + } + function getPathComponents(url) { + return url.pathname.split("/").slice(1); + } + function getLastPathComponent(url) { + return getPathComponents(url).slice(-1)[0]; + } + function getPrefix(url) { + return addTrailingSlash(url.origin + url.pathname); + } + function addTrailingSlash(value) { + return value.endsWith("/") ? value : value + "/"; + } + var FetchResponse = class { + constructor(response) { + this.response = response; + } + get succeeded() { + return this.response.ok; + } + get failed() { + return !this.succeeded; + } + get clientError() { + return this.statusCode >= 400 && this.statusCode <= 499; + } + get serverError() { + return this.statusCode >= 500 && this.statusCode <= 599; + } + get redirected() { + return this.response.redirected; + } + get location() { + return expandURL(this.response.url); + } + get isHTML() { + return this.contentType && this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/); + } + get statusCode() { + return this.response.status; + } + get contentType() { + return this.header("Content-Type"); + } + get responseText() { + return this.response.clone().text(); + } + get responseHTML() { + if (this.isHTML) { + return this.response.clone().text(); + } else { + return Promise.resolve(void 0); + } + } + header(name) { + return this.response.headers.get(name); + } + }; + function dispatch(eventName, { target, cancelable, detail } = {}) { + const event = new CustomEvent(eventName, { cancelable, bubbles: true, detail }); + if (target && target.isConnected) { + target.dispatchEvent(event); + } else { + document.documentElement.dispatchEvent(event); + } + return event; + } + function nextAnimationFrame() { + return new Promise((resolve) => requestAnimationFrame(() => resolve())); + } + function nextEventLoopTick() { + return new Promise((resolve) => setTimeout(() => resolve(), 0)); + } + function nextMicrotask() { + return Promise.resolve(); + } + function parseHTMLDocument(html = "") { + return new DOMParser().parseFromString(html, "text/html"); + } + function unindent(strings, ...values) { + const lines = interpolate(strings, values).replace(/^\n/, "").split("\n"); + const match = lines[0].match(/^\s+/); + const indent = match ? match[0].length : 0; + return lines.map((line) => line.slice(indent)).join("\n"); + } + function interpolate(strings, values) { + return strings.reduce((result, string, i) => { + const value = values[i] == void 0 ? "" : values[i]; + return result + string + value; + }, ""); + } + function uuid() { + return Array.apply(null, { length: 36 }).map((_, i) => { + if (i == 8 || i == 13 || i == 18 || i == 23) { + return "-"; + } else if (i == 14) { + return "4"; + } else if (i == 19) { + return (Math.floor(Math.random() * 4) + 8).toString(16); + } else { + return Math.floor(Math.random() * 15).toString(16); + } + }).join(""); + } + function getAttribute(attributeName, ...elements) { + for (const value of elements.map((element) => element === null || element === void 0 ? void 0 : element.getAttribute(attributeName))) { + if (typeof value == "string") + return value; + } + return null; + } + function markAsBusy(...elements) { + for (const element of elements) { + if (element.localName == "turbo-frame") { + element.setAttribute("busy", ""); + } + element.setAttribute("aria-busy", "true"); + } + } + function clearBusyState(...elements) { + for (const element of elements) { + if (element.localName == "turbo-frame") { + element.removeAttribute("busy"); + } + element.removeAttribute("aria-busy"); + } + } + var FetchMethod; + (function(FetchMethod2) { + FetchMethod2[FetchMethod2["get"] = 0] = "get"; + FetchMethod2[FetchMethod2["post"] = 1] = "post"; + FetchMethod2[FetchMethod2["put"] = 2] = "put"; + FetchMethod2[FetchMethod2["patch"] = 3] = "patch"; + FetchMethod2[FetchMethod2["delete"] = 4] = "delete"; + })(FetchMethod || (FetchMethod = {})); + function fetchMethodFromString(method) { + switch (method.toLowerCase()) { + case "get": + return FetchMethod.get; + case "post": + return FetchMethod.post; + case "put": + return FetchMethod.put; + case "patch": + return FetchMethod.patch; + case "delete": + return FetchMethod.delete; + } + } + var FetchRequest = class { + constructor(delegate, method, location2, body = new URLSearchParams(), target = null) { + this.abortController = new AbortController(); + this.resolveRequestPromise = (value) => { + }; + this.delegate = delegate; + this.method = method; + this.headers = this.defaultHeaders; + this.body = body; + this.url = location2; + this.target = target; + } + get location() { + return this.url; + } + get params() { + return this.url.searchParams; + } + get entries() { + return this.body ? Array.from(this.body.entries()) : []; + } + cancel() { + this.abortController.abort(); + } + async perform() { + var _a, _b; + const { fetchOptions } = this; + (_b = (_a = this.delegate).prepareHeadersForRequest) === null || _b === void 0 ? void 0 : _b.call(_a, this.headers, this); + await this.allowRequestToBeIntercepted(fetchOptions); + try { + this.delegate.requestStarted(this); + const response = await fetch(this.url.href, fetchOptions); + return await this.receive(response); + } catch (error2) { + if (error2.name !== "AbortError") { + this.delegate.requestErrored(this, error2); + throw error2; + } + } finally { + this.delegate.requestFinished(this); + } + } + async receive(response) { + const fetchResponse = new FetchResponse(response); + const event = dispatch("turbo:before-fetch-response", { cancelable: true, detail: { fetchResponse }, target: this.target }); + if (event.defaultPrevented) { + this.delegate.requestPreventedHandlingResponse(this, fetchResponse); + } else if (fetchResponse.succeeded) { + this.delegate.requestSucceededWithResponse(this, fetchResponse); + } else { + this.delegate.requestFailedWithResponse(this, fetchResponse); + } + return fetchResponse; + } + get fetchOptions() { + var _a; + return { + method: FetchMethod[this.method].toUpperCase(), + credentials: "same-origin", + headers: this.headers, + redirect: "follow", + body: this.isIdempotent ? null : this.body, + signal: this.abortSignal, + referrer: (_a = this.delegate.referrer) === null || _a === void 0 ? void 0 : _a.href + }; + } + get defaultHeaders() { + return { + "Accept": "text/html, application/xhtml+xml" + }; + } + get isIdempotent() { + return this.method == FetchMethod.get; + } + get abortSignal() { + return this.abortController.signal; + } + async allowRequestToBeIntercepted(fetchOptions) { + const requestInterception = new Promise((resolve) => this.resolveRequestPromise = resolve); + const event = dispatch("turbo:before-fetch-request", { + cancelable: true, + detail: { + fetchOptions, + url: this.url, + resume: this.resolveRequestPromise + }, + target: this.target + }); + if (event.defaultPrevented) + await requestInterception; + } + }; + var AppearanceObserver = class { + constructor(delegate, element) { + this.started = false; + this.intersect = (entries) => { + const lastEntry = entries.slice(-1)[0]; + if (lastEntry === null || lastEntry === void 0 ? void 0 : lastEntry.isIntersecting) { + this.delegate.elementAppearedInViewport(this.element); + } + }; + this.delegate = delegate; + this.element = element; + this.intersectionObserver = new IntersectionObserver(this.intersect); + } + start() { + if (!this.started) { + this.started = true; + this.intersectionObserver.observe(this.element); + } + } + stop() { + if (this.started) { + this.started = false; + this.intersectionObserver.unobserve(this.element); + } + } + }; + var StreamMessage = class { + constructor(html) { + this.templateElement = document.createElement("template"); + this.templateElement.innerHTML = html; + } + static wrap(message) { + if (typeof message == "string") { + return new this(message); + } else { + return message; + } + } + get fragment() { + const fragment = document.createDocumentFragment(); + for (const element of this.foreignElements) { + fragment.appendChild(document.importNode(element, true)); + } + return fragment; + } + get foreignElements() { + return this.templateChildren.reduce((streamElements, child) => { + if (child.tagName.toLowerCase() == "turbo-stream") { + return [...streamElements, child]; + } else { + return streamElements; + } + }, []); + } + get templateChildren() { + return Array.from(this.templateElement.content.children); + } + }; + StreamMessage.contentType = "text/vnd.turbo-stream.html"; + var FormSubmissionState; + (function(FormSubmissionState2) { + FormSubmissionState2[FormSubmissionState2["initialized"] = 0] = "initialized"; + FormSubmissionState2[FormSubmissionState2["requesting"] = 1] = "requesting"; + FormSubmissionState2[FormSubmissionState2["waiting"] = 2] = "waiting"; + FormSubmissionState2[FormSubmissionState2["receiving"] = 3] = "receiving"; + FormSubmissionState2[FormSubmissionState2["stopping"] = 4] = "stopping"; + FormSubmissionState2[FormSubmissionState2["stopped"] = 5] = "stopped"; + })(FormSubmissionState || (FormSubmissionState = {})); + var FormEnctype; + (function(FormEnctype2) { + FormEnctype2["urlEncoded"] = "application/x-www-form-urlencoded"; + FormEnctype2["multipart"] = "multipart/form-data"; + FormEnctype2["plain"] = "text/plain"; + })(FormEnctype || (FormEnctype = {})); + function formEnctypeFromString(encoding) { + switch (encoding.toLowerCase()) { + case FormEnctype.multipart: + return FormEnctype.multipart; + case FormEnctype.plain: + return FormEnctype.plain; + default: + return FormEnctype.urlEncoded; + } + } + var FormSubmission = class { + constructor(delegate, formElement, submitter, mustRedirect = false) { + this.state = FormSubmissionState.initialized; + this.delegate = delegate; + this.formElement = formElement; + this.submitter = submitter; + this.formData = buildFormData(formElement, submitter); + this.location = expandURL(this.action); + if (this.method == FetchMethod.get) { + mergeFormDataEntries(this.location, [...this.body.entries()]); + } + this.fetchRequest = new FetchRequest(this, this.method, this.location, this.body, this.formElement); + this.mustRedirect = mustRedirect; + } + static confirmMethod(message, element) { + return confirm(message); + } + get method() { + var _a; + const method = ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formmethod")) || this.formElement.getAttribute("method") || ""; + return fetchMethodFromString(method.toLowerCase()) || FetchMethod.get; + } + get action() { + var _a; + const formElementAction = typeof this.formElement.action === "string" ? this.formElement.action : null; + return ((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formaction")) || this.formElement.getAttribute("action") || formElementAction || ""; + } + get body() { + if (this.enctype == FormEnctype.urlEncoded || this.method == FetchMethod.get) { + return new URLSearchParams(this.stringFormData); + } else { + return this.formData; + } + } + get enctype() { + var _a; + return formEnctypeFromString(((_a = this.submitter) === null || _a === void 0 ? void 0 : _a.getAttribute("formenctype")) || this.formElement.enctype); + } + get isIdempotent() { + return this.fetchRequest.isIdempotent; + } + get stringFormData() { + return [...this.formData].reduce((entries, [name, value]) => { + return entries.concat(typeof value == "string" ? [[name, value]] : []); + }, []); + } + get confirmationMessage() { + return this.formElement.getAttribute("data-turbo-confirm"); + } + get needsConfirmation() { + return this.confirmationMessage !== null; + } + async start() { + const { initialized, requesting } = FormSubmissionState; + if (this.needsConfirmation) { + const answer = FormSubmission.confirmMethod(this.confirmationMessage, this.formElement); + if (!answer) { + return; + } + } + if (this.state == initialized) { + this.state = requesting; + return this.fetchRequest.perform(); + } + } + stop() { + const { stopping, stopped } = FormSubmissionState; + if (this.state != stopping && this.state != stopped) { + this.state = stopping; + this.fetchRequest.cancel(); + return true; + } + } + prepareHeadersForRequest(headers, request) { + if (!request.isIdempotent) { + const token = getCookieValue(getMetaContent("csrf-param")) || getMetaContent("csrf-token"); + if (token) { + headers["X-CSRF-Token"] = token; + } + headers["Accept"] = [StreamMessage.contentType, headers["Accept"]].join(", "); + } + } + requestStarted(request) { + var _a; + this.state = FormSubmissionState.waiting; + (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.setAttribute("disabled", ""); + dispatch("turbo:submit-start", { target: this.formElement, detail: { formSubmission: this } }); + this.delegate.formSubmissionStarted(this); + } + requestPreventedHandlingResponse(request, response) { + this.result = { success: response.succeeded, fetchResponse: response }; + } + requestSucceededWithResponse(request, response) { + if (response.clientError || response.serverError) { + this.delegate.formSubmissionFailedWithResponse(this, response); + } else if (this.requestMustRedirect(request) && responseSucceededWithoutRedirect(response)) { + const error2 = new Error("Form responses must redirect to another location"); + this.delegate.formSubmissionErrored(this, error2); + } else { + this.state = FormSubmissionState.receiving; + this.result = { success: true, fetchResponse: response }; + this.delegate.formSubmissionSucceededWithResponse(this, response); + } + } + requestFailedWithResponse(request, response) { + this.result = { success: false, fetchResponse: response }; + this.delegate.formSubmissionFailedWithResponse(this, response); + } + requestErrored(request, error2) { + this.result = { success: false, error: error2 }; + this.delegate.formSubmissionErrored(this, error2); + } + requestFinished(request) { + var _a; + this.state = FormSubmissionState.stopped; + (_a = this.submitter) === null || _a === void 0 ? void 0 : _a.removeAttribute("disabled"); + dispatch("turbo:submit-end", { target: this.formElement, detail: Object.assign({ formSubmission: this }, this.result) }); + this.delegate.formSubmissionFinished(this); + } + requestMustRedirect(request) { + return !request.isIdempotent && this.mustRedirect; + } + }; + function buildFormData(formElement, submitter) { + const formData = new FormData(formElement); + const name = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("name"); + const value = submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("value"); + if (name && value != null && formData.get(name) != value) { + formData.append(name, value); + } + return formData; + } + function getCookieValue(cookieName) { + if (cookieName != null) { + const cookies = document.cookie ? document.cookie.split("; ") : []; + const cookie = cookies.find((cookie2) => cookie2.startsWith(cookieName)); + if (cookie) { + const value = cookie.split("=").slice(1).join("="); + return value ? decodeURIComponent(value) : void 0; + } + } + } + function getMetaContent(name) { + const element = document.querySelector(`meta[name="${name}"]`); + return element && element.content; + } + function responseSucceededWithoutRedirect(response) { + return response.statusCode == 200 && !response.redirected; + } + function mergeFormDataEntries(url, entries) { + const searchParams = new URLSearchParams(); + for (const [name, value] of entries) { + if (value instanceof File) + continue; + searchParams.append(name, value); + } + url.search = searchParams.toString(); + return url; + } + var Snapshot = class { + constructor(element) { + this.element = element; + } + get children() { + return [...this.element.children]; + } + hasAnchor(anchor) { + return this.getElementForAnchor(anchor) != null; + } + getElementForAnchor(anchor) { + return anchor ? this.element.querySelector(`[id='${anchor}'], a[name='${anchor}']`) : null; + } + get isConnected() { + return this.element.isConnected; + } + get firstAutofocusableElement() { + return this.element.querySelector("[autofocus]"); + } + get permanentElements() { + return [...this.element.querySelectorAll("[id][data-turbo-permanent]")]; + } + getPermanentElementById(id) { + return this.element.querySelector(`#${id}[data-turbo-permanent]`); + } + getPermanentElementMapForSnapshot(snapshot) { + const permanentElementMap = {}; + for (const currentPermanentElement of this.permanentElements) { + const { id } = currentPermanentElement; + const newPermanentElement = snapshot.getPermanentElementById(id); + if (newPermanentElement) { + permanentElementMap[id] = [currentPermanentElement, newPermanentElement]; + } + } + return permanentElementMap; + } + }; + var FormInterceptor = class { + constructor(delegate, element) { + this.submitBubbled = (event) => { + const form = event.target; + if (!event.defaultPrevented && form instanceof HTMLFormElement && form.closest("turbo-frame, html") == this.element) { + const submitter = event.submitter || void 0; + const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.method; + if (method != "dialog" && this.delegate.shouldInterceptFormSubmission(form, submitter)) { + event.preventDefault(); + event.stopImmediatePropagation(); + this.delegate.formSubmissionIntercepted(form, submitter); + } + } + }; + this.delegate = delegate; + this.element = element; + } + start() { + this.element.addEventListener("submit", this.submitBubbled); + } + stop() { + this.element.removeEventListener("submit", this.submitBubbled); + } + }; + var View = class { + constructor(delegate, element) { + this.resolveRenderPromise = (value) => { + }; + this.resolveInterceptionPromise = (value) => { + }; + this.delegate = delegate; + this.element = element; + } + scrollToAnchor(anchor) { + const element = this.snapshot.getElementForAnchor(anchor); + if (element) { + this.scrollToElement(element); + this.focusElement(element); + } else { + this.scrollToPosition({ x: 0, y: 0 }); + } + } + scrollToAnchorFromLocation(location2) { + this.scrollToAnchor(getAnchor(location2)); + } + scrollToElement(element) { + element.scrollIntoView(); + } + focusElement(element) { + if (element instanceof HTMLElement) { + if (element.hasAttribute("tabindex")) { + element.focus(); + } else { + element.setAttribute("tabindex", "-1"); + element.focus(); + element.removeAttribute("tabindex"); + } + } + } + scrollToPosition({ x, y }) { + this.scrollRoot.scrollTo(x, y); + } + scrollToTop() { + this.scrollToPosition({ x: 0, y: 0 }); + } + get scrollRoot() { + return window; + } + async render(renderer) { + const { isPreview, shouldRender, newSnapshot: snapshot } = renderer; + if (shouldRender) { + try { + this.renderPromise = new Promise((resolve) => this.resolveRenderPromise = resolve); + this.renderer = renderer; + this.prepareToRenderSnapshot(renderer); + const renderInterception = new Promise((resolve) => this.resolveInterceptionPromise = resolve); + const immediateRender = this.delegate.allowsImmediateRender(snapshot, this.resolveInterceptionPromise); + if (!immediateRender) + await renderInterception; + await this.renderSnapshot(renderer); + this.delegate.viewRenderedSnapshot(snapshot, isPreview); + this.finishRenderingSnapshot(renderer); + } finally { + delete this.renderer; + this.resolveRenderPromise(void 0); + delete this.renderPromise; + } + } else { + this.invalidate(); + } + } + invalidate() { + this.delegate.viewInvalidated(); + } + prepareToRenderSnapshot(renderer) { + this.markAsPreview(renderer.isPreview); + renderer.prepareToRender(); + } + markAsPreview(isPreview) { + if (isPreview) { + this.element.setAttribute("data-turbo-preview", ""); + } else { + this.element.removeAttribute("data-turbo-preview"); + } + } + async renderSnapshot(renderer) { + await renderer.render(); + } + finishRenderingSnapshot(renderer) { + renderer.finishRendering(); + } + }; + var FrameView = class extends View { + invalidate() { + this.element.innerHTML = ""; + } + get snapshot() { + return new Snapshot(this.element); + } + }; + var LinkInterceptor = class { + constructor(delegate, element) { + this.clickBubbled = (event) => { + if (this.respondsToEventTarget(event.target)) { + this.clickEvent = event; + } else { + delete this.clickEvent; + } + }; + this.linkClicked = (event) => { + if (this.clickEvent && this.respondsToEventTarget(event.target) && event.target instanceof Element) { + if (this.delegate.shouldInterceptLinkClick(event.target, event.detail.url)) { + this.clickEvent.preventDefault(); + event.preventDefault(); + this.delegate.linkClickIntercepted(event.target, event.detail.url); + } + } + delete this.clickEvent; + }; + this.willVisit = () => { + delete this.clickEvent; + }; + this.delegate = delegate; + this.element = element; + } + start() { + this.element.addEventListener("click", this.clickBubbled); + document.addEventListener("turbo:click", this.linkClicked); + document.addEventListener("turbo:before-visit", this.willVisit); + } + stop() { + this.element.removeEventListener("click", this.clickBubbled); + document.removeEventListener("turbo:click", this.linkClicked); + document.removeEventListener("turbo:before-visit", this.willVisit); + } + respondsToEventTarget(target) { + const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null; + return element && element.closest("turbo-frame, html") == this.element; + } + }; + var Bardo = class { + constructor(permanentElementMap) { + this.permanentElementMap = permanentElementMap; + } + static preservingPermanentElements(permanentElementMap, callback) { + const bardo = new this(permanentElementMap); + bardo.enter(); + callback(); + bardo.leave(); + } + enter() { + for (const id in this.permanentElementMap) { + const [, newPermanentElement] = this.permanentElementMap[id]; + this.replaceNewPermanentElementWithPlaceholder(newPermanentElement); + } + } + leave() { + for (const id in this.permanentElementMap) { + const [currentPermanentElement] = this.permanentElementMap[id]; + this.replaceCurrentPermanentElementWithClone(currentPermanentElement); + this.replacePlaceholderWithPermanentElement(currentPermanentElement); + } + } + replaceNewPermanentElementWithPlaceholder(permanentElement) { + const placeholder = createPlaceholderForPermanentElement(permanentElement); + permanentElement.replaceWith(placeholder); + } + replaceCurrentPermanentElementWithClone(permanentElement) { + const clone = permanentElement.cloneNode(true); + permanentElement.replaceWith(clone); + } + replacePlaceholderWithPermanentElement(permanentElement) { + const placeholder = this.getPlaceholderById(permanentElement.id); + placeholder === null || placeholder === void 0 ? void 0 : placeholder.replaceWith(permanentElement); + } + getPlaceholderById(id) { + return this.placeholders.find((element) => element.content == id); + } + get placeholders() { + return [...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")]; + } + }; + function createPlaceholderForPermanentElement(permanentElement) { + const element = document.createElement("meta"); + element.setAttribute("name", "turbo-permanent-placeholder"); + element.setAttribute("content", permanentElement.id); + return element; + } + var Renderer = class { + constructor(currentSnapshot, newSnapshot, isPreview, willRender = true) { + this.currentSnapshot = currentSnapshot; + this.newSnapshot = newSnapshot; + this.isPreview = isPreview; + this.willRender = willRender; + this.promise = new Promise((resolve, reject) => this.resolvingFunctions = { resolve, reject }); + } + get shouldRender() { + return true; + } + prepareToRender() { + return; + } + finishRendering() { + if (this.resolvingFunctions) { + this.resolvingFunctions.resolve(); + delete this.resolvingFunctions; + } + } + createScriptElement(element) { + if (element.getAttribute("data-turbo-eval") == "false") { + return element; + } else { + const createdScriptElement = document.createElement("script"); + if (this.cspNonce) { + createdScriptElement.nonce = this.cspNonce; + } + createdScriptElement.textContent = element.textContent; + createdScriptElement.async = false; + copyElementAttributes(createdScriptElement, element); + return createdScriptElement; + } + } + preservingPermanentElements(callback) { + Bardo.preservingPermanentElements(this.permanentElementMap, callback); + } + focusFirstAutofocusableElement() { + const element = this.connectedSnapshot.firstAutofocusableElement; + if (elementIsFocusable(element)) { + element.focus(); + } + } + get connectedSnapshot() { + return this.newSnapshot.isConnected ? this.newSnapshot : this.currentSnapshot; + } + get currentElement() { + return this.currentSnapshot.element; + } + get newElement() { + return this.newSnapshot.element; + } + get permanentElementMap() { + return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot); + } + get cspNonce() { + var _a; + return (_a = document.head.querySelector('meta[name="csp-nonce"]')) === null || _a === void 0 ? void 0 : _a.getAttribute("content"); + } + }; + function copyElementAttributes(destinationElement, sourceElement) { + for (const { name, value } of [...sourceElement.attributes]) { + destinationElement.setAttribute(name, value); + } + } + function elementIsFocusable(element) { + return element && typeof element.focus == "function"; + } + var FrameRenderer = class extends Renderer { + get shouldRender() { + return true; + } + async render() { + await nextAnimationFrame(); + this.preservingPermanentElements(() => { + this.loadFrameElement(); + }); + this.scrollFrameIntoView(); + await nextAnimationFrame(); + this.focusFirstAutofocusableElement(); + await nextAnimationFrame(); + this.activateScriptElements(); + } + loadFrameElement() { + var _a; + const destinationRange = document.createRange(); + destinationRange.selectNodeContents(this.currentElement); + destinationRange.deleteContents(); + const frameElement = this.newElement; + const sourceRange = (_a = frameElement.ownerDocument) === null || _a === void 0 ? void 0 : _a.createRange(); + if (sourceRange) { + sourceRange.selectNodeContents(frameElement); + this.currentElement.appendChild(sourceRange.extractContents()); + } + } + scrollFrameIntoView() { + if (this.currentElement.autoscroll || this.newElement.autoscroll) { + const element = this.currentElement.firstElementChild; + const block = readScrollLogicalPosition(this.currentElement.getAttribute("data-autoscroll-block"), "end"); + if (element) { + element.scrollIntoView({ block }); + return true; + } + } + return false; + } + activateScriptElements() { + for (const inertScriptElement of this.newScriptElements) { + const activatedScriptElement = this.createScriptElement(inertScriptElement); + inertScriptElement.replaceWith(activatedScriptElement); + } + } + get newScriptElements() { + return this.currentElement.querySelectorAll("script"); + } + }; + function readScrollLogicalPosition(value, defaultValue) { + if (value == "end" || value == "start" || value == "center" || value == "nearest") { + return value; + } else { + return defaultValue; + } + } + var ProgressBar = class { + constructor() { + this.hiding = false; + this.value = 0; + this.visible = false; + this.trickle = () => { + this.setValue(this.value + Math.random() / 100); + }; + this.stylesheetElement = this.createStylesheetElement(); + this.progressElement = this.createProgressElement(); + this.installStylesheetElement(); + this.setValue(0); + } + static get defaultCSS() { + return unindent` + .turbo-progress-bar { + position: fixed; + display: block; + top: 0; + left: 0; + height: 3px; + background: #0076ff; + z-index: 9999; + transition: + width ${ProgressBar.animationDuration}ms ease-out, + opacity ${ProgressBar.animationDuration / 2}ms ${ProgressBar.animationDuration / 2}ms ease-in; + transform: translate3d(0, 0, 0); + } + `; + } + show() { + if (!this.visible) { + this.visible = true; + this.installProgressElement(); + this.startTrickling(); + } + } + hide() { + if (this.visible && !this.hiding) { + this.hiding = true; + this.fadeProgressElement(() => { + this.uninstallProgressElement(); + this.stopTrickling(); + this.visible = false; + this.hiding = false; + }); + } + } + setValue(value) { + this.value = value; + this.refresh(); + } + installStylesheetElement() { + document.head.insertBefore(this.stylesheetElement, document.head.firstChild); + } + installProgressElement() { + this.progressElement.style.width = "0"; + this.progressElement.style.opacity = "1"; + document.documentElement.insertBefore(this.progressElement, document.body); + this.refresh(); + } + fadeProgressElement(callback) { + this.progressElement.style.opacity = "0"; + setTimeout(callback, ProgressBar.animationDuration * 1.5); + } + uninstallProgressElement() { + if (this.progressElement.parentNode) { + document.documentElement.removeChild(this.progressElement); + } + } + startTrickling() { + if (!this.trickleInterval) { + this.trickleInterval = window.setInterval(this.trickle, ProgressBar.animationDuration); + } + } + stopTrickling() { + window.clearInterval(this.trickleInterval); + delete this.trickleInterval; + } + refresh() { + requestAnimationFrame(() => { + this.progressElement.style.width = `${10 + this.value * 90}%`; + }); + } + createStylesheetElement() { + const element = document.createElement("style"); + element.type = "text/css"; + element.textContent = ProgressBar.defaultCSS; + return element; + } + createProgressElement() { + const element = document.createElement("div"); + element.className = "turbo-progress-bar"; + return element; + } + }; + ProgressBar.animationDuration = 300; + var HeadSnapshot = class extends Snapshot { + constructor() { + super(...arguments); + this.detailsByOuterHTML = this.children.filter((element) => !elementIsNoscript(element)).map((element) => elementWithoutNonce(element)).reduce((result, element) => { + const { outerHTML } = element; + const details = outerHTML in result ? result[outerHTML] : { + type: elementType(element), + tracked: elementIsTracked(element), + elements: [] + }; + return Object.assign(Object.assign({}, result), { [outerHTML]: Object.assign(Object.assign({}, details), { elements: [...details.elements, element] }) }); + }, {}); + } + get trackedElementSignature() { + return Object.keys(this.detailsByOuterHTML).filter((outerHTML) => this.detailsByOuterHTML[outerHTML].tracked).join(""); + } + getScriptElementsNotInSnapshot(snapshot) { + return this.getElementsMatchingTypeNotInSnapshot("script", snapshot); + } + getStylesheetElementsNotInSnapshot(snapshot) { + return this.getElementsMatchingTypeNotInSnapshot("stylesheet", snapshot); + } + getElementsMatchingTypeNotInSnapshot(matchedType, snapshot) { + return Object.keys(this.detailsByOuterHTML).filter((outerHTML) => !(outerHTML in snapshot.detailsByOuterHTML)).map((outerHTML) => this.detailsByOuterHTML[outerHTML]).filter(({ type }) => type == matchedType).map(({ elements: [element] }) => element); + } + get provisionalElements() { + return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => { + const { type, tracked, elements } = this.detailsByOuterHTML[outerHTML]; + if (type == null && !tracked) { + return [...result, ...elements]; + } else if (elements.length > 1) { + return [...result, ...elements.slice(1)]; + } else { + return result; + } + }, []); + } + getMetaValue(name) { + const element = this.findMetaElementByName(name); + return element ? element.getAttribute("content") : null; + } + findMetaElementByName(name) { + return Object.keys(this.detailsByOuterHTML).reduce((result, outerHTML) => { + const { elements: [element] } = this.detailsByOuterHTML[outerHTML]; + return elementIsMetaElementWithName(element, name) ? element : result; + }, void 0); + } + }; + function elementType(element) { + if (elementIsScript(element)) { + return "script"; + } else if (elementIsStylesheet(element)) { + return "stylesheet"; + } + } + function elementIsTracked(element) { + return element.getAttribute("data-turbo-track") == "reload"; + } + function elementIsScript(element) { + const tagName = element.tagName.toLowerCase(); + return tagName == "script"; + } + function elementIsNoscript(element) { + const tagName = element.tagName.toLowerCase(); + return tagName == "noscript"; + } + function elementIsStylesheet(element) { + const tagName = element.tagName.toLowerCase(); + return tagName == "style" || tagName == "link" && element.getAttribute("rel") == "stylesheet"; + } + function elementIsMetaElementWithName(element, name) { + const tagName = element.tagName.toLowerCase(); + return tagName == "meta" && element.getAttribute("name") == name; + } + function elementWithoutNonce(element) { + if (element.hasAttribute("nonce")) { + element.setAttribute("nonce", ""); + } + return element; + } + var PageSnapshot = class extends Snapshot { + constructor(element, headSnapshot) { + super(element); + this.headSnapshot = headSnapshot; + } + static fromHTMLString(html = "") { + return this.fromDocument(parseHTMLDocument(html)); + } + static fromElement(element) { + return this.fromDocument(element.ownerDocument); + } + static fromDocument({ head, body }) { + return new this(body, new HeadSnapshot(head)); + } + clone() { + return new PageSnapshot(this.element.cloneNode(true), this.headSnapshot); + } + get headElement() { + return this.headSnapshot.element; + } + get rootLocation() { + var _a; + const root = (_a = this.getSetting("root")) !== null && _a !== void 0 ? _a : "/"; + return expandURL(root); + } + get cacheControlValue() { + return this.getSetting("cache-control"); + } + get isPreviewable() { + return this.cacheControlValue != "no-preview"; + } + get isCacheable() { + return this.cacheControlValue != "no-cache"; + } + get isVisitable() { + return this.getSetting("visit-control") != "reload"; + } + getSetting(name) { + return this.headSnapshot.getMetaValue(`turbo-${name}`); + } + }; + var TimingMetric; + (function(TimingMetric2) { + TimingMetric2["visitStart"] = "visitStart"; + TimingMetric2["requestStart"] = "requestStart"; + TimingMetric2["requestEnd"] = "requestEnd"; + TimingMetric2["visitEnd"] = "visitEnd"; + })(TimingMetric || (TimingMetric = {})); + var VisitState; + (function(VisitState2) { + VisitState2["initialized"] = "initialized"; + VisitState2["started"] = "started"; + VisitState2["canceled"] = "canceled"; + VisitState2["failed"] = "failed"; + VisitState2["completed"] = "completed"; + })(VisitState || (VisitState = {})); + var defaultOptions = { + action: "advance", + historyChanged: false, + visitCachedSnapshot: () => { + }, + willRender: true + }; + var SystemStatusCode; + (function(SystemStatusCode2) { + SystemStatusCode2[SystemStatusCode2["networkFailure"] = 0] = "networkFailure"; + SystemStatusCode2[SystemStatusCode2["timeoutFailure"] = -1] = "timeoutFailure"; + SystemStatusCode2[SystemStatusCode2["contentTypeMismatch"] = -2] = "contentTypeMismatch"; + })(SystemStatusCode || (SystemStatusCode = {})); + var Visit = class { + constructor(delegate, location2, restorationIdentifier, options = {}) { + this.identifier = uuid(); + this.timingMetrics = {}; + this.followedRedirect = false; + this.historyChanged = false; + this.scrolled = false; + this.snapshotCached = false; + this.state = VisitState.initialized; + this.delegate = delegate; + this.location = location2; + this.restorationIdentifier = restorationIdentifier || uuid(); + const { action, historyChanged, referrer, snapshotHTML, response, visitCachedSnapshot, willRender } = Object.assign(Object.assign({}, defaultOptions), options); + this.action = action; + this.historyChanged = historyChanged; + this.referrer = referrer; + this.snapshotHTML = snapshotHTML; + this.response = response; + this.isSamePage = this.delegate.locationWithActionIsSamePage(this.location, this.action); + this.visitCachedSnapshot = visitCachedSnapshot; + this.willRender = willRender; + this.scrolled = !willRender; + } + get adapter() { + return this.delegate.adapter; + } + get view() { + return this.delegate.view; + } + get history() { + return this.delegate.history; + } + get restorationData() { + return this.history.getRestorationDataForIdentifier(this.restorationIdentifier); + } + get silent() { + return this.isSamePage; + } + start() { + if (this.state == VisitState.initialized) { + this.recordTimingMetric(TimingMetric.visitStart); + this.state = VisitState.started; + this.adapter.visitStarted(this); + this.delegate.visitStarted(this); + } + } + cancel() { + if (this.state == VisitState.started) { + if (this.request) { + this.request.cancel(); + } + this.cancelRender(); + this.state = VisitState.canceled; + } + } + complete() { + if (this.state == VisitState.started) { + this.recordTimingMetric(TimingMetric.visitEnd); + this.state = VisitState.completed; + this.adapter.visitCompleted(this); + this.delegate.visitCompleted(this); + this.followRedirect(); + } + } + fail() { + if (this.state == VisitState.started) { + this.state = VisitState.failed; + this.adapter.visitFailed(this); + } + } + changeHistory() { + var _a; + if (!this.historyChanged) { + const actionForHistory = this.location.href === ((_a = this.referrer) === null || _a === void 0 ? void 0 : _a.href) ? "replace" : this.action; + const method = this.getHistoryMethodForAction(actionForHistory); + this.history.update(method, this.location, this.restorationIdentifier); + this.historyChanged = true; + } + } + issueRequest() { + if (this.hasPreloadedResponse()) { + this.simulateRequest(); + } else if (this.shouldIssueRequest() && !this.request) { + this.request = new FetchRequest(this, FetchMethod.get, this.location); + this.request.perform(); + } + } + simulateRequest() { + if (this.response) { + this.startRequest(); + this.recordResponse(); + this.finishRequest(); + } + } + startRequest() { + this.recordTimingMetric(TimingMetric.requestStart); + this.adapter.visitRequestStarted(this); + } + recordResponse(response = this.response) { + this.response = response; + if (response) { + const { statusCode } = response; + if (isSuccessful(statusCode)) { + this.adapter.visitRequestCompleted(this); + } else { + this.adapter.visitRequestFailedWithStatusCode(this, statusCode); + } + } + } + finishRequest() { + this.recordTimingMetric(TimingMetric.requestEnd); + this.adapter.visitRequestFinished(this); + } + loadResponse() { + if (this.response) { + const { statusCode, responseHTML } = this.response; + this.render(async () => { + this.cacheSnapshot(); + if (this.view.renderPromise) + await this.view.renderPromise; + if (isSuccessful(statusCode) && responseHTML != null) { + await this.view.renderPage(PageSnapshot.fromHTMLString(responseHTML), false, this.willRender); + this.adapter.visitRendered(this); + this.complete(); + } else { + await this.view.renderError(PageSnapshot.fromHTMLString(responseHTML)); + this.adapter.visitRendered(this); + this.fail(); + } + }); + } + } + getCachedSnapshot() { + const snapshot = this.view.getCachedSnapshotForLocation(this.location) || this.getPreloadedSnapshot(); + if (snapshot && (!getAnchor(this.location) || snapshot.hasAnchor(getAnchor(this.location)))) { + if (this.action == "restore" || snapshot.isPreviewable) { + return snapshot; + } + } + } + getPreloadedSnapshot() { + if (this.snapshotHTML) { + return PageSnapshot.fromHTMLString(this.snapshotHTML); + } + } + hasCachedSnapshot() { + return this.getCachedSnapshot() != null; + } + loadCachedSnapshot() { + const snapshot = this.getCachedSnapshot(); + if (snapshot) { + const isPreview = this.shouldIssueRequest(); + this.render(async () => { + this.cacheSnapshot(); + if (this.isSamePage) { + this.adapter.visitRendered(this); + } else { + if (this.view.renderPromise) + await this.view.renderPromise; + await this.view.renderPage(snapshot, isPreview, this.willRender); + this.adapter.visitRendered(this); + if (!isPreview) { + this.complete(); + } + } + }); + } + } + followRedirect() { + var _a; + if (this.redirectedToLocation && !this.followedRedirect && ((_a = this.response) === null || _a === void 0 ? void 0 : _a.redirected)) { + this.adapter.visitProposedToLocation(this.redirectedToLocation, { + action: "replace", + response: this.response + }); + this.followedRedirect = true; + } + } + goToSamePageAnchor() { + if (this.isSamePage) { + this.render(async () => { + this.cacheSnapshot(); + this.adapter.visitRendered(this); + }); + } + } + requestStarted() { + this.startRequest(); + } + requestPreventedHandlingResponse(request, response) { + } + async requestSucceededWithResponse(request, response) { + const responseHTML = await response.responseHTML; + const { redirected, statusCode } = response; + if (responseHTML == void 0) { + this.recordResponse({ statusCode: SystemStatusCode.contentTypeMismatch, redirected }); + } else { + this.redirectedToLocation = response.redirected ? response.location : void 0; + this.recordResponse({ statusCode, responseHTML, redirected }); + } + } + async requestFailedWithResponse(request, response) { + const responseHTML = await response.responseHTML; + const { redirected, statusCode } = response; + if (responseHTML == void 0) { + this.recordResponse({ statusCode: SystemStatusCode.contentTypeMismatch, redirected }); + } else { + this.recordResponse({ statusCode, responseHTML, redirected }); + } + } + requestErrored(request, error2) { + this.recordResponse({ statusCode: SystemStatusCode.networkFailure, redirected: false }); + } + requestFinished() { + this.finishRequest(); + } + performScroll() { + if (!this.scrolled) { + if (this.action == "restore") { + this.scrollToRestoredPosition() || this.scrollToAnchor() || this.view.scrollToTop(); + } else { + this.scrollToAnchor() || this.view.scrollToTop(); + } + if (this.isSamePage) { + this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation, this.location); + } + this.scrolled = true; + } + } + scrollToRestoredPosition() { + const { scrollPosition } = this.restorationData; + if (scrollPosition) { + this.view.scrollToPosition(scrollPosition); + return true; + } + } + scrollToAnchor() { + const anchor = getAnchor(this.location); + if (anchor != null) { + this.view.scrollToAnchor(anchor); + return true; + } + } + recordTimingMetric(metric) { + this.timingMetrics[metric] = new Date().getTime(); + } + getTimingMetrics() { + return Object.assign({}, this.timingMetrics); + } + getHistoryMethodForAction(action) { + switch (action) { + case "replace": + return history.replaceState; + case "advance": + case "restore": + return history.pushState; + } + } + hasPreloadedResponse() { + return typeof this.response == "object"; + } + shouldIssueRequest() { + if (this.isSamePage) { + return false; + } else if (this.action == "restore") { + return !this.hasCachedSnapshot(); + } else { + return this.willRender; + } + } + cacheSnapshot() { + if (!this.snapshotCached) { + this.view.cacheSnapshot().then((snapshot) => snapshot && this.visitCachedSnapshot(snapshot)); + this.snapshotCached = true; + } + } + async render(callback) { + this.cancelRender(); + await new Promise((resolve) => { + this.frame = requestAnimationFrame(() => resolve()); + }); + await callback(); + delete this.frame; + this.performScroll(); + } + cancelRender() { + if (this.frame) { + cancelAnimationFrame(this.frame); + delete this.frame; + } + } + }; + function isSuccessful(statusCode) { + return statusCode >= 200 && statusCode < 300; + } + var BrowserAdapter = class { + constructor(session2) { + this.progressBar = new ProgressBar(); + this.showProgressBar = () => { + this.progressBar.show(); + }; + this.session = session2; + } + visitProposedToLocation(location2, options) { + this.navigator.startVisit(location2, uuid(), options); + } + visitStarted(visit2) { + visit2.loadCachedSnapshot(); + visit2.issueRequest(); + visit2.changeHistory(); + visit2.goToSamePageAnchor(); + } + visitRequestStarted(visit2) { + this.progressBar.setValue(0); + if (visit2.hasCachedSnapshot() || visit2.action != "restore") { + this.showVisitProgressBarAfterDelay(); + } else { + this.showProgressBar(); + } + } + visitRequestCompleted(visit2) { + visit2.loadResponse(); + } + visitRequestFailedWithStatusCode(visit2, statusCode) { + switch (statusCode) { + case SystemStatusCode.networkFailure: + case SystemStatusCode.timeoutFailure: + case SystemStatusCode.contentTypeMismatch: + return this.reload(); + default: + return visit2.loadResponse(); + } + } + visitRequestFinished(visit2) { + this.progressBar.setValue(1); + this.hideVisitProgressBar(); + } + visitCompleted(visit2) { + } + pageInvalidated() { + this.reload(); + } + visitFailed(visit2) { + } + visitRendered(visit2) { + } + formSubmissionStarted(formSubmission) { + this.progressBar.setValue(0); + this.showFormProgressBarAfterDelay(); + } + formSubmissionFinished(formSubmission) { + this.progressBar.setValue(1); + this.hideFormProgressBar(); + } + showVisitProgressBarAfterDelay() { + this.visitProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay); + } + hideVisitProgressBar() { + this.progressBar.hide(); + if (this.visitProgressBarTimeout != null) { + window.clearTimeout(this.visitProgressBarTimeout); + delete this.visitProgressBarTimeout; + } + } + showFormProgressBarAfterDelay() { + if (this.formProgressBarTimeout == null) { + this.formProgressBarTimeout = window.setTimeout(this.showProgressBar, this.session.progressBarDelay); + } + } + hideFormProgressBar() { + this.progressBar.hide(); + if (this.formProgressBarTimeout != null) { + window.clearTimeout(this.formProgressBarTimeout); + delete this.formProgressBarTimeout; + } + } + reload() { + window.location.reload(); + } + get navigator() { + return this.session.navigator; + } + }; + var CacheObserver = class { + constructor() { + this.started = false; + } + start() { + if (!this.started) { + this.started = true; + addEventListener("turbo:before-cache", this.removeStaleElements, false); + } + } + stop() { + if (this.started) { + this.started = false; + removeEventListener("turbo:before-cache", this.removeStaleElements, false); + } + } + removeStaleElements() { + const staleElements = [...document.querySelectorAll('[data-turbo-cache="false"]')]; + for (const element of staleElements) { + element.remove(); + } + } + }; + var FormSubmitObserver = class { + constructor(delegate) { + this.started = false; + this.submitCaptured = () => { + removeEventListener("submit", this.submitBubbled, false); + addEventListener("submit", this.submitBubbled, false); + }; + this.submitBubbled = (event) => { + if (!event.defaultPrevented) { + const form = event.target instanceof HTMLFormElement ? event.target : void 0; + const submitter = event.submitter || void 0; + if (form) { + const method = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("formmethod")) || form.getAttribute("method"); + if (method != "dialog" && this.delegate.willSubmitForm(form, submitter)) { + event.preventDefault(); + this.delegate.formSubmitted(form, submitter); + } + } + } + }; + this.delegate = delegate; + } + start() { + if (!this.started) { + addEventListener("submit", this.submitCaptured, true); + this.started = true; + } + } + stop() { + if (this.started) { + removeEventListener("submit", this.submitCaptured, true); + this.started = false; + } + } + }; + var FrameRedirector = class { + constructor(element) { + this.element = element; + this.linkInterceptor = new LinkInterceptor(this, element); + this.formInterceptor = new FormInterceptor(this, element); + } + start() { + this.linkInterceptor.start(); + this.formInterceptor.start(); + } + stop() { + this.linkInterceptor.stop(); + this.formInterceptor.stop(); + } + shouldInterceptLinkClick(element, url) { + return this.shouldRedirect(element); + } + linkClickIntercepted(element, url) { + const frame = this.findFrameElement(element); + if (frame) { + frame.delegate.linkClickIntercepted(element, url); + } + } + shouldInterceptFormSubmission(element, submitter) { + return this.shouldSubmit(element, submitter); + } + formSubmissionIntercepted(element, submitter) { + const frame = this.findFrameElement(element, submitter); + if (frame) { + frame.removeAttribute("reloadable"); + frame.delegate.formSubmissionIntercepted(element, submitter); + } + } + shouldSubmit(form, submitter) { + var _a; + const action = getAction(form, submitter); + const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`); + const rootLocation = expandURL((_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/"); + return this.shouldRedirect(form, submitter) && locationIsVisitable(action, rootLocation); + } + shouldRedirect(element, submitter) { + const frame = this.findFrameElement(element, submitter); + return frame ? frame != element.closest("turbo-frame") : false; + } + findFrameElement(element, submitter) { + const id = (submitter === null || submitter === void 0 ? void 0 : submitter.getAttribute("data-turbo-frame")) || element.getAttribute("data-turbo-frame"); + if (id && id != "_top") { + const frame = this.element.querySelector(`#${id}:not([disabled])`); + if (frame instanceof FrameElement) { + return frame; + } + } + } + }; + var History = class { + constructor(delegate) { + this.restorationIdentifier = uuid(); + this.restorationData = {}; + this.started = false; + this.pageLoaded = false; + this.onPopState = (event) => { + if (this.shouldHandlePopState()) { + const { turbo } = event.state || {}; + if (turbo) { + this.location = new URL(window.location.href); + const { restorationIdentifier } = turbo; + this.restorationIdentifier = restorationIdentifier; + this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location, restorationIdentifier); + } + } + }; + this.onPageLoad = async (event) => { + await nextMicrotask(); + this.pageLoaded = true; + }; + this.delegate = delegate; + } + start() { + if (!this.started) { + addEventListener("popstate", this.onPopState, false); + addEventListener("load", this.onPageLoad, false); + this.started = true; + this.replace(new URL(window.location.href)); + } + } + stop() { + if (this.started) { + removeEventListener("popstate", this.onPopState, false); + removeEventListener("load", this.onPageLoad, false); + this.started = false; + } + } + push(location2, restorationIdentifier) { + this.update(history.pushState, location2, restorationIdentifier); + } + replace(location2, restorationIdentifier) { + this.update(history.replaceState, location2, restorationIdentifier); + } + update(method, location2, restorationIdentifier = uuid()) { + const state = { turbo: { restorationIdentifier } }; + method.call(history, state, "", location2.href); + this.location = location2; + this.restorationIdentifier = restorationIdentifier; + } + getRestorationDataForIdentifier(restorationIdentifier) { + return this.restorationData[restorationIdentifier] || {}; + } + updateRestorationData(additionalData) { + const { restorationIdentifier } = this; + const restorationData = this.restorationData[restorationIdentifier]; + this.restorationData[restorationIdentifier] = Object.assign(Object.assign({}, restorationData), additionalData); + } + assumeControlOfScrollRestoration() { + var _a; + if (!this.previousScrollRestoration) { + this.previousScrollRestoration = (_a = history.scrollRestoration) !== null && _a !== void 0 ? _a : "auto"; + history.scrollRestoration = "manual"; + } + } + relinquishControlOfScrollRestoration() { + if (this.previousScrollRestoration) { + history.scrollRestoration = this.previousScrollRestoration; + delete this.previousScrollRestoration; + } + } + shouldHandlePopState() { + return this.pageIsLoaded(); + } + pageIsLoaded() { + return this.pageLoaded || document.readyState == "complete"; + } + }; + var LinkClickObserver = class { + constructor(delegate) { + this.started = false; + this.clickCaptured = () => { + removeEventListener("click", this.clickBubbled, false); + addEventListener("click", this.clickBubbled, false); + }; + this.clickBubbled = (event) => { + if (this.clickEventIsSignificant(event)) { + const target = event.composedPath && event.composedPath()[0] || event.target; + const link = this.findLinkFromClickTarget(target); + if (link) { + const location2 = this.getLocationForLink(link); + if (this.delegate.willFollowLinkToLocation(link, location2)) { + event.preventDefault(); + this.delegate.followedLinkToLocation(link, location2); + } + } + } + }; + this.delegate = delegate; + } + start() { + if (!this.started) { + addEventListener("click", this.clickCaptured, true); + this.started = true; + } + } + stop() { + if (this.started) { + removeEventListener("click", this.clickCaptured, true); + this.started = false; + } + } + clickEventIsSignificant(event) { + return !(event.target && event.target.isContentEditable || event.defaultPrevented || event.which > 1 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey); + } + findLinkFromClickTarget(target) { + if (target instanceof Element) { + return target.closest("a[href]:not([target^=_]):not([download])"); + } + } + getLocationForLink(link) { + return expandURL(link.getAttribute("href") || ""); + } + }; + function isAction(action) { + return action == "advance" || action == "replace" || action == "restore"; + } + var Navigator = class { + constructor(delegate) { + this.delegate = delegate; + } + proposeVisit(location2, options = {}) { + if (this.delegate.allowsVisitingLocationWithAction(location2, options.action)) { + if (locationIsVisitable(location2, this.view.snapshot.rootLocation)) { + this.delegate.visitProposedToLocation(location2, options); + } else { + window.location.href = location2.toString(); + } + } + } + startVisit(locatable, restorationIdentifier, options = {}) { + this.stop(); + this.currentVisit = new Visit(this, expandURL(locatable), restorationIdentifier, Object.assign({ referrer: this.location }, options)); + this.currentVisit.start(); + } + submitForm(form, submitter) { + this.stop(); + this.formSubmission = new FormSubmission(this, form, submitter, true); + this.formSubmission.start(); + } + stop() { + if (this.formSubmission) { + this.formSubmission.stop(); + delete this.formSubmission; + } + if (this.currentVisit) { + this.currentVisit.cancel(); + delete this.currentVisit; + } + } + get adapter() { + return this.delegate.adapter; + } + get view() { + return this.delegate.view; + } + get history() { + return this.delegate.history; + } + formSubmissionStarted(formSubmission) { + if (typeof this.adapter.formSubmissionStarted === "function") { + this.adapter.formSubmissionStarted(formSubmission); + } + } + async formSubmissionSucceededWithResponse(formSubmission, fetchResponse) { + if (formSubmission == this.formSubmission) { + const responseHTML = await fetchResponse.responseHTML; + if (responseHTML) { + if (formSubmission.method != FetchMethod.get) { + this.view.clearSnapshotCache(); + } + const { statusCode, redirected } = fetchResponse; + const action = this.getActionForFormSubmission(formSubmission); + const visitOptions = { action, response: { statusCode, responseHTML, redirected } }; + this.proposeVisit(fetchResponse.location, visitOptions); + } + } + } + async formSubmissionFailedWithResponse(formSubmission, fetchResponse) { + const responseHTML = await fetchResponse.responseHTML; + if (responseHTML) { + const snapshot = PageSnapshot.fromHTMLString(responseHTML); + if (fetchResponse.serverError) { + await this.view.renderError(snapshot); + } else { + await this.view.renderPage(snapshot); + } + this.view.scrollToTop(); + this.view.clearSnapshotCache(); + } + } + formSubmissionErrored(formSubmission, error2) { + console.error(error2); + } + formSubmissionFinished(formSubmission) { + if (typeof this.adapter.formSubmissionFinished === "function") { + this.adapter.formSubmissionFinished(formSubmission); + } + } + visitStarted(visit2) { + this.delegate.visitStarted(visit2); + } + visitCompleted(visit2) { + this.delegate.visitCompleted(visit2); + } + locationWithActionIsSamePage(location2, action) { + const anchor = getAnchor(location2); + const currentAnchor = getAnchor(this.view.lastRenderedLocation); + const isRestorationToTop = action === "restore" && typeof anchor === "undefined"; + return action !== "replace" && getRequestURL(location2) === getRequestURL(this.view.lastRenderedLocation) && (isRestorationToTop || anchor != null && anchor !== currentAnchor); + } + visitScrolledToSamePageLocation(oldURL, newURL) { + this.delegate.visitScrolledToSamePageLocation(oldURL, newURL); + } + get location() { + return this.history.location; + } + get restorationIdentifier() { + return this.history.restorationIdentifier; + } + getActionForFormSubmission(formSubmission) { + const { formElement, submitter } = formSubmission; + const action = getAttribute("data-turbo-action", submitter, formElement); + return isAction(action) ? action : "advance"; + } + }; + var PageStage; + (function(PageStage2) { + PageStage2[PageStage2["initial"] = 0] = "initial"; + PageStage2[PageStage2["loading"] = 1] = "loading"; + PageStage2[PageStage2["interactive"] = 2] = "interactive"; + PageStage2[PageStage2["complete"] = 3] = "complete"; + })(PageStage || (PageStage = {})); + var PageObserver = class { + constructor(delegate) { + this.stage = PageStage.initial; + this.started = false; + this.interpretReadyState = () => { + const { readyState } = this; + if (readyState == "interactive") { + this.pageIsInteractive(); + } else if (readyState == "complete") { + this.pageIsComplete(); + } + }; + this.pageWillUnload = () => { + this.delegate.pageWillUnload(); + }; + this.delegate = delegate; + } + start() { + if (!this.started) { + if (this.stage == PageStage.initial) { + this.stage = PageStage.loading; + } + document.addEventListener("readystatechange", this.interpretReadyState, false); + addEventListener("pagehide", this.pageWillUnload, false); + this.started = true; + } + } + stop() { + if (this.started) { + document.removeEventListener("readystatechange", this.interpretReadyState, false); + removeEventListener("pagehide", this.pageWillUnload, false); + this.started = false; + } + } + pageIsInteractive() { + if (this.stage == PageStage.loading) { + this.stage = PageStage.interactive; + this.delegate.pageBecameInteractive(); + } + } + pageIsComplete() { + this.pageIsInteractive(); + if (this.stage == PageStage.interactive) { + this.stage = PageStage.complete; + this.delegate.pageLoaded(); + } + } + get readyState() { + return document.readyState; + } + }; + var ScrollObserver = class { + constructor(delegate) { + this.started = false; + this.onScroll = () => { + this.updatePosition({ x: window.pageXOffset, y: window.pageYOffset }); + }; + this.delegate = delegate; + } + start() { + if (!this.started) { + addEventListener("scroll", this.onScroll, false); + this.onScroll(); + this.started = true; + } + } + stop() { + if (this.started) { + removeEventListener("scroll", this.onScroll, false); + this.started = false; + } + } + updatePosition(position) { + this.delegate.scrollPositionChanged(position); + } + }; + var StreamObserver = class { + constructor(delegate) { + this.sources = /* @__PURE__ */ new Set(); + this.started = false; + this.inspectFetchResponse = (event) => { + const response = fetchResponseFromEvent(event); + if (response && fetchResponseIsStream(response)) { + event.preventDefault(); + this.receiveMessageResponse(response); + } + }; + this.receiveMessageEvent = (event) => { + if (this.started && typeof event.data == "string") { + this.receiveMessageHTML(event.data); + } + }; + this.delegate = delegate; + } + start() { + if (!this.started) { + this.started = true; + addEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false); + } + } + stop() { + if (this.started) { + this.started = false; + removeEventListener("turbo:before-fetch-response", this.inspectFetchResponse, false); + } + } + connectStreamSource(source) { + if (!this.streamSourceIsConnected(source)) { + this.sources.add(source); + source.addEventListener("message", this.receiveMessageEvent, false); + } + } + disconnectStreamSource(source) { + if (this.streamSourceIsConnected(source)) { + this.sources.delete(source); + source.removeEventListener("message", this.receiveMessageEvent, false); + } + } + streamSourceIsConnected(source) { + return this.sources.has(source); + } + async receiveMessageResponse(response) { + const html = await response.responseHTML; + if (html) { + this.receiveMessageHTML(html); + } + } + receiveMessageHTML(html) { + this.delegate.receivedMessageFromStream(new StreamMessage(html)); + } + }; + function fetchResponseFromEvent(event) { + var _a; + const fetchResponse = (_a = event.detail) === null || _a === void 0 ? void 0 : _a.fetchResponse; + if (fetchResponse instanceof FetchResponse) { + return fetchResponse; + } + } + function fetchResponseIsStream(response) { + var _a; + const contentType = (_a = response.contentType) !== null && _a !== void 0 ? _a : ""; + return contentType.startsWith(StreamMessage.contentType); + } + var ErrorRenderer = class extends Renderer { + async render() { + this.replaceHeadAndBody(); + this.activateScriptElements(); + } + replaceHeadAndBody() { + const { documentElement, head, body } = document; + documentElement.replaceChild(this.newHead, head); + documentElement.replaceChild(this.newElement, body); + } + activateScriptElements() { + for (const replaceableElement of this.scriptElements) { + const parentNode = replaceableElement.parentNode; + if (parentNode) { + const element = this.createScriptElement(replaceableElement); + parentNode.replaceChild(element, replaceableElement); + } + } + } + get newHead() { + return this.newSnapshot.headSnapshot.element; + } + get scriptElements() { + return [...document.documentElement.querySelectorAll("script")]; + } + }; + var PageRenderer = class extends Renderer { + get shouldRender() { + return this.newSnapshot.isVisitable && this.trackedElementsAreIdentical; + } + prepareToRender() { + this.mergeHead(); + } + async render() { + if (this.willRender) { + this.replaceBody(); + } + } + finishRendering() { + super.finishRendering(); + if (!this.isPreview) { + this.focusFirstAutofocusableElement(); + } + } + get currentHeadSnapshot() { + return this.currentSnapshot.headSnapshot; + } + get newHeadSnapshot() { + return this.newSnapshot.headSnapshot; + } + get newElement() { + return this.newSnapshot.element; + } + mergeHead() { + this.copyNewHeadStylesheetElements(); + this.copyNewHeadScriptElements(); + this.removeCurrentHeadProvisionalElements(); + this.copyNewHeadProvisionalElements(); + } + replaceBody() { + this.preservingPermanentElements(() => { + this.activateNewBody(); + this.assignNewBody(); + }); + } + get trackedElementsAreIdentical() { + return this.currentHeadSnapshot.trackedElementSignature == this.newHeadSnapshot.trackedElementSignature; + } + copyNewHeadStylesheetElements() { + for (const element of this.newHeadStylesheetElements) { + document.head.appendChild(element); + } + } + copyNewHeadScriptElements() { + for (const element of this.newHeadScriptElements) { + document.head.appendChild(this.createScriptElement(element)); + } + } + removeCurrentHeadProvisionalElements() { + for (const element of this.currentHeadProvisionalElements) { + document.head.removeChild(element); + } + } + copyNewHeadProvisionalElements() { + for (const element of this.newHeadProvisionalElements) { + document.head.appendChild(element); + } + } + activateNewBody() { + document.adoptNode(this.newElement); + this.activateNewBodyScriptElements(); + } + activateNewBodyScriptElements() { + for (const inertScriptElement of this.newBodyScriptElements) { + const activatedScriptElement = this.createScriptElement(inertScriptElement); + inertScriptElement.replaceWith(activatedScriptElement); + } + } + assignNewBody() { + if (document.body && this.newElement instanceof HTMLBodyElement) { + document.body.replaceWith(this.newElement); + } else { + document.documentElement.appendChild(this.newElement); + } + } + get newHeadStylesheetElements() { + return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot); + } + get newHeadScriptElements() { + return this.newHeadSnapshot.getScriptElementsNotInSnapshot(this.currentHeadSnapshot); + } + get currentHeadProvisionalElements() { + return this.currentHeadSnapshot.provisionalElements; + } + get newHeadProvisionalElements() { + return this.newHeadSnapshot.provisionalElements; + } + get newBodyScriptElements() { + return this.newElement.querySelectorAll("script"); + } + }; + var SnapshotCache = class { + constructor(size) { + this.keys = []; + this.snapshots = {}; + this.size = size; + } + has(location2) { + return toCacheKey(location2) in this.snapshots; + } + get(location2) { + if (this.has(location2)) { + const snapshot = this.read(location2); + this.touch(location2); + return snapshot; + } + } + put(location2, snapshot) { + this.write(location2, snapshot); + this.touch(location2); + return snapshot; + } + clear() { + this.snapshots = {}; + } + read(location2) { + return this.snapshots[toCacheKey(location2)]; + } + write(location2, snapshot) { + this.snapshots[toCacheKey(location2)] = snapshot; + } + touch(location2) { + const key = toCacheKey(location2); + const index = this.keys.indexOf(key); + if (index > -1) + this.keys.splice(index, 1); + this.keys.unshift(key); + this.trim(); + } + trim() { + for (const key of this.keys.splice(this.size)) { + delete this.snapshots[key]; + } + } + }; + var PageView = class extends View { + constructor() { + super(...arguments); + this.snapshotCache = new SnapshotCache(10); + this.lastRenderedLocation = new URL(location.href); + } + renderPage(snapshot, isPreview = false, willRender = true) { + const renderer = new PageRenderer(this.snapshot, snapshot, isPreview, willRender); + return this.render(renderer); + } + renderError(snapshot) { + const renderer = new ErrorRenderer(this.snapshot, snapshot, false); + return this.render(renderer); + } + clearSnapshotCache() { + this.snapshotCache.clear(); + } + async cacheSnapshot() { + if (this.shouldCacheSnapshot) { + this.delegate.viewWillCacheSnapshot(); + const { snapshot, lastRenderedLocation: location2 } = this; + await nextEventLoopTick(); + const cachedSnapshot = snapshot.clone(); + this.snapshotCache.put(location2, cachedSnapshot); + return cachedSnapshot; + } + } + getCachedSnapshotForLocation(location2) { + return this.snapshotCache.get(location2); + } + get snapshot() { + return PageSnapshot.fromElement(this.element); + } + get shouldCacheSnapshot() { + return this.snapshot.isCacheable; + } + }; + var Session = class { + constructor() { + this.navigator = new Navigator(this); + this.history = new History(this); + this.view = new PageView(this, document.documentElement); + this.adapter = new BrowserAdapter(this); + this.pageObserver = new PageObserver(this); + this.cacheObserver = new CacheObserver(); + this.linkClickObserver = new LinkClickObserver(this); + this.formSubmitObserver = new FormSubmitObserver(this); + this.scrollObserver = new ScrollObserver(this); + this.streamObserver = new StreamObserver(this); + this.frameRedirector = new FrameRedirector(document.documentElement); + this.drive = true; + this.enabled = true; + this.progressBarDelay = 500; + this.started = false; + } + start() { + if (!this.started) { + this.pageObserver.start(); + this.cacheObserver.start(); + this.linkClickObserver.start(); + this.formSubmitObserver.start(); + this.scrollObserver.start(); + this.streamObserver.start(); + this.frameRedirector.start(); + this.history.start(); + this.started = true; + this.enabled = true; + } + } + disable() { + this.enabled = false; + } + stop() { + if (this.started) { + this.pageObserver.stop(); + this.cacheObserver.stop(); + this.linkClickObserver.stop(); + this.formSubmitObserver.stop(); + this.scrollObserver.stop(); + this.streamObserver.stop(); + this.frameRedirector.stop(); + this.history.stop(); + this.started = false; + } + } + registerAdapter(adapter) { + this.adapter = adapter; + } + visit(location2, options = {}) { + this.navigator.proposeVisit(expandURL(location2), options); + } + connectStreamSource(source) { + this.streamObserver.connectStreamSource(source); + } + disconnectStreamSource(source) { + this.streamObserver.disconnectStreamSource(source); + } + renderStreamMessage(message) { + document.documentElement.appendChild(StreamMessage.wrap(message).fragment); + } + clearCache() { + this.view.clearSnapshotCache(); + } + setProgressBarDelay(delay) { + this.progressBarDelay = delay; + } + get location() { + return this.history.location; + } + get restorationIdentifier() { + return this.history.restorationIdentifier; + } + historyPoppedToLocationWithRestorationIdentifier(location2, restorationIdentifier) { + if (this.enabled) { + this.navigator.startVisit(location2, restorationIdentifier, { action: "restore", historyChanged: true }); + } else { + this.adapter.pageInvalidated(); + } + } + scrollPositionChanged(position) { + this.history.updateRestorationData({ scrollPosition: position }); + } + willFollowLinkToLocation(link, location2) { + return this.elementDriveEnabled(link) && locationIsVisitable(location2, this.snapshot.rootLocation) && this.applicationAllowsFollowingLinkToLocation(link, location2); + } + followedLinkToLocation(link, location2) { + const action = this.getActionForLink(link); + this.convertLinkWithMethodClickToFormSubmission(link) || this.visit(location2.href, { action }); + } + convertLinkWithMethodClickToFormSubmission(link) { + const linkMethod = link.getAttribute("data-turbo-method"); + if (linkMethod) { + const form = document.createElement("form"); + form.method = linkMethod; + form.action = link.getAttribute("href") || "undefined"; + form.hidden = true; + if (link.hasAttribute("data-turbo-confirm")) { + form.setAttribute("data-turbo-confirm", link.getAttribute("data-turbo-confirm")); + } + const frame = this.getTargetFrameForLink(link); + if (frame) { + form.setAttribute("data-turbo-frame", frame); + form.addEventListener("turbo:submit-start", () => form.remove()); + } else { + form.addEventListener("submit", () => form.remove()); + } + document.body.appendChild(form); + return dispatch("submit", { cancelable: true, target: form }); + } else { + return false; + } + } + allowsVisitingLocationWithAction(location2, action) { + return this.locationWithActionIsSamePage(location2, action) || this.applicationAllowsVisitingLocation(location2); + } + visitProposedToLocation(location2, options) { + extendURLWithDeprecatedProperties(location2); + this.adapter.visitProposedToLocation(location2, options); + } + visitStarted(visit2) { + extendURLWithDeprecatedProperties(visit2.location); + if (!visit2.silent) { + this.notifyApplicationAfterVisitingLocation(visit2.location, visit2.action); + } + } + visitCompleted(visit2) { + this.notifyApplicationAfterPageLoad(visit2.getTimingMetrics()); + } + locationWithActionIsSamePage(location2, action) { + return this.navigator.locationWithActionIsSamePage(location2, action); + } + visitScrolledToSamePageLocation(oldURL, newURL) { + this.notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL); + } + willSubmitForm(form, submitter) { + const action = getAction(form, submitter); + return this.elementDriveEnabled(form) && (!submitter || this.elementDriveEnabled(submitter)) && locationIsVisitable(expandURL(action), this.snapshot.rootLocation); + } + formSubmitted(form, submitter) { + this.navigator.submitForm(form, submitter); + } + pageBecameInteractive() { + this.view.lastRenderedLocation = this.location; + this.notifyApplicationAfterPageLoad(); + } + pageLoaded() { + this.history.assumeControlOfScrollRestoration(); + } + pageWillUnload() { + this.history.relinquishControlOfScrollRestoration(); + } + receivedMessageFromStream(message) { + this.renderStreamMessage(message); + } + viewWillCacheSnapshot() { + var _a; + if (!((_a = this.navigator.currentVisit) === null || _a === void 0 ? void 0 : _a.silent)) { + this.notifyApplicationBeforeCachingSnapshot(); + } + } + allowsImmediateRender({ element }, resume) { + const event = this.notifyApplicationBeforeRender(element, resume); + return !event.defaultPrevented; + } + viewRenderedSnapshot(snapshot, isPreview) { + this.view.lastRenderedLocation = this.history.location; + this.notifyApplicationAfterRender(); + } + viewInvalidated() { + this.adapter.pageInvalidated(); + } + frameLoaded(frame) { + this.notifyApplicationAfterFrameLoad(frame); + } + frameRendered(fetchResponse, frame) { + this.notifyApplicationAfterFrameRender(fetchResponse, frame); + } + applicationAllowsFollowingLinkToLocation(link, location2) { + const event = this.notifyApplicationAfterClickingLinkToLocation(link, location2); + return !event.defaultPrevented; + } + applicationAllowsVisitingLocation(location2) { + const event = this.notifyApplicationBeforeVisitingLocation(location2); + return !event.defaultPrevented; + } + notifyApplicationAfterClickingLinkToLocation(link, location2) { + return dispatch("turbo:click", { target: link, detail: { url: location2.href }, cancelable: true }); + } + notifyApplicationBeforeVisitingLocation(location2) { + return dispatch("turbo:before-visit", { detail: { url: location2.href }, cancelable: true }); + } + notifyApplicationAfterVisitingLocation(location2, action) { + markAsBusy(document.documentElement); + return dispatch("turbo:visit", { detail: { url: location2.href, action } }); + } + notifyApplicationBeforeCachingSnapshot() { + return dispatch("turbo:before-cache"); + } + notifyApplicationBeforeRender(newBody, resume) { + return dispatch("turbo:before-render", { detail: { newBody, resume }, cancelable: true }); + } + notifyApplicationAfterRender() { + return dispatch("turbo:render"); + } + notifyApplicationAfterPageLoad(timing = {}) { + clearBusyState(document.documentElement); + return dispatch("turbo:load", { detail: { url: this.location.href, timing } }); + } + notifyApplicationAfterVisitingSamePageLocation(oldURL, newURL) { + dispatchEvent(new HashChangeEvent("hashchange", { oldURL: oldURL.toString(), newURL: newURL.toString() })); + } + notifyApplicationAfterFrameLoad(frame) { + return dispatch("turbo:frame-load", { target: frame }); + } + notifyApplicationAfterFrameRender(fetchResponse, frame) { + return dispatch("turbo:frame-render", { detail: { fetchResponse }, target: frame, cancelable: true }); + } + elementDriveEnabled(element) { + const container = element === null || element === void 0 ? void 0 : element.closest("[data-turbo]"); + if (this.drive) { + if (container) { + return container.getAttribute("data-turbo") != "false"; + } else { + return true; + } + } else { + if (container) { + return container.getAttribute("data-turbo") == "true"; + } else { + return false; + } + } + } + getActionForLink(link) { + const action = link.getAttribute("data-turbo-action"); + return isAction(action) ? action : "advance"; + } + getTargetFrameForLink(link) { + const frame = link.getAttribute("data-turbo-frame"); + if (frame) { + return frame; + } else { + const container = link.closest("turbo-frame"); + if (container) { + return container.id; + } + } + } + get snapshot() { + return this.view.snapshot; + } + }; + function extendURLWithDeprecatedProperties(url) { + Object.defineProperties(url, deprecatedLocationPropertyDescriptors); + } + var deprecatedLocationPropertyDescriptors = { + absoluteURL: { + get() { + return this.toString(); + } + } + }; + var session = new Session(); + var { navigator: navigator$1 } = session; + function start() { + session.start(); + } + function registerAdapter(adapter) { + session.registerAdapter(adapter); + } + function visit(location2, options) { + session.visit(location2, options); + } + function connectStreamSource(source) { + session.connectStreamSource(source); + } + function disconnectStreamSource(source) { + session.disconnectStreamSource(source); + } + function renderStreamMessage(message) { + session.renderStreamMessage(message); + } + function clearCache() { + session.clearCache(); + } + function setProgressBarDelay(delay) { + session.setProgressBarDelay(delay); + } + function setConfirmMethod(confirmMethod) { + FormSubmission.confirmMethod = confirmMethod; + } + var Turbo = /* @__PURE__ */ Object.freeze({ + __proto__: null, + navigator: navigator$1, + session, + PageRenderer, + PageSnapshot, + start, + registerAdapter, + visit, + connectStreamSource, + disconnectStreamSource, + renderStreamMessage, + clearCache, + setProgressBarDelay, + setConfirmMethod + }); + var FrameController = class { + constructor(element) { + this.fetchResponseLoaded = (fetchResponse) => { + }; + this.currentFetchRequest = null; + this.resolveVisitPromise = () => { + }; + this.connected = false; + this.hasBeenLoaded = false; + this.settingSourceURL = false; + this.element = element; + this.view = new FrameView(this, this.element); + this.appearanceObserver = new AppearanceObserver(this, this.element); + this.linkInterceptor = new LinkInterceptor(this, this.element); + this.formInterceptor = new FormInterceptor(this, this.element); + } + connect() { + if (!this.connected) { + this.connected = true; + this.reloadable = false; + if (this.loadingStyle == FrameLoadingStyle.lazy) { + this.appearanceObserver.start(); + } + this.linkInterceptor.start(); + this.formInterceptor.start(); + this.sourceURLChanged(); + } + } + disconnect() { + if (this.connected) { + this.connected = false; + this.appearanceObserver.stop(); + this.linkInterceptor.stop(); + this.formInterceptor.stop(); + } + } + disabledChanged() { + if (this.loadingStyle == FrameLoadingStyle.eager) { + this.loadSourceURL(); + } + } + sourceURLChanged() { + if (this.loadingStyle == FrameLoadingStyle.eager || this.hasBeenLoaded) { + this.loadSourceURL(); + } + } + loadingStyleChanged() { + if (this.loadingStyle == FrameLoadingStyle.lazy) { + this.appearanceObserver.start(); + } else { + this.appearanceObserver.stop(); + this.loadSourceURL(); + } + } + async loadSourceURL() { + if (!this.settingSourceURL && this.enabled && this.isActive && (this.reloadable || this.sourceURL != this.currentURL)) { + const previousURL = this.currentURL; + this.currentURL = this.sourceURL; + if (this.sourceURL) { + try { + this.element.loaded = this.visit(expandURL(this.sourceURL)); + this.appearanceObserver.stop(); + await this.element.loaded; + this.hasBeenLoaded = true; + } catch (error2) { + this.currentURL = previousURL; + throw error2; + } + } + } + } + async loadResponse(fetchResponse) { + if (fetchResponse.redirected || fetchResponse.succeeded && fetchResponse.isHTML) { + this.sourceURL = fetchResponse.response.url; + } + try { + const html = await fetchResponse.responseHTML; + if (html) { + const { body } = parseHTMLDocument(html); + const snapshot = new Snapshot(await this.extractForeignFrameElement(body)); + const renderer = new FrameRenderer(this.view.snapshot, snapshot, false, false); + if (this.view.renderPromise) + await this.view.renderPromise; + await this.view.render(renderer); + session.frameRendered(fetchResponse, this.element); + session.frameLoaded(this.element); + this.fetchResponseLoaded(fetchResponse); + } + } catch (error2) { + console.error(error2); + this.view.invalidate(); + } finally { + this.fetchResponseLoaded = () => { + }; + } + } + elementAppearedInViewport(element) { + this.loadSourceURL(); + } + shouldInterceptLinkClick(element, url) { + if (element.hasAttribute("data-turbo-method")) { + return false; + } else { + return this.shouldInterceptNavigation(element); + } + } + linkClickIntercepted(element, url) { + this.reloadable = true; + this.navigateFrame(element, url); + } + shouldInterceptFormSubmission(element, submitter) { + return this.shouldInterceptNavigation(element, submitter); + } + formSubmissionIntercepted(element, submitter) { + if (this.formSubmission) { + this.formSubmission.stop(); + } + this.reloadable = false; + this.formSubmission = new FormSubmission(this, element, submitter); + const { fetchRequest } = this.formSubmission; + this.prepareHeadersForRequest(fetchRequest.headers, fetchRequest); + this.formSubmission.start(); + } + prepareHeadersForRequest(headers, request) { + headers["Turbo-Frame"] = this.id; + } + requestStarted(request) { + markAsBusy(this.element); + } + requestPreventedHandlingResponse(request, response) { + this.resolveVisitPromise(); + } + async requestSucceededWithResponse(request, response) { + await this.loadResponse(response); + this.resolveVisitPromise(); + } + requestFailedWithResponse(request, response) { + console.error(response); + this.resolveVisitPromise(); + } + requestErrored(request, error2) { + console.error(error2); + this.resolveVisitPromise(); + } + requestFinished(request) { + clearBusyState(this.element); + } + formSubmissionStarted({ formElement }) { + markAsBusy(formElement, this.findFrameElement(formElement)); + } + formSubmissionSucceededWithResponse(formSubmission, response) { + const frame = this.findFrameElement(formSubmission.formElement, formSubmission.submitter); + this.proposeVisitIfNavigatedWithAction(frame, formSubmission.formElement, formSubmission.submitter); + frame.delegate.loadResponse(response); + } + formSubmissionFailedWithResponse(formSubmission, fetchResponse) { + this.element.delegate.loadResponse(fetchResponse); + } + formSubmissionErrored(formSubmission, error2) { + console.error(error2); + } + formSubmissionFinished({ formElement }) { + clearBusyState(formElement, this.findFrameElement(formElement)); + } + allowsImmediateRender(snapshot, resume) { + return true; + } + viewRenderedSnapshot(snapshot, isPreview) { + } + viewInvalidated() { + } + async visit(url) { + var _a; + const request = new FetchRequest(this, FetchMethod.get, url, new URLSearchParams(), this.element); + (_a = this.currentFetchRequest) === null || _a === void 0 ? void 0 : _a.cancel(); + this.currentFetchRequest = request; + return new Promise((resolve) => { + this.resolveVisitPromise = () => { + this.resolveVisitPromise = () => { + }; + this.currentFetchRequest = null; + resolve(); + }; + request.perform(); + }); + } + navigateFrame(element, url, submitter) { + const frame = this.findFrameElement(element, submitter); + this.proposeVisitIfNavigatedWithAction(frame, element, submitter); + frame.setAttribute("reloadable", ""); + frame.src = url; + } + proposeVisitIfNavigatedWithAction(frame, element, submitter) { + const action = getAttribute("data-turbo-action", submitter, element, frame); + if (isAction(action)) { + const { visitCachedSnapshot } = new SnapshotSubstitution(frame); + frame.delegate.fetchResponseLoaded = (fetchResponse) => { + if (frame.src) { + const { statusCode, redirected } = fetchResponse; + const responseHTML = frame.ownerDocument.documentElement.outerHTML; + const response = { statusCode, redirected, responseHTML }; + session.visit(frame.src, { action, response, visitCachedSnapshot, willRender: false }); + } + }; + } + } + findFrameElement(element, submitter) { + var _a; + const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target"); + return (_a = getFrameElementById(id)) !== null && _a !== void 0 ? _a : this.element; + } + async extractForeignFrameElement(container) { + let element; + const id = CSS.escape(this.id); + try { + if (element = activateElement(container.querySelector(`turbo-frame#${id}`), this.currentURL)) { + return element; + } + if (element = activateElement(container.querySelector(`turbo-frame[src][recurse~=${id}]`), this.currentURL)) { + await element.loaded; + return await this.extractForeignFrameElement(element); + } + console.error(`Response has no matching element`); + } catch (error2) { + console.error(error2); + } + return new FrameElement(); + } + formActionIsVisitable(form, submitter) { + const action = getAction(form, submitter); + return locationIsVisitable(expandURL(action), this.rootLocation); + } + shouldInterceptNavigation(element, submitter) { + const id = getAttribute("data-turbo-frame", submitter, element) || this.element.getAttribute("target"); + if (element instanceof HTMLFormElement && !this.formActionIsVisitable(element, submitter)) { + return false; + } + if (!this.enabled || id == "_top") { + return false; + } + if (id) { + const frameElement = getFrameElementById(id); + if (frameElement) { + return !frameElement.disabled; + } + } + if (!session.elementDriveEnabled(element)) { + return false; + } + if (submitter && !session.elementDriveEnabled(submitter)) { + return false; + } + return true; + } + get id() { + return this.element.id; + } + get enabled() { + return !this.element.disabled; + } + get sourceURL() { + if (this.element.src) { + return this.element.src; + } + } + get reloadable() { + const frame = this.findFrameElement(this.element); + return frame.hasAttribute("reloadable"); + } + set reloadable(value) { + const frame = this.findFrameElement(this.element); + if (value) { + frame.setAttribute("reloadable", ""); + } else { + frame.removeAttribute("reloadable"); + } + } + set sourceURL(sourceURL) { + this.settingSourceURL = true; + this.element.src = sourceURL !== null && sourceURL !== void 0 ? sourceURL : null; + this.currentURL = this.element.src; + this.settingSourceURL = false; + } + get loadingStyle() { + return this.element.loading; + } + get isLoading() { + return this.formSubmission !== void 0 || this.resolveVisitPromise() !== void 0; + } + get isActive() { + return this.element.isActive && this.connected; + } + get rootLocation() { + var _a; + const meta = this.element.ownerDocument.querySelector(`meta[name="turbo-root"]`); + const root = (_a = meta === null || meta === void 0 ? void 0 : meta.content) !== null && _a !== void 0 ? _a : "/"; + return expandURL(root); + } + }; + var SnapshotSubstitution = class { + constructor(element) { + this.visitCachedSnapshot = ({ element: element2 }) => { + var _a; + const { id, clone } = this; + (_a = element2.querySelector("#" + id)) === null || _a === void 0 ? void 0 : _a.replaceWith(clone); + }; + this.clone = element.cloneNode(true); + this.id = element.id; + } + }; + function getFrameElementById(id) { + if (id != null) { + const element = document.getElementById(id); + if (element instanceof FrameElement) { + return element; + } + } + } + function activateElement(element, currentURL) { + if (element) { + const src = element.getAttribute("src"); + if (src != null && currentURL != null && urlsAreEqual(src, currentURL)) { + throw new Error(`Matching element has a source URL which references itself`); + } + if (element.ownerDocument !== document) { + element = document.importNode(element, true); + } + if (element instanceof FrameElement) { + element.connectedCallback(); + element.disconnectedCallback(); + return element; + } + } + } + var StreamActions = { + after() { + this.targetElements.forEach((e) => { + var _a; + return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e.nextSibling); + }); + }, + append() { + this.removeDuplicateTargetChildren(); + this.targetElements.forEach((e) => e.append(this.templateContent)); + }, + before() { + this.targetElements.forEach((e) => { + var _a; + return (_a = e.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(this.templateContent, e); + }); + }, + prepend() { + this.removeDuplicateTargetChildren(); + this.targetElements.forEach((e) => e.prepend(this.templateContent)); + }, + remove() { + this.targetElements.forEach((e) => e.remove()); + }, + replace() { + this.targetElements.forEach((e) => e.replaceWith(this.templateContent)); + }, + update() { + this.targetElements.forEach((e) => { + e.innerHTML = ""; + e.append(this.templateContent); + }); + } + }; + var StreamElement = class extends HTMLElement { + async connectedCallback() { + try { + await this.render(); + } catch (error2) { + console.error(error2); + } finally { + this.disconnect(); + } + } + async render() { + var _a; + return (_a = this.renderPromise) !== null && _a !== void 0 ? _a : this.renderPromise = (async () => { + if (this.dispatchEvent(this.beforeRenderEvent)) { + await nextAnimationFrame(); + this.performAction(); + } + })(); + } + disconnect() { + try { + this.remove(); + } catch (_a) { + } + } + removeDuplicateTargetChildren() { + this.duplicateChildren.forEach((c) => c.remove()); + } + get duplicateChildren() { + var _a; + const existingChildren = this.targetElements.flatMap((e) => [...e.children]).filter((c) => !!c.id); + const newChildrenIds = [...(_a = this.templateContent) === null || _a === void 0 ? void 0 : _a.children].filter((c) => !!c.id).map((c) => c.id); + return existingChildren.filter((c) => newChildrenIds.includes(c.id)); + } + get performAction() { + if (this.action) { + const actionFunction = StreamActions[this.action]; + if (actionFunction) { + return actionFunction; + } + this.raise("unknown action"); + } + this.raise("action attribute is missing"); + } + get targetElements() { + if (this.target) { + return this.targetElementsById; + } else if (this.targets) { + return this.targetElementsByQuery; + } else { + this.raise("target or targets attribute is missing"); + } + } + get templateContent() { + return this.templateElement.content.cloneNode(true); + } + get templateElement() { + if (this.firstElementChild instanceof HTMLTemplateElement) { + return this.firstElementChild; + } + this.raise("first child element must be a