@lumiastream/ui 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +344 -15
- package/dist/index.js +3098 -179
- package/package.json +2 -1
package/dist/index.js
CHANGED
|
@@ -21,29 +21,57 @@ function styleInject(css, { insertAt } = {}) {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// src/lumia-ui.css
|
|
24
|
-
styleInject(".ls-button,\n.ls-button *,\n.ls-color-picker,\n.ls-color-picker *,\n.mui-multi-select,\n.mui-multi-select *,\n.ls-multi-select-value,\n.ls-multi-select-value *,\n.ls-variable-picker,\n.ls-variable-picker *,\n.ls-variable-token,\n.ls-variable-token *,\n.ls-font-picker,\n.ls-font-picker *,\n.mui-ls-input,\n.mui-ls-input * {\n box-sizing: border-box;\n}\n.ls-button,\n.ls-color-picker button,\n.mui-multi-select button {\n font: inherit;\n letter-spacing: inherit;\n color: inherit;\n margin: 0;\n}\n.ls-button,\n.ls-color-picker__preview {\n appearance: none;\n -webkit-appearance: none;\n background-color: transparent;\n background-image: none;\n cursor: pointer;\n text-transform: none;\n user-select: none;\n}\n.ls-button {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 0.5rem;\n border-radius: var(--radiusContainerSm, 0.375rem);\n border: 1px solid color-mix(in srgb, #fff 10%, transparent);\n color: var(--neutralLight1, #f4f3ff);\n font-weight: 500;\n box-shadow: 0 8px 18px rgba(0, 0, 0, 0.18);\n transition:\n filter 150ms cubic-bezier(0.4, 0, 0.2, 1),\n opacity 150ms cubic-bezier(0.4, 0, 0.2, 1),\n box-shadow 150ms cubic-bezier(0.4, 0, 0.2, 1);\n white-space: nowrap;\n}\n.ls-button--small {\n padding-inline: 0.75rem;\n padding-block: 0.25rem;\n font-size: 0.875rem;\n line-height: 1.25rem;\n}\n.ls-button--medium {\n padding-inline: 1rem;\n padding-block: 0.5rem;\n font-size: 1rem;\n line-height: 1.5rem;\n}\n.ls-button--large {\n padding-inline: 1.5rem;\n padding-block: 0.75rem;\n font-size: 1.125rem;\n line-height: 1.75rem;\n}\n.ls-button:hover {\n filter: brightness(1.1);\n}\n.ls-button:focus {\n outline: none;\n}\n.ls-button:focus-visible {\n box-shadow:\n 0 0 0 2px var(--primary, #ff4076),\n 0 0 0 4px var(--neutralDark1, #1b1a28),\n 0 8px 18px rgba(0, 0, 0, 0.18);\n}\n.ls-button:active {\n filter: brightness(0.95);\n}\n.ls-button:disabled,\n.ls-button[aria-disabled=true] {\n cursor: not-allowed;\n opacity: 0.5;\n}\n.ls-button:disabled:hover,\n.ls-button[aria-disabled=true]:hover {\n filter: none;\n}\n.mui-ls-input,\n.ls-font-picker,\n.ls-color-picker__input {\n width: 100%;\n}\n.mui-multi-select .MuiSelect-select {\n min-width: 0;\n}\n.ls-multi-select-value {\n display: flex;\n width: 100%;\n min-width: 0;\n flex-wrap: nowrap;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n overflow: hidden;\n white-space: nowrap;\n}\n.ls-multi-select-value__label {\n min-width: 0;\n flex: 1 1 0%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ls-multi-select-value__count {\n flex-shrink: 0;\n white-space: nowrap;\n}\n.ls-color-picker__preview {\n position: relative;\n display: inline-block;\n width: 1.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n padding: 0;\n border: 1px solid color-mix(in srgb, #fff 25%, transparent);\n border-radius: var(--radiusContainerSm, 0.375rem);\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);\n color: transparent;\n line-height: 0;\n}\n.ls-color-picker__preview:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n.ls-color-picker__preview:focus {\n outline: none;\n}\n.ls-color-picker__preview:focus-visible {\n box-shadow:\n 0 0 0 2px var(--primary, #ff4076),\n 0 0 0 4px var(--neutralDark1, #1b1a28),\n 0 0 0 1px rgba(0, 0, 0, 0.25);\n}\n.ls-color-picker__gradient circle,\n.ls-color-picker__gradient polyline {\n stroke: #fff;\n}\n.ls-variable-picker {\n --variable-custom-color: var(--customVariables, #69ffd2);\n --variable-function-color: var(--functionVariables, var(--semanticPurple, #b489ff));\n --variable-normal-color: var(--normalVariables, var(--semanticBlue, #65b8ff));\n display: flex;\n width: 92vw;\n max-width: 1100px;\n min-height: 50vh;\n max-height: 55vh;\n flex-direction: column;\n overflow: hidden;\n}\n.ls-variable-picker__intro {\n margin-bottom: 1rem;\n color: var(--neutralLight2, #cac9d5);\n}\n.ls-variable-picker__header,\n.ls-variable-picker__row {\n display: grid;\n grid-template-columns: minmax(300px, 1.5fr) 2fr;\n gap: 2rem;\n}\n.ls-variable-picker__header {\n margin-bottom: 0.25rem;\n padding-inline: 0.25rem;\n color: var(--neutralLight3, #9392a1);\n}\n.ls-variable-picker__list {\n height: 100%;\n overflow: auto;\n padding-right: 1rem;\n}\n.ls-variable-picker__row {\n cursor: pointer;\n align-items: start;\n border-bottom: 1px solid color-mix(in srgb, #fff 10%, transparent);\n padding: 1rem 0.25rem;\n}\n.ls-variable-picker__row:active {\n opacity: 0.8;\n}\n.ls-variable-picker__description {\n max-width: 600px;\n overflow-wrap: break-word;\n line-height: 1.25;\n}\n.ls-variable-token {\n display: flex;\n min-width: 0;\n align-items: center;\n}\n.ls-variable-token--custom {\n color: var(--customVariables, #69ffd2);\n}\n.ls-variable-token--function {\n color: var(--functionVariables, var(--semanticPurple, #b489ff));\n}\n.ls-variable-token--system {\n color: var(--normalVariables, var(--semanticBlue, #65b8ff));\n}\n.ls-variable-token__name {\n min-width: 0;\n word-break: break-all;\n}\n.ls-variable-token__badge {\n display: inline-flex;\n margin-left: 0.5rem;\n flex-shrink: 0;\n align-items: center;\n border: 1px solid currentcolor;\n border-radius: 0.25rem;\n padding-inline: 0.25rem;\n padding-block: 0;\n font-size: 10px;\n font-weight: 600;\n line-height: 1;\n text-transform: uppercase;\n}\n");
|
|
24
|
+
styleInject(".ls-color-picker,\n.ls-color-picker *,\n.mui-multi-select,\n.mui-multi-select *,\n.ls-multi-select-value,\n.ls-multi-select-value *,\n.ls-variable-picker,\n.ls-variable-picker *,\n.ls-variable-token,\n.ls-variable-token *,\n.ls-font-picker,\n.ls-font-picker *,\n.mui-ls-input,\n.mui-ls-input * {\n box-sizing: border-box;\n}\n.ls-color-picker button,\n.mui-multi-select button {\n font: inherit;\n letter-spacing: inherit;\n color: inherit;\n margin: 0;\n}\n.ls-color-picker__preview {\n appearance: none;\n -webkit-appearance: none;\n background-color: transparent;\n background-image: none;\n cursor: pointer;\n text-transform: uppercase;\n user-select: none;\n}\n.mui-ls-button.Mui-disabled {\n color: var(--neutralLight2, var(--white2, #cac9d5));\n opacity: 0.45;\n background-color: var(--separator, #0a0821);\n cursor: not-allowed;\n}\n.mui-ls-button {\n border-radius: var(--radius, 1rem);\n padding: 0.375rem 1.5rem;\n text-transform: uppercase;\n}\n.mui-ls-button.MuiButton-sizeSmall {\n padding: 0.25rem 1rem;\n}\n.mui-ls-button.MuiButton-sizeLarge {\n padding: 0.625rem 2rem;\n}\n.mui-ls-button--extended {\n padding-inline: 3rem;\n}\n.mui-ls-button.MuiButton-containedPrimary,\n.mui-ls-button.Mui-disabled.MuiButton-containedPrimary {\n background: var(--primary, #ff4076);\n color: var(--alwayswhite, #fff) !important;\n}\n.mui-ls-button.MuiButton-containedSecondary {\n background-color: var(--secondary, #535395);\n color: var(--alwayswhite, #fff) !important;\n}\n.mui-ls-button.Mui-disabled.MuiButton-containedSecondary {\n background-color: var(--secondary, #535395);\n color: var(--neutralLight2, var(--white2, #cac9d5));\n opacity: 0.4;\n}\n.mui-ls-button.MuiButton-outlinedPrimary {\n color: var(--primary, #ff4076);\n border-color: var(--primary, #ff4076);\n}\n.mui-ls-button.MuiButton-outlinedPrimary:hover {\n border-color: var(--primary, #ff4076);\n background-color: color-mix(in srgb, var(--primary, #ff4076) 12%, transparent);\n}\n.mui-ls-button.MuiButton-outlinedSecondary {\n color: var(--neutralLight1, var(--white, #fff));\n border-color: var(--secondary, #535395);\n}\n.mui-ls-button.MuiButton-outlinedSecondary.Mui-disabled {\n color: var(--neutralLight2, var(--white2, #cac9d5));\n border-color: var(--neutralDark4, var(--cardborder, #393853));\n background-color: var(--transwhite, rgba(255, 255, 255, 0.05));\n opacity: 0.5;\n}\n.mui-ls-button.MuiButton-outlinedSecondary:hover {\n border-color: var(--secondary, #535395);\n background-color: var(--transwhite, rgba(255, 255, 255, 0.05));\n}\n.mui-ls-button.MuiButton-containedError {\n color: var(--alwayswhite, #fff) !important;\n}\n.mui-ls-button.MuiButton-outlinedError {\n color: var(--error, #fd5454);\n border-color: var(--error, #fd5454);\n}\n.mui-ls-button.MuiButton-outlinedError:hover {\n border-color: var(--error, #fd5454);\n background-color: color-mix(in srgb, var(--error, #fd5454) 12%, transparent);\n}\n.mui-ls-button--neutral.mui-ls-button--contained {\n background-color: var(--neutralDark4, var(--cardborder, #393853));\n color: var(--neutralLight1, var(--white, #fff)) !important;\n}\n.mui-ls-button--neutral.mui-ls-button--contained:hover {\n background-color: color-mix(in srgb, var(--neutralDark4, var(--cardborder, #393853)) 82%, var(--neutralLight1, #fff));\n}\n.mui-ls-button--neutral.mui-ls-button--outlined {\n color: var(--neutralLight1, var(--white, #fff));\n border-color: var(--neutralDark4, var(--cardborder, #393853));\n background-color: transparent;\n}\n.mui-ls-button--neutral.mui-ls-button--outlined:hover {\n border-color: var(--neutralLight3, var(--grey, #9392a1));\n background-color: var(--transwhite, rgba(255, 255, 255, 0.05));\n}\n.mui-ls-button--neutral.mui-ls-button--text {\n color: var(--neutralLight1, var(--white, #fff));\n}\n.mui-ls-button--neutral.mui-ls-button--text:hover {\n background-color: var(--transwhite, rgba(255, 255, 255, 0.05));\n}\n.mui-ls-button svg {\n max-height: 24px;\n max-width: 24px;\n}\n.mui-ls-input,\n.ls-font-picker,\n.ls-color-picker__input {\n width: 100%;\n}\n.mui-ls-input,\n.mui-ls-select-form-control,\n.mui-multi-select,\n.ls-font-picker,\n.mui-ls-slider-input-root {\n --ls-control-height: 55px;\n}\n.mui-ls-input .MuiOutlinedInput-root,\n.mui-ls-input .MuiInputBase-root,\n.mui-ls-input .MuiOutlinedInput-notchedOutline,\n.mui-ls-select.MuiOutlinedInput-root,\n.mui-ls-select .MuiOutlinedInput-notchedOutline,\n.mui-multi-select .mui-ls-select.MuiOutlinedInput-root,\n.mui-multi-select .mui-ls-select .MuiOutlinedInput-notchedOutline,\n.ls-font-picker .MuiOutlinedInput-root,\n.ls-font-picker .MuiInputBase-root,\n.ls-font-picker .MuiOutlinedInput-notchedOutline,\n.ls-color-picker__input .MuiOutlinedInput-root,\n.ls-color-picker__input .MuiInputBase-root,\n.ls-color-picker__input .MuiOutlinedInput-notchedOutline {\n border-radius: var(--radius) !important;\n}\n.mui-ls-input .MuiInputBase-root,\n.mui-ls-select.MuiInputBase-root,\n.mui-multi-select .mui-ls-select.MuiInputBase-root,\n.ls-font-picker .MuiInputBase-root {\n min-height: var(--ls-control-height);\n}\n.mui-ls-input.small .MuiInputBase-root {\n min-height: 25px;\n}\n.mui-ls-input.medium .MuiInputBase-root {\n min-height: 35px;\n}\n.mui-ls-input.noMinHeight .MuiInputBase-root {\n min-height: unset;\n}\n.mui-ls-select .MuiSelect-select,\n.mui-multi-select .MuiSelect-select {\n display: flex;\n min-height: calc(var(--ls-control-height) - 2px);\n align-items: center;\n box-sizing: border-box;\n border-radius: var(--radius);\n}\n.mui-multi-select .MuiSelect-select {\n min-width: 0;\n}\n.MuiSvgIcon-root svg {\n color: var(--neutralLight1, var(--white, #fff)) !important;\n}\n.mui-ls-input .MuiSvgIcon-root svg path {\n fill: currentcolor;\n stroke: currentcolor;\n}\n.mui-ls-input .Mui-focused .MuiOutlinedInput-notchedOutline,\n.mui-ls-input .MuiOutlinedInput-root.Mui-focused .MuiOutlinedInput-notchedOutline {\n border-color: var(--primary, #ff4076) !important;\n}\n.ls-variable-autocomplete-popper .MuiAutocomplete-paper,\n.ls-variable-autocomplete-paper {\n border: 1px solid var(--neutralDark4, var(--cardborder, #393853)) !important;\n border-radius: var(--radius, 1rem) !important;\n background: var(--neutralDark2, var(--cardbackground, #211f45)) !important;\n color: var(--neutralLight1, var(--white, #fff)) !important;\n box-shadow: 0 16px 32px rgba(0, 0, 0, 0.32) !important;\n overflow: hidden !important;\n}\n.ls-variable-autocomplete-popper .MuiAutocomplete-listbox,\n.ls-variable-autocomplete-listbox {\n padding: 0.25rem 0 !important;\n background: var(--neutralDark2, var(--cardbackground, #211f45)) !important;\n color: var(--neutralLight1, var(--white, #fff)) !important;\n}\n.ls-variable-autocomplete-popper .MuiAutocomplete-option,\n.ls-variable-autocomplete-listbox .MuiAutocomplete-option {\n display: flex !important;\n min-height: 44px !important;\n align-items: center !important;\n padding: 0.625rem 1rem !important;\n color: var(--neutralLight1, var(--white, #fff)) !important;\n font-size: 1rem !important;\n line-height: 1.35 !important;\n cursor: pointer !important;\n transition: background-color 120ms ease, color 120ms ease !important;\n}\n.ls-variable-autocomplete-popper .MuiAutocomplete-option > *,\n.ls-variable-autocomplete-listbox .MuiAutocomplete-option > * {\n min-width: 0;\n}\n.ls-variable-autocomplete-popper .MuiAutocomplete-option:hover,\n.ls-variable-autocomplete-popper .MuiAutocomplete-option.Mui-focused,\n.ls-variable-autocomplete-popper .MuiAutocomplete-option[data-focus=true],\n.ls-variable-autocomplete-popper .MuiAutocomplete-option[aria-selected=true],\n.ls-variable-autocomplete-listbox .MuiAutocomplete-option:hover,\n.ls-variable-autocomplete-listbox .MuiAutocomplete-option.Mui-focused,\n.ls-variable-autocomplete-listbox .MuiAutocomplete-option[data-focus=true],\n.ls-variable-autocomplete-listbox .MuiAutocomplete-option[aria-selected=true] {\n background: var( --cardHover, var(--transwhite, rgba(255, 255, 255, 0.05)) ) !important;\n color: var(--neutralLight1, var(--white, #fff)) !important;\n}\n.ls-variable-option {\n gap: 0.75rem;\n}\n.ls-variable-option__thumb {\n width: 40px;\n height: 40px;\n flex: 0 0 40px;\n border-radius: var(--radius, 1rem);\n object-fit: cover;\n}\n.ls-variable-option__thumb--placeholder {\n background: var(--neutralDark4, var(--cardborder, #393853));\n}\n.ls-variable-option__body {\n min-width: 0;\n}\n.ls-variable-option__label {\n color: var(--neutralLight1, var(--white, #fff));\n font-weight: 500;\n line-height: 1.25;\n}\n.ls-variable-option__helper {\n margin-top: 0.125rem;\n color: var(--neutralLight3, var(--grey, #9392a1));\n font-size: 0.875rem;\n line-height: 1.25;\n}\n.ls-variable-autocomplete-popup-indicator,\n.ls-variable-autocomplete-popup-indicator.MuiIconButton-root,\n.ls-variable-autocomplete-popup-indicator svg {\n color: var(--neutralLight1, var(--white, #fff)) !important;\n}\n.ls-variable-autocomplete-popup-indicator svg path {\n fill: currentcolor !important;\n stroke: currentcolor !important;\n}\n.ls-variable-input-adornment,\n.ls-variable-input-adornment.MuiInputAdornment-root {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 24px;\n width: 24px;\n min-width: 24px;\n margin-left: 0.35rem;\n border-radius: var(--radius, 1rem);\n background: var(--primary, #ff4076) !important;\n color: var(--alwayswhite, var(--white, #fff)) !important;\n font-weight: 800;\n line-height: 1;\n letter-spacing: 0;\n cursor: pointer;\n user-select: none;\n}\n.ls-variable-input-adornment svg,\n.ls-variable-input-adornment path {\n color: currentcolor !important;\n fill: currentcolor !important;\n stroke: currentcolor !important;\n}\n.ls-variable-input-adornment:hover,\n.ls-variable-input-adornment.MuiInputAdornment-root:hover {\n filter: brightness(1.08);\n}\n.ls-variable-input-adornment:active,\n.ls-variable-input-adornment.MuiInputAdornment-root:active {\n filter: brightness(0.96);\n}\n.mui-ls-slider-input-root {\n width: 100%;\n}\n.mui-ls-slider-input-fieldset {\n position: relative;\n min-width: 0;\n width: 100%;\n min-height: var(--ls-control-height);\n margin: 0;\n border: 2px solid var(--neutralDark4, var(--cardborder, #393853));\n border-radius: var(--radius, 1rem);\n padding: 0 0.875rem 0.5rem 0.875rem;\n background: transparent;\n color: var(--neutralLight1, var(--white, #fff));\n}\n.mui-ls-slider-input-fieldset:hover {\n border-color: var(--primary, #ff4076);\n}\n.mui-ls-slider-input-legend {\n display: block;\n width: auto;\n max-width: calc(100% - 1rem);\n margin: 0;\n padding: 0 0.25rem;\n color: var(--neutralLight1, var(--white, #fff));\n font-size: 0.875rem;\n line-height: 1.1;\n white-space: nowrap;\n}\n.mui-ls-slider-input-row {\n display: flex;\n min-width: 0;\n min-height: calc(var(--ls-control-height) - 14px);\n align-items: center;\n gap: 1rem;\n}\n.mui-ls-slider-input-row--slider {\n flex-wrap: nowrap;\n}\n.mui-ls-slider-input-row--input {\n justify-content: stretch;\n}\n.mui-ls-slider-input-value.mui-ls-input {\n margin: 0;\n}\n.mui-ls-slider-input-value.mui-ls-input .MuiFormControl-root,\n.mui-ls-slider-input-value.mui-ls-input .MuiTextField-root {\n margin: 0;\n}\n.mui-ls-slider-input-value.mui-ls-input .MuiInputBase-root {\n min-height: 36px;\n}\n.mui-ls-slider-input-value.mui-ls-input .MuiOutlinedInput-notchedOutline {\n border-color: var(--neutralDark4, var(--cardborder, #393853));\n}\n.mui-ls-slider-input-helper {\n display: block;\n margin-top: 0.25rem;\n color: var(--neutralLight3, var(--grey, #9392a1));\n font-size: 0.75rem;\n line-height: 1.25;\n}\n.ls-multi-select-value {\n display: flex;\n width: 100%;\n min-width: 0;\n flex-wrap: nowrap;\n align-items: center;\n justify-content: space-between;\n gap: 0.5rem;\n overflow: hidden;\n white-space: nowrap;\n}\n.ls-multi-select-value__label {\n min-width: 0;\n flex: 1 1 0%;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.ls-multi-select-value__count {\n flex-shrink: 0;\n white-space: nowrap;\n}\n.ls-color-picker__preview {\n position: relative;\n display: inline-block;\n width: 1.5rem;\n height: 1.5rem;\n flex-shrink: 0;\n padding: 0;\n border: 1px solid color-mix(in srgb, #fff 25%, transparent);\n border-radius: var(--radius, 1rem);\n background-size: cover;\n background-position: center;\n background-repeat: no-repeat;\n box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.25);\n color: transparent;\n line-height: 0;\n}\n.ls-color-picker__preview:disabled {\n cursor: not-allowed;\n opacity: 0.5;\n}\n.ls-color-picker__preview:focus {\n outline: none;\n}\n.ls-color-picker__preview:focus-visible {\n box-shadow:\n 0 0 0 2px var(--primary, #ff4076),\n 0 0 0 4px var(--neutralDark1, #1b1a28),\n 0 0 0 1px rgba(0, 0, 0, 0.25);\n}\n.ls-color-picker__gradient circle,\n.ls-color-picker__gradient polyline {\n stroke: #fff;\n}\n.ls-variable-picker {\n --variable-custom-color: var(--customVariables, #69ffd2);\n --variable-function-color: var( --functionVariables, var(--semanticPurple, #b489ff) );\n --variable-normal-color: var(--normalVariables, var(--semanticBlue, #65b8ff));\n display: flex;\n width: 92vw;\n max-width: 1100px;\n min-height: 50vh;\n max-height: 55vh;\n flex-direction: column;\n overflow: hidden;\n padding: 1rem;\n}\n.ls-variable-picker__field {\n margin: 0 0 0.75rem;\n border: 1px solid color-mix(in srgb, var(--primary, #ff4076) 42%, var(--neutralDark4, #393853));\n border-radius: var(--radius, 1rem);\n padding: 0.5rem;\n}\n.ls-variable-picker__legend {\n padding-inline: 0.375rem;\n color: var(--primary, #ff4076);\n font-size: 0.75rem;\n font-weight: 700;\n}\n.ls-variable-picker__intro {\n margin-bottom: 1rem;\n color: var(--neutralLight2, #cac9d5);\n}\n.ls-variable-picker__header,\n.ls-variable-picker__row {\n display: grid;\n grid-template-columns: minmax(300px, 1.5fr) 1fr 1fr;\n gap: 2rem;\n}\n.ls-variable-picker__header {\n margin-bottom: 0.25rem;\n padding-inline: 0.25rem;\n padding-right: 1.7rem;\n color: var(--neutralLight3, #9392a1);\n}\n.ls-variable-picker__list {\n height: 100%;\n overflow: auto;\n padding-right: 1rem;\n}\n.ls-variable-picker__row {\n cursor: pointer;\n align-items: start;\n border-bottom: 1px solid color-mix(in srgb, var(--neutralDark4, #393853) 70%, transparent);\n padding: 1rem 0.25rem;\n}\n.ls-variable-picker__row--no-border {\n border-bottom: 0;\n}\n.ls-variable-picker__token-cell {\n display: flex;\n min-width: 0;\n align-items: center;\n gap: 0.375rem;\n}\n.ls-variable-picker__expand-toggle,\n.ls-variable-picker__expand-spacer {\n width: 24px;\n height: 24px;\n flex: 0 0 24px;\n}\n.ls-variable-picker__expand-toggle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n border: 1px solid color-mix(in srgb, var(--neutralDark4, #393853) 75%, transparent);\n border-radius: var(--radius, 1rem);\n padding: 0;\n background: var(--neutralDark3, var(--containerbackground, #1f1f3a));\n color: var(--neutralLight2, #cac9d5);\n transition:\n background-color 140ms ease,\n border-color 140ms ease,\n color 140ms ease,\n transform 140ms ease;\n}\n.ls-variable-picker__expand-toggle:hover {\n border-color: var(--primary, #ff4076);\n background: color-mix(in srgb, var(--primary, #ff4076) 16%, var(--neutralDark3, #1f1f3a));\n color: var(--neutralLight1, #fff);\n}\n.ls-variable-picker__expand-toggle svg {\n transform: rotate(-90deg);\n transition: transform 140ms ease;\n}\n.ls-variable-picker__expand-toggle--expanded svg {\n transform: rotate(0deg);\n}\n.ls-variable-picker__row:active {\n opacity: 0.8;\n}\n.ls-variable-picker__description {\n max-width: 600px;\n overflow-wrap: break-word;\n line-height: 1.25;\n word-break: break-all;\n}\n.ls-variable-picker__value {\n min-width: 0;\n}\n.ls-variable-picker__value-input {\n width: 100%;\n min-width: 0;\n cursor: text;\n overflow: hidden;\n border: 0;\n background: transparent;\n color: var(--neutralLight1, var(--white, #fff));\n caret-color: transparent;\n font: inherit;\n font-size: 1rem;\n line-height: 1.25;\n outline: 0;\n padding: 0;\n text-overflow: ellipsis;\n}\n.ls-variable-picker__value-input:focus {\n outline: 0;\n}\n.ls-variable-picker__value-input::selection {\n background: color-mix(in srgb, var(--primary, #ff4076) 45%, transparent);\n color: var(--alwayswhite, var(--white, #fff));\n}\n.ls-variable-token {\n display: flex;\n min-width: 0;\n align-items: center;\n}\n.ls-variable-token--custom {\n color: var(--customVariables, #69ffd2);\n}\n.ls-variable-token--function {\n color: var(--functionVariables, var(--semanticPurple, #b489ff));\n}\n.ls-variable-token--system {\n color: var(--normalVariables, var(--semanticBlue, #65b8ff));\n}\n.ls-variable-token__name {\n min-width: 0;\n word-break: break-all;\n}\n.ls-variable-token__badge {\n display: inline-flex;\n margin-left: 0.5rem;\n flex-shrink: 0;\n align-items: center;\n border: 1px solid currentcolor;\n border-radius: var(--radius, 1rem);\n padding-inline: 0.25rem;\n padding-block: 0;\n font-size: 10px;\n font-weight: 600;\n line-height: 1;\n text-transform: uppercase;\n}\n");
|
|
25
25
|
|
|
26
26
|
// src/components/LSButton/LSButton.tsx
|
|
27
|
+
import Button from "@mui/material/Button";
|
|
28
|
+
import classNames from "classnames";
|
|
27
29
|
import { jsx } from "react/jsx-runtime";
|
|
28
30
|
var LSButton = ({
|
|
31
|
+
label,
|
|
32
|
+
disabled = false,
|
|
33
|
+
loading = false,
|
|
34
|
+
variant = "contained",
|
|
35
|
+
extended = 0,
|
|
36
|
+
color,
|
|
29
37
|
primary = false,
|
|
30
|
-
size = "medium",
|
|
31
38
|
backgroundColor,
|
|
32
|
-
|
|
39
|
+
className,
|
|
40
|
+
sx,
|
|
41
|
+
style,
|
|
33
42
|
...props
|
|
34
43
|
}) => {
|
|
35
|
-
const
|
|
44
|
+
const resolvedColor = color ?? (primary ? "primary" : "primary");
|
|
45
|
+
const muiColor = resolvedColor === "neutral" ? void 0 : resolvedColor;
|
|
46
|
+
const backgroundSx = backgroundColor ? { backgroundColor, "&:hover": { backgroundColor } } : null;
|
|
47
|
+
const secondaryOutlinedStyles = resolvedColor === "secondary" && variant === "outlined" ? {
|
|
48
|
+
color: "var(--white) !important",
|
|
49
|
+
"& .MuiButton-startIcon, & .MuiButton-endIcon": {
|
|
50
|
+
color: "inherit"
|
|
51
|
+
}
|
|
52
|
+
} : null;
|
|
36
53
|
return /* @__PURE__ */ jsx(
|
|
37
|
-
|
|
54
|
+
Button,
|
|
38
55
|
{
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
56
|
+
disabled: disabled || loading,
|
|
57
|
+
variant,
|
|
58
|
+
color: muiColor,
|
|
59
|
+
style,
|
|
60
|
+
sx: [
|
|
61
|
+
{ borderRadius: "1rem", transition: "opacity 300ms ease-in-out" },
|
|
62
|
+
...backgroundSx ? [backgroundSx] : [],
|
|
63
|
+
...Array.isArray(sx) ? sx : sx ? [sx] : [],
|
|
64
|
+
...secondaryOutlinedStyles ? [secondaryOutlinedStyles] : []
|
|
65
|
+
],
|
|
66
|
+
className: classNames(
|
|
67
|
+
"mui-ls-button cursor-pointer rounded-2xl pb-1.5 pt-1.5 hover:opacity-80 svg-current-color",
|
|
68
|
+
extended ? "pl-12 pr-12 mui-ls-button--extended" : "pl-6 pr-6",
|
|
69
|
+
`mui-ls-button--${resolvedColor}`,
|
|
70
|
+
`mui-ls-button--${variant}`,
|
|
71
|
+
className
|
|
72
|
+
),
|
|
45
73
|
...props,
|
|
46
|
-
children: label
|
|
74
|
+
children: loading ? "Loading..." : label
|
|
47
75
|
}
|
|
48
76
|
);
|
|
49
77
|
};
|
|
@@ -52,7 +80,7 @@ var LSButton = ({
|
|
|
52
80
|
import FormControl from "@mui/material/FormControl";
|
|
53
81
|
import InputAdornment from "@mui/material/InputAdornment";
|
|
54
82
|
import TextField from "@mui/material/TextField";
|
|
55
|
-
import
|
|
83
|
+
import classNames2 from "classnames";
|
|
56
84
|
import { forwardRef } from "react";
|
|
57
85
|
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
58
86
|
var LSInput = forwardRef(
|
|
@@ -149,7 +177,7 @@ var LSInput = forwardRef(
|
|
|
149
177
|
FormControl,
|
|
150
178
|
{
|
|
151
179
|
variant: "outlined",
|
|
152
|
-
className:
|
|
180
|
+
className: classNames2("mui-ls-input", className, {
|
|
153
181
|
noMinHeight: $noMinHeight,
|
|
154
182
|
bypassMuiColor: bypasscolor || bypasscolor === "default"
|
|
155
183
|
}),
|
|
@@ -182,7 +210,7 @@ LSInput.displayName = "LSInput";
|
|
|
182
210
|
|
|
183
211
|
// src/components/LSSliderInput/LSSliderInput.tsx
|
|
184
212
|
import Slider from "@mui/material/Slider";
|
|
185
|
-
import
|
|
213
|
+
import classNames3 from "classnames";
|
|
186
214
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
187
215
|
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
188
216
|
var normalizeSliderValue = (rawValue) => {
|
|
@@ -301,7 +329,7 @@ var LSSliderInput = ({
|
|
|
301
329
|
const controlsRow = /* @__PURE__ */ jsxs(
|
|
302
330
|
"div",
|
|
303
331
|
{
|
|
304
|
-
className:
|
|
332
|
+
className: classNames3("mui-ls-slider-input-row", {
|
|
305
333
|
"mui-ls-slider-input-row--slider": !hideSlider,
|
|
306
334
|
"mui-ls-slider-input-row--input": hideInput
|
|
307
335
|
}),
|
|
@@ -342,28 +370,20 @@ var LSSliderInput = ({
|
|
|
342
370
|
inputMode: stepPrecision > 0 ? "decimal" : "numeric"
|
|
343
371
|
},
|
|
344
372
|
fullWidth: hideSlider ? fullWidth : false,
|
|
345
|
-
$noMinHeight:
|
|
346
|
-
className: hideSlider ? inputProps?.className : `${inputProps?.className ?? ""}
|
|
347
|
-
style: hideSlider ? inputProps?.style : { width:
|
|
373
|
+
$noMinHeight: false,
|
|
374
|
+
className: hideSlider ? inputProps?.className : `${inputProps?.className ?? ""} mui-ls-slider-input-value`.trim(),
|
|
375
|
+
style: hideSlider ? inputProps?.style : { width: 112, maxWidth: 112, flexShrink: 0 },
|
|
348
376
|
...!hideSlider ? { size: "small" } : {}
|
|
349
377
|
}
|
|
350
378
|
)
|
|
351
379
|
]
|
|
352
380
|
}
|
|
353
381
|
);
|
|
354
|
-
return /* @__PURE__ */ jsxs("div", { className:
|
|
355
|
-
/* @__PURE__ */ jsxs(
|
|
356
|
-
"
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
"mui-ls-slider-input-fieldset--fullWidth": fullWidth
|
|
360
|
-
}),
|
|
361
|
-
children: [
|
|
362
|
-
label && /* @__PURE__ */ jsx3("legend", { className: "mui-ls-slider-input-legend", children: label }),
|
|
363
|
-
controlsRow
|
|
364
|
-
]
|
|
365
|
-
}
|
|
366
|
-
),
|
|
382
|
+
return /* @__PURE__ */ jsxs("div", { className: "mui-ls-slider-input-root", children: [
|
|
383
|
+
/* @__PURE__ */ jsxs("fieldset", { className: "mui-ls-slider-input-fieldset", children: [
|
|
384
|
+
label && /* @__PURE__ */ jsx3("legend", { className: "mui-ls-slider-input-legend", children: label }),
|
|
385
|
+
controlsRow
|
|
386
|
+
] }),
|
|
367
387
|
helperText && /* @__PURE__ */ jsx3("small", { className: "mui-ls-slider-input-helper", children: helperText })
|
|
368
388
|
] });
|
|
369
389
|
};
|
|
@@ -374,8 +394,19 @@ import FormControl2 from "@mui/material/FormControl";
|
|
|
374
394
|
import InputLabel from "@mui/material/InputLabel";
|
|
375
395
|
import Select from "@mui/material/Select";
|
|
376
396
|
import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
377
|
-
var LSSelect = ({
|
|
378
|
-
|
|
397
|
+
var LSSelect = ({
|
|
398
|
+
className = "",
|
|
399
|
+
style,
|
|
400
|
+
...props
|
|
401
|
+
}) => {
|
|
402
|
+
const {
|
|
403
|
+
placeholder,
|
|
404
|
+
displayEmpty: displayEmptyProp,
|
|
405
|
+
renderValue: renderValueProp,
|
|
406
|
+
variant: _variant,
|
|
407
|
+
MenuProps,
|
|
408
|
+
...rest
|
|
409
|
+
} = props;
|
|
379
410
|
const labelKey = props.name ?? (typeof props.label === "string" ? props.label : void 0);
|
|
380
411
|
const labelId = props.label && labelKey ? `label_${labelKey}` : void 0;
|
|
381
412
|
const placeholderText = typeof placeholder === "string" ? placeholder : "";
|
|
@@ -398,6 +429,7 @@ var LSSelect = ({ className = "", style, ...props }) => {
|
|
|
398
429
|
backgroundColor: "var(--neutralDark2)",
|
|
399
430
|
color: "var(--neutralLight1)",
|
|
400
431
|
border: "1px solid var(--neutralDark4)",
|
|
432
|
+
borderRadius: "var(--radius, 1rem)",
|
|
401
433
|
boxShadow: "0 16px 32px rgba(0, 0, 0, 0.32)",
|
|
402
434
|
...MenuProps?.slotProps?.paper?.sx
|
|
403
435
|
}
|
|
@@ -418,6 +450,7 @@ var LSSelect = ({ className = "", style, ...props }) => {
|
|
|
418
450
|
backgroundColor: "var(--neutralDark2)",
|
|
419
451
|
color: "var(--neutralLight1)",
|
|
420
452
|
border: "1px solid var(--neutralDark4)",
|
|
453
|
+
borderRadius: "var(--radius, 1rem)",
|
|
421
454
|
boxShadow: "0 16px 32px rgba(0, 0, 0, 0.32)",
|
|
422
455
|
"& .MuiList-root": {
|
|
423
456
|
backgroundColor: "var(--neutralDark2)"
|
|
@@ -433,24 +466,39 @@ var LSSelect = ({ className = "", style, ...props }) => {
|
|
|
433
466
|
}
|
|
434
467
|
}
|
|
435
468
|
};
|
|
436
|
-
return /* @__PURE__ */ jsxs2(
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
{
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
children: props.
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
469
|
+
return /* @__PURE__ */ jsxs2(
|
|
470
|
+
FormControl2,
|
|
471
|
+
{
|
|
472
|
+
variant: "outlined",
|
|
473
|
+
className: `${className} mui-ls-select-form-control`,
|
|
474
|
+
sx: {
|
|
475
|
+
marginBottom: ".3rem",
|
|
476
|
+
marginTop: ".5rem",
|
|
477
|
+
minWidth: "100px",
|
|
478
|
+
width: "100%"
|
|
479
|
+
},
|
|
480
|
+
size: rest.size,
|
|
481
|
+
style,
|
|
482
|
+
children: [
|
|
483
|
+
props.label && /* @__PURE__ */ jsx4(InputLabel, { shrink: true, id: labelId, children: props.label }),
|
|
484
|
+
/* @__PURE__ */ jsx4(
|
|
485
|
+
Select,
|
|
486
|
+
{
|
|
487
|
+
MenuProps: mergedMenuProps,
|
|
488
|
+
className: "mui-ls-select",
|
|
489
|
+
variant: "outlined",
|
|
490
|
+
labelId,
|
|
491
|
+
label: props.label,
|
|
492
|
+
displayEmpty,
|
|
493
|
+
renderValue,
|
|
494
|
+
...rest,
|
|
495
|
+
value,
|
|
496
|
+
children: props.children
|
|
497
|
+
}
|
|
498
|
+
)
|
|
499
|
+
]
|
|
500
|
+
}
|
|
501
|
+
);
|
|
454
502
|
};
|
|
455
503
|
LSSelect.displayName = "LSSelect";
|
|
456
504
|
|
|
@@ -459,7 +507,7 @@ import Checkbox from "@mui/material/Checkbox";
|
|
|
459
507
|
import FormControlLabel from "@mui/material/FormControlLabel";
|
|
460
508
|
import { forwardRef as forwardRef2 } from "react";
|
|
461
509
|
import { useController, useFormContext } from "react-hook-form";
|
|
462
|
-
import
|
|
510
|
+
import classNames4 from "classnames";
|
|
463
511
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
464
512
|
var LSCheckbox = forwardRef2(({ className = "", checked, inputRef, slotProps, ...props }, ref) => {
|
|
465
513
|
const CheckboxComponent = Checkbox;
|
|
@@ -468,7 +516,7 @@ var LSCheckbox = forwardRef2(({ className = "", checked, inputRef, slotProps, ..
|
|
|
468
516
|
{
|
|
469
517
|
...props,
|
|
470
518
|
checked,
|
|
471
|
-
className:
|
|
519
|
+
className: classNames4("ls-checkbox", className, { "Mui-disabled": props.disabled }),
|
|
472
520
|
ref,
|
|
473
521
|
slotProps: {
|
|
474
522
|
...slotProps ?? {},
|
|
@@ -496,7 +544,7 @@ function LSCheckboxField({
|
|
|
496
544
|
return /* @__PURE__ */ jsx5(
|
|
497
545
|
FormControlLabel,
|
|
498
546
|
{
|
|
499
|
-
className:
|
|
547
|
+
className: classNames4("ls-checkbox-row", className),
|
|
500
548
|
labelPlacement,
|
|
501
549
|
disabled,
|
|
502
550
|
control: /* @__PURE__ */ jsx5(
|
|
@@ -534,7 +582,7 @@ var LSColorPicker = ({ value = DEFAULT_COLOR, onChange, onBlur, className, name,
|
|
|
534
582
|
right: 0,
|
|
535
583
|
top: "calc(100% + 0.5rem)",
|
|
536
584
|
zIndex: 1e3,
|
|
537
|
-
borderRadius: "
|
|
585
|
+
borderRadius: "1rem",
|
|
538
586
|
background: "var(--neutralDark1)",
|
|
539
587
|
padding: "0.5rem",
|
|
540
588
|
boxShadow: "0 8px 24px rgba(0, 0, 0, 0.4)"
|
|
@@ -545,7 +593,7 @@ var LSColorPicker = ({ value = DEFAULT_COLOR, onChange, onBlur, className, name,
|
|
|
545
593
|
height: inlinePickerHeight,
|
|
546
594
|
minHeight: inlinePickerHeight,
|
|
547
595
|
marginTop: "0.5rem",
|
|
548
|
-
borderRadius: "
|
|
596
|
+
borderRadius: "1rem",
|
|
549
597
|
background: "var(--neutralDark1)",
|
|
550
598
|
padding: "0.5rem",
|
|
551
599
|
boxSizing: "border-box",
|
|
@@ -675,15 +723,36 @@ var LSColorPicker = ({ value = DEFAULT_COLOR, onChange, onBlur, className, name,
|
|
|
675
723
|
import { KeyboardArrowDown } from "@mui/icons-material";
|
|
676
724
|
import Autocomplete from "@mui/material/Autocomplete";
|
|
677
725
|
import TextField2 from "@mui/material/TextField";
|
|
678
|
-
import {
|
|
726
|
+
import {
|
|
727
|
+
memo,
|
|
728
|
+
startTransition,
|
|
729
|
+
useEffect as useEffect3,
|
|
730
|
+
useMemo as useMemo2,
|
|
731
|
+
useRef as useRef2,
|
|
732
|
+
useState as useState3
|
|
733
|
+
} from "react";
|
|
679
734
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
680
|
-
var LSFontPicker = memo(function LSFontPicker2({
|
|
735
|
+
var LSFontPicker = memo(function LSFontPicker2({
|
|
736
|
+
value,
|
|
737
|
+
onChange,
|
|
738
|
+
fonts = [],
|
|
739
|
+
localFonts = [],
|
|
740
|
+
onLoadFonts,
|
|
741
|
+
defaultValue = "Roboto",
|
|
742
|
+
placeholder = "Select a font",
|
|
743
|
+
isAlertManager = false,
|
|
744
|
+
label,
|
|
745
|
+
helperText
|
|
746
|
+
}) {
|
|
681
747
|
const AutocompleteComponent = Autocomplete;
|
|
682
748
|
const TextFieldComponent = TextField2;
|
|
683
749
|
const [inputValue, setInputValue] = useState3(value ?? defaultValue);
|
|
684
750
|
const onLoadFontsRef = useRef2(onLoadFonts);
|
|
685
751
|
const onChangeRef = useRef2(onChange);
|
|
686
|
-
const combinedFonts = useMemo2(
|
|
752
|
+
const combinedFonts = useMemo2(
|
|
753
|
+
() => Array.from(/* @__PURE__ */ new Set([...localFonts, ...fonts])).sort(),
|
|
754
|
+
[fonts, localFonts]
|
|
755
|
+
);
|
|
687
756
|
const currentValue = value ?? defaultValue;
|
|
688
757
|
useEffect3(() => {
|
|
689
758
|
onLoadFontsRef.current = onLoadFonts;
|
|
@@ -719,7 +788,9 @@ var LSFontPicker = memo(function LSFontPicker2({ value, onChange, fonts = [], lo
|
|
|
719
788
|
popupIcon: /* @__PURE__ */ jsx7(KeyboardArrowDown, {}),
|
|
720
789
|
isOptionEqualToValue: (option, selectedValue) => option === selectedValue,
|
|
721
790
|
onChange: (_event, newValue) => {
|
|
722
|
-
handleValueChange(
|
|
791
|
+
handleValueChange(
|
|
792
|
+
typeof newValue === "string" ? newValue : `${newValue ?? ""}`
|
|
793
|
+
);
|
|
723
794
|
},
|
|
724
795
|
onInputChange: (_event, newInputValue, reason) => {
|
|
725
796
|
if (reason === "input" || reason === "clear") {
|
|
@@ -734,7 +805,7 @@ var LSFontPicker = memo(function LSFontPicker2({ value, onChange, fonts = [], lo
|
|
|
734
805
|
sx: {
|
|
735
806
|
background: "var(--neutralDark3)",
|
|
736
807
|
border: "1px solid var(--neutralDark4)",
|
|
737
|
-
borderRadius: "var(--
|
|
808
|
+
borderRadius: "var(--radius, 1rem)",
|
|
738
809
|
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.3)",
|
|
739
810
|
color: "var(--neutralLight1)",
|
|
740
811
|
marginTop: "4px"
|
|
@@ -783,7 +854,7 @@ var LSFontPicker = memo(function LSFontPicker2({ value, onChange, fonts = [], lo
|
|
|
783
854
|
helperText,
|
|
784
855
|
placeholder,
|
|
785
856
|
fullWidth: true,
|
|
786
|
-
className: "mui-ls-input
|
|
857
|
+
className: "mui-ls-input",
|
|
787
858
|
variant: "outlined",
|
|
788
859
|
sx: {
|
|
789
860
|
"& .MuiOutlinedInput-root": {
|
|
@@ -803,7 +874,13 @@ var LSFontPicker = memo(function LSFontPicker2({ value, onChange, fonts = [], lo
|
|
|
803
874
|
// src/components/LSMultiSelect/LSMultiSelect.tsx
|
|
804
875
|
import { MenuItem } from "@mui/material";
|
|
805
876
|
import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
806
|
-
var LSMultiSelect = ({
|
|
877
|
+
var LSMultiSelect = ({
|
|
878
|
+
options,
|
|
879
|
+
placeholder = "Select...",
|
|
880
|
+
value,
|
|
881
|
+
onChange,
|
|
882
|
+
label
|
|
883
|
+
}) => {
|
|
807
884
|
const handleChange = (event) => {
|
|
808
885
|
const {
|
|
809
886
|
target: { value: value2 }
|
|
@@ -821,7 +898,9 @@ var LSMultiSelect = ({ options, placeholder = "Select...", value, onChange, labe
|
|
|
821
898
|
onChange: handleChange,
|
|
822
899
|
displayEmpty: true,
|
|
823
900
|
renderValue: (selected) => /* @__PURE__ */ jsxs4("div", { className: "ls-multi-select-value", children: [
|
|
824
|
-
/* @__PURE__ */ jsx8("div", { className: "ls-multi-select-value__label", children: selected.length > 0 ? selected.map(
|
|
901
|
+
/* @__PURE__ */ jsx8("div", { className: "ls-multi-select-value__label", children: selected.length > 0 ? selected.map(
|
|
902
|
+
(val) => options.find((opt) => opt.value === val)?.label ?? val
|
|
903
|
+
).join(", ") : placeholder }),
|
|
825
904
|
/* @__PURE__ */ jsx8("div", { className: "ls-multi-select-value__count", children: `(${selected.length})` })
|
|
826
905
|
] }),
|
|
827
906
|
MenuProps: {
|
|
@@ -832,6 +911,7 @@ var LSMultiSelect = ({ options, placeholder = "Select...", value, onChange, labe
|
|
|
832
911
|
backgroundColor: "var(--neutralDark2)",
|
|
833
912
|
color: "var(--neutralLight1)",
|
|
834
913
|
border: "1px solid var(--neutralDark4)",
|
|
914
|
+
borderRadius: "var(--radius, 1rem)",
|
|
835
915
|
boxShadow: "0 16px 32px rgba(0, 0, 0, 0.32)",
|
|
836
916
|
backdropFilter: "none",
|
|
837
917
|
opacity: 1,
|
|
@@ -854,6 +934,7 @@ var LSMultiSelect = ({ options, placeholder = "Select...", value, onChange, labe
|
|
|
854
934
|
opacity: 1,
|
|
855
935
|
maxHeight: "280px !important",
|
|
856
936
|
border: "1px solid var(--neutralDark4)",
|
|
937
|
+
borderRadius: "var(--radius, 1rem)",
|
|
857
938
|
"& .MuiList-root": {
|
|
858
939
|
backgroundColor: "var(--neutralDark2)"
|
|
859
940
|
}
|
|
@@ -877,7 +958,14 @@ var LSMultiSelect = ({ options, placeholder = "Select...", value, onChange, labe
|
|
|
877
958
|
}
|
|
878
959
|
},
|
|
879
960
|
children: [
|
|
880
|
-
/* @__PURE__ */ jsx8(
|
|
961
|
+
/* @__PURE__ */ jsx8(
|
|
962
|
+
LSCheckbox,
|
|
963
|
+
{
|
|
964
|
+
checked: (value ?? []).includes(option.value),
|
|
965
|
+
tabIndex: -1,
|
|
966
|
+
disableRipple: true
|
|
967
|
+
}
|
|
968
|
+
),
|
|
881
969
|
/* @__PURE__ */ jsx8("span", { children: option.label })
|
|
882
970
|
]
|
|
883
971
|
},
|
|
@@ -891,16 +979,16 @@ var LSMultiSelect = ({ options, placeholder = "Select...", value, onChange, labe
|
|
|
891
979
|
import FormControlLabel2 from "@mui/material/FormControlLabel";
|
|
892
980
|
import Radio from "@mui/material/Radio";
|
|
893
981
|
import RadioGroup from "@mui/material/RadioGroup";
|
|
894
|
-
import
|
|
982
|
+
import classNames5 from "classnames";
|
|
895
983
|
import { jsx as jsx9 } from "react/jsx-runtime";
|
|
896
984
|
var LSRadio = ({ className = "", ...props }) => {
|
|
897
|
-
return /* @__PURE__ */ jsx9(Radio, { ...props, className:
|
|
985
|
+
return /* @__PURE__ */ jsx9(Radio, { ...props, className: classNames5("ls-radio", className) });
|
|
898
986
|
};
|
|
899
987
|
var LSRadioGroup = ({ selections, className = "", optionClassName = "", row, ...props }) => {
|
|
900
|
-
return /* @__PURE__ */ jsx9(RadioGroup, { ...props, row, className:
|
|
988
|
+
return /* @__PURE__ */ jsx9(RadioGroup, { ...props, row, className: classNames5("ls-radio-group", className, { row }), children: selections.map((selection) => /* @__PURE__ */ jsx9(
|
|
901
989
|
FormControlLabel2,
|
|
902
990
|
{
|
|
903
|
-
className:
|
|
991
|
+
className: classNames5("ls-radio-row", optionClassName),
|
|
904
992
|
value: selection.value,
|
|
905
993
|
disabled: selection.disabled,
|
|
906
994
|
control: /* @__PURE__ */ jsx9(LSRadio, {}),
|
|
@@ -915,47 +1003,65 @@ LSRadioGroup.displayName = "LSRadioGroup";
|
|
|
915
1003
|
import TextField3 from "@mui/material/TextField";
|
|
916
1004
|
import { forwardRef as forwardRef3 } from "react";
|
|
917
1005
|
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
918
|
-
var LSTextField = forwardRef3(
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
...slotProps
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
...
|
|
932
|
-
|
|
1006
|
+
var LSTextField = forwardRef3(
|
|
1007
|
+
(props, ref) => {
|
|
1008
|
+
const { InputLabelProps, InputProps, slotProps, ...rest } = props;
|
|
1009
|
+
return /* @__PURE__ */ jsx10(
|
|
1010
|
+
TextField3,
|
|
1011
|
+
{
|
|
1012
|
+
...rest,
|
|
1013
|
+
variant: "outlined",
|
|
1014
|
+
className: "mui-ls-input",
|
|
1015
|
+
slotProps: {
|
|
1016
|
+
...slotProps ?? {},
|
|
1017
|
+
input: {
|
|
1018
|
+
...slotProps?.input ?? {},
|
|
1019
|
+
...InputProps ?? {},
|
|
1020
|
+
sx: {
|
|
1021
|
+
...slotProps?.input?.sx ?? {},
|
|
1022
|
+
...InputProps?.sx ?? {}
|
|
1023
|
+
}
|
|
1024
|
+
},
|
|
1025
|
+
inputLabel: {
|
|
1026
|
+
...slotProps?.inputLabel ?? {},
|
|
1027
|
+
shrink: true,
|
|
1028
|
+
...InputLabelProps ?? {}
|
|
933
1029
|
}
|
|
934
1030
|
},
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
},
|
|
941
|
-
ref
|
|
942
|
-
}
|
|
943
|
-
);
|
|
944
|
-
});
|
|
1031
|
+
ref
|
|
1032
|
+
}
|
|
1033
|
+
);
|
|
1034
|
+
}
|
|
1035
|
+
);
|
|
945
1036
|
LSTextField.displayName = "LSTextField";
|
|
946
1037
|
|
|
947
1038
|
// src/components/LSVariableInputField/LSVariableInputField.tsx
|
|
948
|
-
import Autocomplete2, {
|
|
1039
|
+
import Autocomplete2, {
|
|
1040
|
+
createFilterOptions
|
|
1041
|
+
} from "@mui/material/Autocomplete";
|
|
949
1042
|
import InputAdornment2 from "@mui/material/InputAdornment";
|
|
950
1043
|
import Popover from "@mui/material/Popover";
|
|
951
1044
|
import Search from "@mui/icons-material/Search";
|
|
952
|
-
import
|
|
1045
|
+
import KeyboardArrowDown2 from "@mui/icons-material/KeyboardArrowDown";
|
|
953
1046
|
import Tooltip from "@mui/material/Tooltip";
|
|
954
|
-
import {
|
|
1047
|
+
import {
|
|
1048
|
+
Fragment,
|
|
1049
|
+
createContext,
|
|
1050
|
+
forwardRef as forwardRef4,
|
|
1051
|
+
useCallback as useCallback2,
|
|
1052
|
+
useContext,
|
|
1053
|
+
useEffect as useEffect4,
|
|
1054
|
+
useMemo as useMemo3,
|
|
1055
|
+
useRef as useRef3,
|
|
1056
|
+
useState as useState4
|
|
1057
|
+
} from "react";
|
|
955
1058
|
import { Fragment as Fragment2, jsx as jsx11, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
956
1059
|
import { createElement } from "react";
|
|
957
1060
|
var LSVariableInputContext = createContext({});
|
|
958
|
-
var LSVariableInputProvider = ({
|
|
1061
|
+
var LSVariableInputProvider = ({
|
|
1062
|
+
children,
|
|
1063
|
+
value
|
|
1064
|
+
}) => {
|
|
959
1065
|
return /* @__PURE__ */ jsx11(LSVariableInputContext.Provider, { value, children });
|
|
960
1066
|
};
|
|
961
1067
|
var DEFAULT_FUNCTION_VARIABLES = [
|
|
@@ -1007,7 +1113,9 @@ var renderPrimitiveValue = (value) => {
|
|
|
1007
1113
|
};
|
|
1008
1114
|
var renderComplexPreview = (value) => {
|
|
1009
1115
|
if (Array.isArray(value)) {
|
|
1010
|
-
return `Array(${value.length}) [${value.slice(0, 3).map(
|
|
1116
|
+
return `Array(${value.length}) [${value.slice(0, 3).map(
|
|
1117
|
+
(item) => typeof item === "string" ? `"${item}"` : typeof item === "object" ? "{...}" : String(item)
|
|
1118
|
+
).join(", ")}${value.length > 3 ? "..." : ""}]`;
|
|
1011
1119
|
}
|
|
1012
1120
|
const keys = Object.keys(value);
|
|
1013
1121
|
return `Object {${keys.slice(0, 2).join(", ")}${keys.length > 2 ? "..." : ""}}`;
|
|
@@ -1076,9 +1184,12 @@ var normalizeVariableRecords = (systemVariables) => {
|
|
|
1076
1184
|
};
|
|
1077
1185
|
var defaultTranslate = (key, fallback, options) => {
|
|
1078
1186
|
if (fallback && fallback !== "-") return fallback;
|
|
1079
|
-
if (key === "overlay-variables.variables-description")
|
|
1080
|
-
|
|
1081
|
-
if (key === "overlay-variables.
|
|
1187
|
+
if (key === "overlay-variables.variables-description")
|
|
1188
|
+
return "Use variables that will automatically be replaced before sending out the text";
|
|
1189
|
+
if (key === "overlay-variables.variable" || key === "commands.variable")
|
|
1190
|
+
return "Variable";
|
|
1191
|
+
if (key === "overlay-variables.description" || key === "commands.description")
|
|
1192
|
+
return "Description";
|
|
1082
1193
|
if (key === "commands.suggested-variables") return "Suggested Variables";
|
|
1083
1194
|
if (key === "common.value") return "Value";
|
|
1084
1195
|
if (key === "common.search" || key === "assets.search") return "Search";
|
|
@@ -1104,7 +1215,11 @@ var normalizeAllowedDefinitions = (allowedVariables) => {
|
|
|
1104
1215
|
variableName = variable.trim();
|
|
1105
1216
|
} else if (variable && typeof variable === "object") {
|
|
1106
1217
|
const typedVariable = variable;
|
|
1107
|
-
const candidateName = [
|
|
1218
|
+
const candidateName = [
|
|
1219
|
+
typedVariable.name,
|
|
1220
|
+
typedVariable.key,
|
|
1221
|
+
typedVariable.variable
|
|
1222
|
+
].find((value) => typeof value === "string");
|
|
1108
1223
|
variableName = typeof candidateName === "string" ? candidateName.trim() : "";
|
|
1109
1224
|
description = typeof typedVariable.description === "string" ? typedVariable.description.trim() : void 0;
|
|
1110
1225
|
origin = typeof typedVariable.origin === "string" ? typedVariable.origin.trim().toLowerCase() : void 0;
|
|
@@ -1119,10 +1234,13 @@ var normalizeAllowedDefinitions = (allowedVariables) => {
|
|
|
1119
1234
|
var filter = createFilterOptions({
|
|
1120
1235
|
stringify: (option) => {
|
|
1121
1236
|
if (typeof option === "string") return option;
|
|
1122
|
-
if (typeof option === "number" || typeof option === "boolean" || typeof option === "bigint")
|
|
1237
|
+
if (typeof option === "number" || typeof option === "boolean" || typeof option === "bigint")
|
|
1238
|
+
return String(option);
|
|
1123
1239
|
if (!option || typeof option !== "object") return "";
|
|
1124
1240
|
const typed = option;
|
|
1125
|
-
return [typed.label, typed.value, typed.helperText, typed.searchText].filter(
|
|
1241
|
+
return [typed.label, typed.value, typed.helperText, typed.searchText].filter(
|
|
1242
|
+
(value) => typeof value === "string" || typeof value === "number" || typeof value === "boolean"
|
|
1243
|
+
).map((value) => String(value)).join(" ");
|
|
1126
1244
|
}
|
|
1127
1245
|
});
|
|
1128
1246
|
var visualTypeFromRecord = (variable) => {
|
|
@@ -1136,7 +1254,11 @@ var visualTypeRank = (variableType) => {
|
|
|
1136
1254
|
return 2;
|
|
1137
1255
|
};
|
|
1138
1256
|
var orderItemsByVariableType = (items, getType) => {
|
|
1139
|
-
const grouped = {
|
|
1257
|
+
const grouped = {
|
|
1258
|
+
custom: [],
|
|
1259
|
+
func: [],
|
|
1260
|
+
system: []
|
|
1261
|
+
};
|
|
1140
1262
|
items.forEach((item) => grouped[getType(item)].push(item));
|
|
1141
1263
|
return [...grouped.custom, ...grouped.func, ...grouped.system];
|
|
1142
1264
|
};
|
|
@@ -1152,7 +1274,8 @@ var humanizeVariableName = (rawName) => {
|
|
|
1152
1274
|
return rawName.replace(/^_+|_+$/g, "").replace(/_/g, " ").replace(/\s+/g, " ").trim().replace(/\b\w/g, (char) => char.toUpperCase());
|
|
1153
1275
|
};
|
|
1154
1276
|
var getVariableColorClass = (variableType, isSuggested) => {
|
|
1155
|
-
if (isSuggested && variableType !== "func")
|
|
1277
|
+
if (isSuggested && variableType !== "func")
|
|
1278
|
+
return "ls-variable-token--custom";
|
|
1156
1279
|
if (variableType === "func") return "ls-variable-token--function";
|
|
1157
1280
|
if (variableType === "system") return "ls-variable-token--system";
|
|
1158
1281
|
return "ls-variable-token--custom";
|
|
@@ -1205,8 +1328,14 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1205
1328
|
} = props;
|
|
1206
1329
|
const t = translate ?? context.translate ?? defaultTranslate;
|
|
1207
1330
|
const rawSystemVariables = systemVariablesProp ?? context.systemVariables ?? {};
|
|
1208
|
-
const variableRecords = useMemo3(
|
|
1209
|
-
|
|
1331
|
+
const variableRecords = useMemo3(
|
|
1332
|
+
() => normalizeVariableRecords(rawSystemVariables),
|
|
1333
|
+
[rawSystemVariables]
|
|
1334
|
+
);
|
|
1335
|
+
const functionVariables = useMemo3(
|
|
1336
|
+
() => functionVariablesProp ?? context.functionVariables ?? DEFAULT_FUNCTION_VARIABLES,
|
|
1337
|
+
[context.functionVariables, functionVariablesProp]
|
|
1338
|
+
);
|
|
1210
1339
|
const requestTranslations = onVariableTranslationsNeeded ?? context.onVariableTranslationsNeeded;
|
|
1211
1340
|
const isOriginConnected = isOriginConnectedProp ?? context.isOriginConnected;
|
|
1212
1341
|
const translationKeyExists = translationKeyExistsProp ?? context.translationKeyExists;
|
|
@@ -1214,18 +1343,33 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1214
1343
|
const variableId = useRef3(`variable-input-${name ?? "field"}`);
|
|
1215
1344
|
const [showVariables, setShowVariables] = useState4(false);
|
|
1216
1345
|
const [searchQuery, setSearchQuery] = useState4("");
|
|
1217
|
-
const functionVariableSet = useMemo3(
|
|
1218
|
-
|
|
1346
|
+
const functionVariableSet = useMemo3(
|
|
1347
|
+
() => new Set(functionVariables),
|
|
1348
|
+
[functionVariables]
|
|
1349
|
+
);
|
|
1350
|
+
const allowedVariableDefinitions = useMemo3(
|
|
1351
|
+
() => normalizeAllowedDefinitions(allowedVariables),
|
|
1352
|
+
[allowedVariables]
|
|
1353
|
+
);
|
|
1219
1354
|
const allowedVariableDefinitionLookup = useMemo3(() => {
|
|
1220
1355
|
const lookup = /* @__PURE__ */ new Map();
|
|
1221
|
-
allowedVariableDefinitions.forEach(
|
|
1356
|
+
allowedVariableDefinitions.forEach(
|
|
1357
|
+
(definition) => lookup.set(definition.name, definition)
|
|
1358
|
+
);
|
|
1222
1359
|
return lookup;
|
|
1223
1360
|
}, [allowedVariableDefinitions]);
|
|
1224
|
-
const allowedVariableNames = useMemo3(
|
|
1361
|
+
const allowedVariableNames = useMemo3(
|
|
1362
|
+
() => allowedVariableDefinitions.map((definition) => definition.name),
|
|
1363
|
+
[allowedVariableDefinitions]
|
|
1364
|
+
);
|
|
1225
1365
|
const [filteredAllowedVariables, setFilteredAllowedVariables] = useState4(allowedVariableDefinitions);
|
|
1226
1366
|
const [filteredSystemVariables, setFilteredSystemVariables] = useState4([]);
|
|
1227
|
-
const [expandedPaths, setExpandedPaths] = useState4(
|
|
1228
|
-
|
|
1367
|
+
const [expandedPaths, setExpandedPaths] = useState4(
|
|
1368
|
+
() => /* @__PURE__ */ new Set()
|
|
1369
|
+
);
|
|
1370
|
+
const [autoExpandPaths, setAutoExpandPaths] = useState4(
|
|
1371
|
+
() => /* @__PURE__ */ new Set()
|
|
1372
|
+
);
|
|
1229
1373
|
const systemVariableValueTrees = useMemo3(() => {
|
|
1230
1374
|
const map = /* @__PURE__ */ new Map();
|
|
1231
1375
|
Object.values(variableRecords).forEach((variable) => {
|
|
@@ -1247,7 +1391,10 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1247
1391
|
useEffect4(() => {
|
|
1248
1392
|
requestTranslations?.();
|
|
1249
1393
|
}, [requestTranslations]);
|
|
1250
|
-
const isPathExpanded = useCallback2(
|
|
1394
|
+
const isPathExpanded = useCallback2(
|
|
1395
|
+
(path) => expandedPaths.has(path) || autoExpandPaths.has(path),
|
|
1396
|
+
[autoExpandPaths, expandedPaths]
|
|
1397
|
+
);
|
|
1251
1398
|
const toggleExpand = useCallback2(
|
|
1252
1399
|
(path) => {
|
|
1253
1400
|
const expanded = expandedPaths.has(path) || autoExpandPaths.has(path);
|
|
@@ -1293,12 +1440,16 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1293
1440
|
if (!normalizedNamespace) return null;
|
|
1294
1441
|
const normalizedName = variableName.trim().toLowerCase();
|
|
1295
1442
|
if (!normalizedName) return null;
|
|
1296
|
-
const unprefixedName = normalizedName.startsWith(
|
|
1443
|
+
const unprefixedName = normalizedName.startsWith(
|
|
1444
|
+
`${normalizedNamespace}_`
|
|
1445
|
+
) ? normalizedName.slice(normalizedNamespace.length + 1) : normalizedName;
|
|
1297
1446
|
const prefixedName = normalizedName.startsWith(`${normalizedNamespace}_`) ? normalizedName : `${normalizedNamespace}_${normalizedName}`;
|
|
1298
1447
|
const candidateKeys = [prefixedName, unprefixedName];
|
|
1299
1448
|
for (const key of candidateKeys) {
|
|
1300
|
-
if (namespaceHas(key, normalizedNamespace))
|
|
1301
|
-
|
|
1449
|
+
if (namespaceHas(key, normalizedNamespace))
|
|
1450
|
+
return t(key, void 0, { ns: normalizedNamespace });
|
|
1451
|
+
if (namespaceHas(`variables.${key}`, normalizedNamespace))
|
|
1452
|
+
return t(`variables.${key}`, void 0, { ns: normalizedNamespace });
|
|
1302
1453
|
}
|
|
1303
1454
|
return null;
|
|
1304
1455
|
},
|
|
@@ -1307,7 +1458,9 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1307
1458
|
const knownOrigins = useMemo3(() => {
|
|
1308
1459
|
return Array.from(
|
|
1309
1460
|
new Set(
|
|
1310
|
-
Object.values(variableRecords).map(
|
|
1461
|
+
Object.values(variableRecords).map(
|
|
1462
|
+
(variable) => typeof variable?.origin === "string" ? variable.origin.trim().toLowerCase() : ""
|
|
1463
|
+
).filter((origin) => origin.length > 0)
|
|
1311
1464
|
)
|
|
1312
1465
|
);
|
|
1313
1466
|
}, [variableRecords]);
|
|
@@ -1321,10 +1474,18 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1321
1474
|
if (!normalizedName) return void 0;
|
|
1322
1475
|
const prefixCandidate = normalizedName.split("_")[0];
|
|
1323
1476
|
if (prefixCandidate) {
|
|
1324
|
-
const hasScopedTranslation = namespaceHas(normalizedName, prefixCandidate) || namespaceHas(`variables.${normalizedName}`, prefixCandidate) || namespaceHas(
|
|
1477
|
+
const hasScopedTranslation = namespaceHas(normalizedName, prefixCandidate) || namespaceHas(`variables.${normalizedName}`, prefixCandidate) || namespaceHas(
|
|
1478
|
+
normalizedName.slice(prefixCandidate.length + 1),
|
|
1479
|
+
prefixCandidate
|
|
1480
|
+
) || namespaceHas(
|
|
1481
|
+
`variables.${normalizedName.slice(prefixCandidate.length + 1)}`,
|
|
1482
|
+
prefixCandidate
|
|
1483
|
+
);
|
|
1325
1484
|
if (hasScopedTranslation) return prefixCandidate;
|
|
1326
1485
|
}
|
|
1327
|
-
const prefixedMatch = knownOrigins.find(
|
|
1486
|
+
const prefixedMatch = knownOrigins.find(
|
|
1487
|
+
(origin) => normalizedName.startsWith(`${origin}_`)
|
|
1488
|
+
);
|
|
1328
1489
|
if (prefixedMatch) return prefixedMatch;
|
|
1329
1490
|
const matchingOrigins = knownOrigins.filter(
|
|
1330
1491
|
(origin) => namespaceHas(normalizedName, origin) || namespaceHas(`variables.${normalizedName}`, origin) || namespaceHas(`${origin}_${normalizedName}`, origin)
|
|
@@ -1342,7 +1503,13 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1342
1503
|
);
|
|
1343
1504
|
return inferredOrigins.length === 1 ? inferredOrigins[0] : void 0;
|
|
1344
1505
|
},
|
|
1345
|
-
[
|
|
1506
|
+
[
|
|
1507
|
+
allowedVariableDefinitionLookup,
|
|
1508
|
+
allowedVariableOrigin,
|
|
1509
|
+
knownOrigins,
|
|
1510
|
+
namespaceHas,
|
|
1511
|
+
variableRecords
|
|
1512
|
+
]
|
|
1346
1513
|
);
|
|
1347
1514
|
const resolveVariableDescription = useCallback2(
|
|
1348
1515
|
(variableName, fallbackDescription, origin) => {
|
|
@@ -1350,8 +1517,10 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1350
1517
|
if (fromOrigin && fromOrigin.trim().length > 0) return fromOrigin;
|
|
1351
1518
|
const defaultTranslationKey = `variables.${variableName}`;
|
|
1352
1519
|
const defaultTranslated = t(defaultTranslationKey);
|
|
1353
|
-
if (typeof defaultTranslated === "string" && defaultTranslated !== defaultTranslationKey)
|
|
1354
|
-
|
|
1520
|
+
if (typeof defaultTranslated === "string" && defaultTranslated !== defaultTranslationKey)
|
|
1521
|
+
return defaultTranslated;
|
|
1522
|
+
if (fallbackDescription && fallbackDescription.trim().length > 0)
|
|
1523
|
+
return fallbackDescription;
|
|
1355
1524
|
return humanizeVariableName(variableName);
|
|
1356
1525
|
},
|
|
1357
1526
|
[resolveTranslationFromNamespace, t]
|
|
@@ -1359,9 +1528,16 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1359
1528
|
const getSystemVariableDescription = useCallback2(
|
|
1360
1529
|
(variable) => {
|
|
1361
1530
|
if (variable?.system && !variable?.pluginId) {
|
|
1362
|
-
return t(`variables.${variable.description}`, void 0, {
|
|
1531
|
+
return t(`variables.${variable.description}`, void 0, {
|
|
1532
|
+
example: variable.example,
|
|
1533
|
+
interpolation: { escapeValue: false, prefix: "{{{", suffix: "}}}" }
|
|
1534
|
+
});
|
|
1363
1535
|
}
|
|
1364
|
-
return resolveVariableDescription(
|
|
1536
|
+
return resolveVariableDescription(
|
|
1537
|
+
variable?.name ?? "",
|
|
1538
|
+
variable?.description,
|
|
1539
|
+
variable?.origin
|
|
1540
|
+
);
|
|
1365
1541
|
},
|
|
1366
1542
|
[resolveVariableDescription, t]
|
|
1367
1543
|
);
|
|
@@ -1382,9 +1558,19 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1382
1558
|
if (variable) return getSystemVariableDescription(variable);
|
|
1383
1559
|
const fromDefinition = allowedVariableDefinitionLookup.get(variableName);
|
|
1384
1560
|
const origin = resolveAllowedVariableOrigin(variableName);
|
|
1385
|
-
return resolveVariableDescription(
|
|
1561
|
+
return resolveVariableDescription(
|
|
1562
|
+
variableName,
|
|
1563
|
+
fromDefinition?.description,
|
|
1564
|
+
origin
|
|
1565
|
+
);
|
|
1386
1566
|
},
|
|
1387
|
-
[
|
|
1567
|
+
[
|
|
1568
|
+
allowedVariableDefinitionLookup,
|
|
1569
|
+
getSystemVariableDescription,
|
|
1570
|
+
resolveAllowedVariableOrigin,
|
|
1571
|
+
resolveVariableDescription,
|
|
1572
|
+
variableRecords
|
|
1573
|
+
]
|
|
1388
1574
|
);
|
|
1389
1575
|
const getAllowedVariableValue = useCallback2(
|
|
1390
1576
|
(variableName) => {
|
|
@@ -1440,14 +1626,21 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1440
1626
|
};
|
|
1441
1627
|
if (allowedVariableNames.length > 0) {
|
|
1442
1628
|
if (!query) {
|
|
1443
|
-
setFilteredAllowedVariables(
|
|
1629
|
+
setFilteredAllowedVariables(
|
|
1630
|
+
orderItemsByVariableType(
|
|
1631
|
+
allowedVariableDefinitions,
|
|
1632
|
+
(definition) => getAllowedVariableVisualType(definition.name)
|
|
1633
|
+
)
|
|
1634
|
+
);
|
|
1444
1635
|
} else {
|
|
1445
1636
|
const nameMatches = [];
|
|
1446
1637
|
const descMatches = [];
|
|
1447
1638
|
const nestedMatches = [];
|
|
1448
1639
|
allowedVariableDefinitions.forEach((definition) => {
|
|
1449
1640
|
const nameLower = definition.name?.toLowerCase();
|
|
1450
|
-
const descLower = getAllowedVariableDescription(
|
|
1641
|
+
const descLower = getAllowedVariableDescription(
|
|
1642
|
+
definition.name
|
|
1643
|
+
)?.toLowerCase();
|
|
1451
1644
|
if (nameLower?.includes(query)) {
|
|
1452
1645
|
nameMatches.push(definition);
|
|
1453
1646
|
return;
|
|
@@ -1461,8 +1654,16 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1461
1654
|
nestedMatches.push(definition);
|
|
1462
1655
|
}
|
|
1463
1656
|
});
|
|
1464
|
-
const sortByDef = (items) => sortItemsByVariableTypeThenName(
|
|
1465
|
-
|
|
1657
|
+
const sortByDef = (items) => sortItemsByVariableTypeThenName(
|
|
1658
|
+
items,
|
|
1659
|
+
(definition) => getAllowedVariableVisualType(definition.name),
|
|
1660
|
+
(definition) => definition.name
|
|
1661
|
+
);
|
|
1662
|
+
setFilteredAllowedVariables([
|
|
1663
|
+
...sortByDef(nameMatches),
|
|
1664
|
+
...sortByDef(descMatches),
|
|
1665
|
+
...sortByDef(nestedMatches)
|
|
1666
|
+
]);
|
|
1466
1667
|
}
|
|
1467
1668
|
} else {
|
|
1468
1669
|
setFilteredAllowedVariables([]);
|
|
@@ -1477,7 +1678,12 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1477
1678
|
const allRecords = Object.values(variableRecords);
|
|
1478
1679
|
if (!query) {
|
|
1479
1680
|
const visible = allRecords.filter(shouldKeep);
|
|
1480
|
-
setFilteredSystemVariables(
|
|
1681
|
+
setFilteredSystemVariables(
|
|
1682
|
+
orderItemsByVariableType(
|
|
1683
|
+
visible,
|
|
1684
|
+
(variable) => visualTypeFromRecord(variable)
|
|
1685
|
+
)
|
|
1686
|
+
);
|
|
1481
1687
|
} else {
|
|
1482
1688
|
const nameMatches = [];
|
|
1483
1689
|
const descMatches = [];
|
|
@@ -1500,8 +1706,16 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1500
1706
|
nestedMatches.push(variable);
|
|
1501
1707
|
}
|
|
1502
1708
|
});
|
|
1503
|
-
const sortSys = (items) => sortItemsByVariableTypeThenName(
|
|
1504
|
-
|
|
1709
|
+
const sortSys = (items) => sortItemsByVariableTypeThenName(
|
|
1710
|
+
items,
|
|
1711
|
+
(variable) => visualTypeFromRecord(variable),
|
|
1712
|
+
(variable) => variable?.name ?? ""
|
|
1713
|
+
);
|
|
1714
|
+
setFilteredSystemVariables([
|
|
1715
|
+
...sortSys(nameMatches),
|
|
1716
|
+
...sortSys(descMatches),
|
|
1717
|
+
...sortSys(nestedMatches)
|
|
1718
|
+
]);
|
|
1505
1719
|
}
|
|
1506
1720
|
setAutoExpandPaths(nextAutoExpand);
|
|
1507
1721
|
}, [
|
|
@@ -1532,10 +1746,23 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1532
1746
|
afterFilter?.(filtered);
|
|
1533
1747
|
return filtered;
|
|
1534
1748
|
};
|
|
1535
|
-
const renderVariableToken = (variableName, variableType, isSuggested = false) => /* @__PURE__ */ jsxs5(
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1749
|
+
const renderVariableToken = (variableName, variableType, isSuggested = false) => /* @__PURE__ */ jsxs5(
|
|
1750
|
+
"div",
|
|
1751
|
+
{
|
|
1752
|
+
className: `ls-variable-token ${getVariableColorClass(variableType, isSuggested)}`,
|
|
1753
|
+
children: [
|
|
1754
|
+
/* @__PURE__ */ jsx11("span", { className: "ls-variable-token__name", children: `{{${variableName}}}` }),
|
|
1755
|
+
variableType === "func" && /* @__PURE__ */ jsx11(
|
|
1756
|
+
"span",
|
|
1757
|
+
{
|
|
1758
|
+
className: "ls-variable-token__badge",
|
|
1759
|
+
title: t("variables.functionvariables", "Function variables"),
|
|
1760
|
+
children: "fx"
|
|
1761
|
+
}
|
|
1762
|
+
)
|
|
1763
|
+
]
|
|
1764
|
+
}
|
|
1765
|
+
);
|
|
1539
1766
|
const renderExpandToggle = (path, expanded) => /* @__PURE__ */ jsx11(
|
|
1540
1767
|
"button",
|
|
1541
1768
|
{
|
|
@@ -1547,7 +1774,7 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1547
1774
|
className: `ls-variable-picker__expand-toggle${expanded ? " ls-variable-picker__expand-toggle--expanded" : ""}`,
|
|
1548
1775
|
"aria-label": expanded ? "Collapse" : "Expand",
|
|
1549
1776
|
"aria-expanded": expanded,
|
|
1550
|
-
children: /* @__PURE__ */ jsx11(
|
|
1777
|
+
children: /* @__PURE__ */ jsx11(KeyboardArrowDown2, { style: { width: 16, height: 16 } })
|
|
1551
1778
|
}
|
|
1552
1779
|
);
|
|
1553
1780
|
const renderExpandSpacer = () => /* @__PURE__ */ jsx11("span", { className: "ls-variable-picker__expand-spacer", "aria-hidden": true });
|
|
@@ -1555,6 +1782,19 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1555
1782
|
const { displayValue, fullValue } = getVariableValueDisplay(variableValue);
|
|
1556
1783
|
return { displayValue, fullValue };
|
|
1557
1784
|
};
|
|
1785
|
+
const renderVariableValueInput = (displayValue, fullValue) => /* @__PURE__ */ jsx11(
|
|
1786
|
+
"input",
|
|
1787
|
+
{
|
|
1788
|
+
className: "ls-variable-picker__value-input",
|
|
1789
|
+
title: fullValue,
|
|
1790
|
+
readOnly: true,
|
|
1791
|
+
value: fullValue || displayValue,
|
|
1792
|
+
onClick: (e) => e.stopPropagation(),
|
|
1793
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
1794
|
+
onKeyDown: (e) => e.stopPropagation(),
|
|
1795
|
+
"aria-label": t("common.value", "Value")
|
|
1796
|
+
}
|
|
1797
|
+
);
|
|
1558
1798
|
const renderValueChildRows = (rootToken, nodes) => nodes.map((node) => {
|
|
1559
1799
|
const fullToken = `${rootToken}.${node.relativePath}`;
|
|
1560
1800
|
const expanded = node.isExpandable && isPathExpanded(fullToken);
|
|
@@ -1569,12 +1809,25 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1569
1809
|
else insertVariable(fullToken);
|
|
1570
1810
|
},
|
|
1571
1811
|
children: [
|
|
1572
|
-
/* @__PURE__ */ jsxs5(
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1812
|
+
/* @__PURE__ */ jsxs5(
|
|
1813
|
+
"div",
|
|
1814
|
+
{
|
|
1815
|
+
className: "ls-variable-picker__token-cell",
|
|
1816
|
+
style: { paddingLeft: `${node.depth * 1.25}rem` },
|
|
1817
|
+
children: [
|
|
1818
|
+
node.isExpandable ? renderExpandToggle(fullToken, expanded) : renderExpandSpacer(),
|
|
1819
|
+
/* @__PURE__ */ jsx11(
|
|
1820
|
+
"div",
|
|
1821
|
+
{
|
|
1822
|
+
className: `ls-variable-token ${CHILD_VARIABLE_COLOR_CLASS}`,
|
|
1823
|
+
children: /* @__PURE__ */ jsx11("span", { className: "ls-variable-token__name", children: `{{${fullToken}}}` })
|
|
1824
|
+
}
|
|
1825
|
+
)
|
|
1826
|
+
]
|
|
1827
|
+
}
|
|
1828
|
+
),
|
|
1576
1829
|
/* @__PURE__ */ jsx11("div", { className: "ls-variable-picker__description", children: node.displayKey }),
|
|
1577
|
-
/* @__PURE__ */ jsx11("div", { className: "ls-variable-picker__value", title: fullValue, children: displayValue })
|
|
1830
|
+
/* @__PURE__ */ jsx11("div", { className: "ls-variable-picker__value", title: fullValue, children: renderVariableValueInput(displayValue, fullValue) })
|
|
1578
1831
|
]
|
|
1579
1832
|
}
|
|
1580
1833
|
),
|
|
@@ -1583,15 +1836,18 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1583
1836
|
});
|
|
1584
1837
|
const toOptionLabelString = (input) => {
|
|
1585
1838
|
if (typeof input === "string") return input;
|
|
1586
|
-
if (typeof input === "number" || typeof input === "boolean" || typeof input === "bigint")
|
|
1839
|
+
if (typeof input === "number" || typeof input === "boolean" || typeof input === "bigint")
|
|
1840
|
+
return String(input);
|
|
1587
1841
|
if (input === null || input === void 0) return "";
|
|
1588
1842
|
if (typeof input === "object") {
|
|
1589
1843
|
const labelCandidate = input.label;
|
|
1590
1844
|
if (typeof labelCandidate === "string") return labelCandidate;
|
|
1591
|
-
if (typeof labelCandidate === "number" || typeof labelCandidate === "boolean" || typeof labelCandidate === "bigint")
|
|
1845
|
+
if (typeof labelCandidate === "number" || typeof labelCandidate === "boolean" || typeof labelCandidate === "bigint")
|
|
1846
|
+
return String(labelCandidate);
|
|
1592
1847
|
const valueCandidate = input.value;
|
|
1593
1848
|
if (typeof valueCandidate === "string") return valueCandidate;
|
|
1594
|
-
if (typeof valueCandidate === "number" || typeof valueCandidate === "boolean" || typeof valueCandidate === "bigint")
|
|
1849
|
+
if (typeof valueCandidate === "number" || typeof valueCandidate === "boolean" || typeof valueCandidate === "bigint")
|
|
1850
|
+
return String(valueCandidate);
|
|
1595
1851
|
try {
|
|
1596
1852
|
return JSON.stringify(input);
|
|
1597
1853
|
} catch {
|
|
@@ -1604,7 +1860,9 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1604
1860
|
if (typeof getOptionLabel === "function") {
|
|
1605
1861
|
try {
|
|
1606
1862
|
const customLabel = getOptionLabel(option);
|
|
1607
|
-
return toOptionLabelString(
|
|
1863
|
+
return toOptionLabelString(
|
|
1864
|
+
customLabel === void 0 ? option : customLabel
|
|
1865
|
+
);
|
|
1608
1866
|
} catch {
|
|
1609
1867
|
return toOptionLabelString(option);
|
|
1610
1868
|
}
|
|
@@ -1621,9 +1879,20 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1621
1879
|
{
|
|
1622
1880
|
...optionProps,
|
|
1623
1881
|
key: String(opt?.label ?? opt?.value ?? ""),
|
|
1624
|
-
className:
|
|
1882
|
+
className: [
|
|
1883
|
+
optionProps.className,
|
|
1884
|
+
"ls-variable-option",
|
|
1885
|
+
isSelected ? "ls-variable-option--selected" : ""
|
|
1886
|
+
].filter(Boolean).join(" ")
|
|
1625
1887
|
},
|
|
1626
|
-
thumb ? /* @__PURE__ */ jsx11(
|
|
1888
|
+
thumb ? /* @__PURE__ */ jsx11(
|
|
1889
|
+
"img",
|
|
1890
|
+
{
|
|
1891
|
+
src: thumb,
|
|
1892
|
+
className: "ls-variable-option__thumb",
|
|
1893
|
+
alt: ""
|
|
1894
|
+
}
|
|
1895
|
+
) : null,
|
|
1627
1896
|
/* @__PURE__ */ jsxs5("div", { className: "ls-variable-option__body", children: [
|
|
1628
1897
|
/* @__PURE__ */ jsx11("div", { className: "ls-variable-option__label", children: resolveOptionLabel(opt) }),
|
|
1629
1898
|
helperText ? /* @__PURE__ */ jsx11("div", { className: "ls-variable-option__helper", children: helperText }) : null
|
|
@@ -1633,22 +1902,24 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1633
1902
|
const showSuggestedSection = allowedVariableNames.length > 0 && filteredAllowedVariables.length > 0;
|
|
1634
1903
|
const pickerBody = /* @__PURE__ */ jsxs5("div", { className: "ls-variable-picker ls-variable-picker--three-col", children: [
|
|
1635
1904
|
/* @__PURE__ */ jsxs5("div", { className: "ls-variable-picker__intro", children: [
|
|
1636
|
-
/* @__PURE__ */ jsx11("div", { className: "ls-variable-picker__intro-text", children: t(
|
|
1905
|
+
/* @__PURE__ */ jsx11("div", { className: "ls-variable-picker__intro-text", children: t(
|
|
1906
|
+
"overlay-variables.variables-description",
|
|
1907
|
+
"Use variables that will automatically be replaced before sending out the text"
|
|
1908
|
+
) }),
|
|
1637
1909
|
/* @__PURE__ */ jsx11(
|
|
1638
1910
|
LSInput,
|
|
1639
1911
|
{
|
|
1640
1912
|
autoFocus: true,
|
|
1641
|
-
startAdornment: /* @__PURE__ */ jsx11(Search, { style: { width:
|
|
1913
|
+
startAdornment: /* @__PURE__ */ jsx11(Search, { style: { color: "#fff", width: 20, height: 20 } }),
|
|
1642
1914
|
placeholder: t("common.search", "Search"),
|
|
1643
1915
|
value: searchQuery,
|
|
1644
1916
|
onChange: (e) => setSearchQuery(e.target.value),
|
|
1645
|
-
type: "text"
|
|
1646
|
-
style: { padding: "1rem 0 0" }
|
|
1917
|
+
type: "text"
|
|
1647
1918
|
}
|
|
1648
1919
|
)
|
|
1649
1920
|
] }),
|
|
1650
1921
|
/* @__PURE__ */ jsxs5("div", { className: "ls-variable-picker__header", children: [
|
|
1651
|
-
/* @__PURE__ */ jsx11("div", { children: t("commands.variable", "Variable") }),
|
|
1922
|
+
/* @__PURE__ */ jsx11("div", { style: { paddingLeft: "2.2rem" }, children: t("commands.variable", "Variable") }),
|
|
1652
1923
|
/* @__PURE__ */ jsx11("div", { children: t("commands.description", "Description") }),
|
|
1653
1924
|
/* @__PURE__ */ jsx11("div", { children: t("common.value", "Value") })
|
|
1654
1925
|
] }),
|
|
@@ -1656,9 +1927,13 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1656
1927
|
showSuggestedSection && /* @__PURE__ */ jsxs5("fieldset", { className: "ls-variable-picker__field", children: [
|
|
1657
1928
|
/* @__PURE__ */ jsx11("legend", { className: "ls-variable-picker__legend", children: t("commands.suggested-variables", "Suggested Variables") }),
|
|
1658
1929
|
filteredAllowedVariables.map((definition, idx) => {
|
|
1659
|
-
const variableType = getAllowedVariableVisualType(
|
|
1930
|
+
const variableType = getAllowedVariableVisualType(
|
|
1931
|
+
definition.name
|
|
1932
|
+
);
|
|
1660
1933
|
const tree = getAllowedVariableTree(definition);
|
|
1661
|
-
const { displayValue, fullValue } = getVariableValuePreview(
|
|
1934
|
+
const { displayValue, fullValue } = getVariableValuePreview(
|
|
1935
|
+
getAllowedVariableValue(definition.name) ?? definition.example
|
|
1936
|
+
);
|
|
1662
1937
|
const expandable = !!tree && tree.length > 0;
|
|
1663
1938
|
const expanded = expandable && isPathExpanded(definition.name);
|
|
1664
1939
|
const isLast = idx === filteredAllowedVariables.length - 1;
|
|
@@ -1669,7 +1944,8 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1669
1944
|
{
|
|
1670
1945
|
className: rowCls,
|
|
1671
1946
|
onClick: () => {
|
|
1672
|
-
if (expandable && !expanded)
|
|
1947
|
+
if (expandable && !expanded)
|
|
1948
|
+
toggleExpand(definition.name);
|
|
1673
1949
|
else insertVariable(definition.name);
|
|
1674
1950
|
},
|
|
1675
1951
|
children: [
|
|
@@ -1678,7 +1954,14 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1678
1954
|
renderVariableToken(definition.name, variableType, true)
|
|
1679
1955
|
] }),
|
|
1680
1956
|
/* @__PURE__ */ jsx11("div", { className: "ls-variable-picker__description", children: getAllowedVariableDescription(definition.name) }),
|
|
1681
|
-
/* @__PURE__ */ jsx11(
|
|
1957
|
+
/* @__PURE__ */ jsx11(
|
|
1958
|
+
"div",
|
|
1959
|
+
{
|
|
1960
|
+
className: "ls-variable-picker__value",
|
|
1961
|
+
title: fullValue,
|
|
1962
|
+
children: renderVariableValueInput(displayValue, fullValue)
|
|
1963
|
+
}
|
|
1964
|
+
)
|
|
1682
1965
|
]
|
|
1683
1966
|
}
|
|
1684
1967
|
),
|
|
@@ -1688,7 +1971,9 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1688
1971
|
] }),
|
|
1689
1972
|
filteredSystemVariables?.map((variable) => {
|
|
1690
1973
|
const variableType = visualTypeFromRecord(variable);
|
|
1691
|
-
const { displayValue, fullValue } = getVariableValuePreview(
|
|
1974
|
+
const { displayValue, fullValue } = getVariableValuePreview(
|
|
1975
|
+
variable.value
|
|
1976
|
+
);
|
|
1692
1977
|
const rootToken = variable.example ?? variable.name;
|
|
1693
1978
|
const tree = systemVariableValueTrees.get(variable.name);
|
|
1694
1979
|
const expandable = !!tree && tree.length > 0;
|
|
@@ -1708,7 +1993,7 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1708
1993
|
renderVariableToken(variable.name, variableType)
|
|
1709
1994
|
] }),
|
|
1710
1995
|
/* @__PURE__ */ jsx11("div", { className: "ls-variable-picker__description", children: getSystemVariableDescription(variable) }),
|
|
1711
|
-
/* @__PURE__ */ jsx11("div", { className: "ls-variable-picker__value", title: fullValue, children: displayValue })
|
|
1996
|
+
/* @__PURE__ */ jsx11("div", { className: "ls-variable-picker__value", title: fullValue, children: renderVariableValueInput(displayValue, fullValue) })
|
|
1712
1997
|
]
|
|
1713
1998
|
}
|
|
1714
1999
|
),
|
|
@@ -1739,7 +2024,7 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1739
2024
|
clickedVariableIcon,
|
|
1740
2025
|
inputProps,
|
|
1741
2026
|
allowedVariables,
|
|
1742
|
-
showVariableIcon: !hideVariables,
|
|
2027
|
+
showVariableIcon: !hideVariables && (!isAutoComplete || allowedVariableDefinitions.length > 0),
|
|
1743
2028
|
ref
|
|
1744
2029
|
}
|
|
1745
2030
|
);
|
|
@@ -1761,7 +2046,9 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1761
2046
|
// single source of internal spacing. Adding paper padding on top of
|
|
1762
2047
|
// that compounds the inset and forces premature horizontal scroll.
|
|
1763
2048
|
padding: 0,
|
|
1764
|
-
border: "1px solid var(--neutralDark4, #393853)"
|
|
2049
|
+
border: "1px solid var(--neutralDark4, #393853)",
|
|
2050
|
+
borderRadius: "var(--radius, 1rem)",
|
|
2051
|
+
overflow: "hidden"
|
|
1765
2052
|
}
|
|
1766
2053
|
}
|
|
1767
2054
|
},
|
|
@@ -1810,7 +2097,55 @@ var LSVariableInputField = forwardRef4((props, ref) => {
|
|
|
1810
2097
|
filterOptions: handleFilterOptions,
|
|
1811
2098
|
renderOption: $renderOption ?? renderOption ?? defaultRenderOption,
|
|
1812
2099
|
slots: ListboxComponent ? { listbox: ListboxComponent } : void 0,
|
|
1813
|
-
slotProps: {
|
|
2100
|
+
slotProps: {
|
|
2101
|
+
popper: {
|
|
2102
|
+
className: "ls-variable-autocomplete-popper"
|
|
2103
|
+
},
|
|
2104
|
+
paper: {
|
|
2105
|
+
className: "ls-variable-autocomplete-paper",
|
|
2106
|
+
sx: {
|
|
2107
|
+
border: "1px solid var(--neutralDark4, var(--cardborder, #393853))",
|
|
2108
|
+
borderRadius: "var(--radius, 1rem)",
|
|
2109
|
+
backgroundColor: "var(--neutralDark2, var(--cardbackground, #211f45))",
|
|
2110
|
+
color: "var(--neutralLight1, var(--white, #fff))",
|
|
2111
|
+
boxShadow: "0 16px 32px rgba(0, 0, 0, 0.32)",
|
|
2112
|
+
overflow: "hidden"
|
|
2113
|
+
}
|
|
2114
|
+
},
|
|
2115
|
+
listbox: {
|
|
2116
|
+
className: "ls-variable-autocomplete-listbox",
|
|
2117
|
+
onScroll: onScrollListBox,
|
|
2118
|
+
sx: {
|
|
2119
|
+
padding: "0.25rem 0",
|
|
2120
|
+
backgroundColor: "var(--neutralDark2, var(--cardbackground, #211f45))",
|
|
2121
|
+
color: "var(--neutralLight1, var(--white, #fff))",
|
|
2122
|
+
"& .MuiAutocomplete-option": {
|
|
2123
|
+
display: "flex",
|
|
2124
|
+
minHeight: 44,
|
|
2125
|
+
alignItems: "center",
|
|
2126
|
+
padding: "0.625rem 1rem",
|
|
2127
|
+
color: "var(--neutralLight1, var(--white, #fff))",
|
|
2128
|
+
fontSize: "1rem",
|
|
2129
|
+
lineHeight: 1.35,
|
|
2130
|
+
transition: "background-color 120ms ease, color 120ms ease"
|
|
2131
|
+
},
|
|
2132
|
+
"& .MuiAutocomplete-option:hover, & .MuiAutocomplete-option.Mui-focused, & .MuiAutocomplete-option[data-focus='true'], & .MuiAutocomplete-option[aria-selected='true']": {
|
|
2133
|
+
backgroundColor: "var(--cardHover, var(--transwhite, rgba(255, 255, 255, 0.05)))",
|
|
2134
|
+
color: "var(--neutralLight1, var(--white, #fff))"
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
2137
|
+
},
|
|
2138
|
+
popupIndicator: {
|
|
2139
|
+
className: "ls-variable-autocomplete-popup-indicator",
|
|
2140
|
+
sx: {
|
|
2141
|
+
color: "var(--neutralLight1, var(--white, #fff))",
|
|
2142
|
+
"& svg": {
|
|
2143
|
+
color: "var(--neutralLight1, var(--white, #fff))",
|
|
2144
|
+
fill: "currentColor"
|
|
2145
|
+
}
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
},
|
|
1814
2149
|
onHighlightChange,
|
|
1815
2150
|
onOpen: onPopupOpen,
|
|
1816
2151
|
onClose: onPopupClose,
|
|
@@ -1846,7 +2181,9 @@ var VariableInputTextField = forwardRef4(
|
|
|
1846
2181
|
const paramsInputProps = params?.InputProps ?? {};
|
|
1847
2182
|
const inputPropsSlotInputProps = inputProps?.slotProps?.input ?? {};
|
|
1848
2183
|
const paramsSlotInputProps = params?.slotProps?.input ?? {};
|
|
1849
|
-
const
|
|
2184
|
+
const explicitStartAdornment = inputProps?.startAdornment;
|
|
2185
|
+
const resolvedExplicitStartAdornment = explicitStartAdornment ? /* @__PURE__ */ jsx11(InputAdornment2, { position: "start", children: explicitStartAdornment }) : void 0;
|
|
2186
|
+
const startAdornment = paramsInputProps.startAdornment ?? paramsSlotInputProps.startAdornment ?? inputPropsInputProps.startAdornment ?? inputPropsSlotInputProps.startAdornment ?? resolvedExplicitStartAdornment;
|
|
1850
2187
|
const endAdornment = paramsInputProps.endAdornment ?? paramsSlotInputProps.endAdornment ?? inputPropsInputProps.endAdornment ?? inputPropsSlotInputProps.endAdornment;
|
|
1851
2188
|
return /* @__PURE__ */ jsx11(
|
|
1852
2189
|
LSTextField,
|
|
@@ -1855,7 +2192,7 @@ var VariableInputTextField = forwardRef4(
|
|
|
1855
2192
|
name,
|
|
1856
2193
|
label,
|
|
1857
2194
|
type,
|
|
1858
|
-
color: "
|
|
2195
|
+
color: "primary",
|
|
1859
2196
|
variant,
|
|
1860
2197
|
disabled,
|
|
1861
2198
|
autoFocus,
|
|
@@ -1865,8 +2202,8 @@ var VariableInputTextField = forwardRef4(
|
|
|
1865
2202
|
maxRows,
|
|
1866
2203
|
value,
|
|
1867
2204
|
fullWidth: true,
|
|
1868
|
-
className: `mui-ls-input
|
|
1869
|
-
onChange: onChange ? (
|
|
2205
|
+
className: `mui-ls-input ${params?.className ?? ""} ${inputProps?.className ?? ""}`.trim(),
|
|
2206
|
+
onChange: onChange ? (e) => onChange(e.target.value) : void 0,
|
|
1870
2207
|
...inputProps,
|
|
1871
2208
|
...params,
|
|
1872
2209
|
InputProps: {
|
|
@@ -1877,16 +2214,22 @@ var VariableInputTextField = forwardRef4(
|
|
|
1877
2214
|
startAdornment,
|
|
1878
2215
|
endAdornment: /* @__PURE__ */ jsxs5(Fragment2, { children: [
|
|
1879
2216
|
endAdornment ?? null,
|
|
1880
|
-
showVariableIcon ? /* @__PURE__ */ jsx11(
|
|
1881
|
-
|
|
2217
|
+
showVariableIcon ? /* @__PURE__ */ jsx11(
|
|
2218
|
+
Tooltip,
|
|
1882
2219
|
{
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
2220
|
+
title: t("chatbot.allowed-variables", "Allowed Variables"),
|
|
2221
|
+
children: /* @__PURE__ */ jsx11(
|
|
2222
|
+
InputAdornment2,
|
|
2223
|
+
{
|
|
2224
|
+
position: "end",
|
|
2225
|
+
onClick: clickedVariableIcon,
|
|
2226
|
+
ref: containerRef,
|
|
2227
|
+
className: "ls-variable-input-adornment",
|
|
2228
|
+
children: "{}"
|
|
2229
|
+
}
|
|
2230
|
+
)
|
|
1888
2231
|
}
|
|
1889
|
-
)
|
|
2232
|
+
) : null
|
|
1890
2233
|
] })
|
|
1891
2234
|
},
|
|
1892
2235
|
inputRef: ref
|
|
@@ -2709,7 +3052,2561 @@ var resolveChatterProfileUrlWithResolvers = async ({
|
|
|
2709
3052
|
userId: normalizedUserId || void 0
|
|
2710
3053
|
});
|
|
2711
3054
|
};
|
|
3055
|
+
|
|
3056
|
+
// src/se-import/index.ts
|
|
3057
|
+
import { nanoid as nanoid3 } from "nanoid";
|
|
3058
|
+
|
|
3059
|
+
// src/se-import/translate.ts
|
|
3060
|
+
var SE_TO_LUMIA_PLACEHOLDER = {
|
|
3061
|
+
name: "username",
|
|
3062
|
+
username: "username",
|
|
3063
|
+
displayName: "displayname",
|
|
3064
|
+
sender: "gifter",
|
|
3065
|
+
amount: "amount",
|
|
3066
|
+
currency: "currency",
|
|
3067
|
+
message: "message",
|
|
3068
|
+
items: "itemsDetailed",
|
|
3069
|
+
item: "firstItem.name",
|
|
3070
|
+
count: "amount",
|
|
3071
|
+
total: "total",
|
|
3072
|
+
gifts: "giftAmount"
|
|
3073
|
+
};
|
|
3074
|
+
function listenerPlaceholderContext(listener) {
|
|
3075
|
+
if (listener === "follower-latest") return { name: "twitch_last_follower", username: "twitch_last_follower" };
|
|
3076
|
+
if (listener === "subscriber-latest" || listener === "subscriber-new-latest" || listener === "subscriber-resub-latest") {
|
|
3077
|
+
return { name: "twitch_last_subscriber", username: "twitch_last_subscriber" };
|
|
3078
|
+
}
|
|
3079
|
+
if (listener === "subscriber-gifted-latest") return { name: "twitch_last_gifter", username: "twitch_last_gifter", amount: "twitch_last_gifter_amount", count: "twitch_last_gifter_amount" };
|
|
3080
|
+
if (listener === "subscriber-alltime-gifter") return { name: "twitch_alltime_top_gifter", username: "twitch_alltime_top_gifter", amount: "twitch_alltime_top_gifter_amount", count: "twitch_alltime_top_gifter_amount" };
|
|
3081
|
+
if (listener === "cheer-latest") return { name: "twitch_last_bit", username: "twitch_last_bit", amount: "twitch_last_bit_amount", count: "twitch_last_bit_amount" };
|
|
3082
|
+
if (listener === "tip-latest" || listener === "latest_donator") {
|
|
3083
|
+
return { name: "latest_donator", username: "latest_donator", amount: "latest_donator_amount", count: "latest_donator_amount", currency: "latest_donator_currency_symbol" };
|
|
3084
|
+
}
|
|
3085
|
+
if (listener === "raid-latest") return { name: "twitch_last_raider", username: "twitch_last_raider", amount: "twitch_last_raid_amount", count: "twitch_last_raid_amount" };
|
|
3086
|
+
if (listener === "follower-session") return { amount: "twitch_session_follower_count", count: "twitch_session_follower_count" };
|
|
3087
|
+
if (listener === "subscriber-session") return { amount: "twitch_session_subscribers_count", count: "twitch_session_subscribers_count" };
|
|
3088
|
+
if (listener === "cheer-session") return { amount: "twitch_session_bits_count", count: "twitch_session_bits_count" };
|
|
3089
|
+
if (listener === "tip-session") return { amount: "session_donation_amount", count: "session_donation_count", currency: "session_donation_amount_currency_symbol" };
|
|
3090
|
+
if (listener === "follower-total") return { amount: "twitch_total_follower_count", count: "twitch_total_follower_count" };
|
|
3091
|
+
if (listener === "subscriber-total") return { amount: "twitch_total_subscriber_count", count: "twitch_total_subscriber_count" };
|
|
3092
|
+
if (listener === "cheer-total") return { amount: "twitch_total_bits_count", count: "twitch_total_bits_count" };
|
|
3093
|
+
if (listener === "tip-total") return { amount: "total_donation_amount", count: "total_donation_amount", currency: "total_donation_amount_currency_symbol" };
|
|
3094
|
+
if (listener === "tip-count") return { amount: "donation_count", count: "donation_count" };
|
|
3095
|
+
if (listener === "cheer-session-top-donation") return { amount: "twitch_session_top_cheer_amount", count: "twitch_session_top_cheer_amount" };
|
|
3096
|
+
if (listener === "cheer-session-top-donator") return { name: "twitch_session_top_cheerer", username: "twitch_session_top_cheerer", amount: "twitch_session_top_cheerer_amount", count: "twitch_session_top_cheerer_amount" };
|
|
3097
|
+
if (listener === "tip-session-top-donation") return { amount: "session_top_donator_amount", count: "session_top_donator_amount", currency: "session_top_donator_currency_symbol" };
|
|
3098
|
+
if (listener === "tip-session-top-donator") return { name: "session_top_donator", username: "session_top_donator", amount: "session_top_donator_amount", count: "session_top_donator_amount", currency: "session_top_donator_currency_symbol" };
|
|
3099
|
+
if (listener === "twitch_session_chat_count") return { wins: "twitch_session_chat_count", count: "twitch_session_chat_count", amount: "twitch_session_chat_count" };
|
|
3100
|
+
if (listener === "merch-latest" || listener === "purchase-latest") {
|
|
3101
|
+
return {
|
|
3102
|
+
name: "fourthwall_last_order.username",
|
|
3103
|
+
username: "fourthwall_last_order.username",
|
|
3104
|
+
amount: "fourthwall_last_order.amount",
|
|
3105
|
+
count: "fourthwall_last_order.itemsCount",
|
|
3106
|
+
currency: "fourthwall_last_order.currency",
|
|
3107
|
+
items: "fourthwall_last_order.items",
|
|
3108
|
+
item: "fourthwall_last_order.firstItem.name",
|
|
3109
|
+
message: "fourthwall_last_order.message"
|
|
3110
|
+
};
|
|
3111
|
+
}
|
|
3112
|
+
return {};
|
|
3113
|
+
}
|
|
3114
|
+
function translateSeText(input, listener) {
|
|
3115
|
+
if (!input) return "";
|
|
3116
|
+
const ctx = listener ? listenerPlaceholderContext(listener) : {};
|
|
3117
|
+
return input.replace(/\{([a-zA-Z][a-zA-Z0-9_.]*)\}/g, (_match, raw) => {
|
|
3118
|
+
const mapped = ctx[raw] ?? SE_TO_LUMIA_PLACEHOLDER[raw] ?? raw;
|
|
3119
|
+
return `{{${mapped}}}`;
|
|
3120
|
+
});
|
|
3121
|
+
}
|
|
3122
|
+
function listenerToLumiaVariable(listener) {
|
|
3123
|
+
if (typeof listener !== "string" || !listener) return "username";
|
|
3124
|
+
const m = {
|
|
3125
|
+
// Latest events
|
|
3126
|
+
"follower-latest": "twitch_last_follower",
|
|
3127
|
+
"subscriber-latest": "twitch_last_subscriber",
|
|
3128
|
+
"subscriber-new-latest": "twitch_last_subscriber",
|
|
3129
|
+
"subscriber-resub-latest": "twitch_last_subscriber",
|
|
3130
|
+
"subscriber-gifted-latest": "twitch_last_gifter",
|
|
3131
|
+
"subscriber-alltime-gifter": "twitch_alltime_top_gifter",
|
|
3132
|
+
"tip-latest": "latest_donator",
|
|
3133
|
+
"cheer-latest": "twitch_last_bit",
|
|
3134
|
+
"raid-latest": "twitch_last_raider",
|
|
3135
|
+
// Counters — session / total / week / month
|
|
3136
|
+
"follower-session": "twitch_session_follower_count",
|
|
3137
|
+
"follower-week": "twitch_week_follower_count",
|
|
3138
|
+
"follower-month": "twitch_month_follower_count",
|
|
3139
|
+
"follower-total": "twitch_total_follower_count",
|
|
3140
|
+
"subscriber-session": "twitch_session_subscribers_count",
|
|
3141
|
+
"subscriber-new-session": "twitch_session_new_subscribers_count",
|
|
3142
|
+
"subscriber-resub-session": "twitch_session_resub_subscribers_count",
|
|
3143
|
+
"subscriber-gifted-session": "twitch_session_gifted_subscribers_count",
|
|
3144
|
+
"subscriber-week": "twitch_week_subscriber_count",
|
|
3145
|
+
"subscriber-month": "twitch_month_subscriber_count",
|
|
3146
|
+
"subscriber-total": "twitch_total_subscriber_count",
|
|
3147
|
+
"cheer-session": "twitch_session_bits_count",
|
|
3148
|
+
"cheer-week": "twitch_week_bits_count",
|
|
3149
|
+
"cheer-month": "twitch_month_bits_count",
|
|
3150
|
+
"cheer-total": "twitch_total_bits_count",
|
|
3151
|
+
"tip-session": "session_donation_amount",
|
|
3152
|
+
"tip-week": "week_donation_amount",
|
|
3153
|
+
"tip-month": "month_donation_amount",
|
|
3154
|
+
"tip-total": "total_donation_amount",
|
|
3155
|
+
"tip-count": "donation_count",
|
|
3156
|
+
// Top donors / cheerers — session / week / month / all-time
|
|
3157
|
+
"tip-session-top-donation": "session_top_donator_amount",
|
|
3158
|
+
"tip-session-top-donator": "session_top_donator",
|
|
3159
|
+
"tip-weekly-top-donation": "week_top_donator_amount",
|
|
3160
|
+
"tip-weekly-top-donator": "week_top_donator",
|
|
3161
|
+
"tip-monthly-top-donation": "month_top_donator_amount",
|
|
3162
|
+
"tip-monthly-top-donator": "month_top_donator",
|
|
3163
|
+
"tip-alltime-top-donation": "top_donator_amount",
|
|
3164
|
+
"tip-alltime-top-donator": "top_donator",
|
|
3165
|
+
"cheer-session-top-donation": "twitch_session_top_cheer_amount",
|
|
3166
|
+
"cheer-session-top-donator": "twitch_session_top_cheerer",
|
|
3167
|
+
// Hype train readouts (SE captures these as listener keys on text widgets)
|
|
3168
|
+
"hypetrain-latest": "twitch_hypetrain_total",
|
|
3169
|
+
"hypetrain-level-progress": "twitch_hypetrain_progress",
|
|
3170
|
+
"hypetrain-level-goal": "twitch_hypetrain_level_goal",
|
|
3171
|
+
"hypetrain-total": "twitch_hypetrain_total",
|
|
3172
|
+
"hypetrain-latest-top-contributors": "twitch_hypetrain_top_contributor",
|
|
3173
|
+
"cheer-weekly-top-donation": "twitch_week_top_cheerer_amount",
|
|
3174
|
+
"cheer-weekly-top-donator": "twitch_week_top_cheerer",
|
|
3175
|
+
"cheer-monthly-top-donation": "twitch_month_top_cheerer_amount",
|
|
3176
|
+
"cheer-monthly-top-donator": "twitch_month_top_cheerer",
|
|
3177
|
+
"cheer-alltime-top-donation": "twitch_alltime_top_cheerer_amount",
|
|
3178
|
+
"cheer-alltime-top-donator": "twitch_alltime_top_cheerer"
|
|
3179
|
+
};
|
|
3180
|
+
return m[listener] ?? listener.replace(/-/g, "_");
|
|
3181
|
+
}
|
|
3182
|
+
function seCssToBounds(css, defaults = { width: 600, height: 200 }, canvas) {
|
|
3183
|
+
const toPx = (v, fallback, axis) => {
|
|
3184
|
+
if (v == null) return fallback;
|
|
3185
|
+
if (typeof v === "number") return v;
|
|
3186
|
+
const s = v.trim();
|
|
3187
|
+
if (s === "auto" || s === "") return fallback;
|
|
3188
|
+
if (s.endsWith("%")) {
|
|
3189
|
+
const pct = parseFloat(s);
|
|
3190
|
+
if (canvas && axis && Number.isFinite(pct)) {
|
|
3191
|
+
const base = axis === "width" ? canvas.width : canvas.height;
|
|
3192
|
+
return pct / 100 * base;
|
|
3193
|
+
}
|
|
3194
|
+
return fallback;
|
|
3195
|
+
}
|
|
3196
|
+
const parsed = parseFloat(s);
|
|
3197
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
3198
|
+
};
|
|
3199
|
+
const width = toPx(css.width, defaults.width, "width");
|
|
3200
|
+
const height = toPx(css.height, defaults.height, "height");
|
|
3201
|
+
let x = toPx(css.left, 0, "width");
|
|
3202
|
+
let y = toPx(css.top, 0, "height");
|
|
3203
|
+
if (typeof css.transform === "string" && css.transform.includes("translate")) {
|
|
3204
|
+
const m = /translate\s*\(\s*([^,)]+)\s*(?:,\s*([^)]+))?\s*\)/i.exec(css.transform);
|
|
3205
|
+
if (m) {
|
|
3206
|
+
const parseShift = (raw, basis) => {
|
|
3207
|
+
if (!raw) return 0;
|
|
3208
|
+
const s = raw.trim();
|
|
3209
|
+
if (s.endsWith("%")) {
|
|
3210
|
+
const pct = parseFloat(s);
|
|
3211
|
+
return Number.isFinite(pct) ? pct / 100 * basis : 0;
|
|
3212
|
+
}
|
|
3213
|
+
const px = parseFloat(s);
|
|
3214
|
+
return Number.isFinite(px) ? px : 0;
|
|
3215
|
+
};
|
|
3216
|
+
x += parseShift(m[1], width);
|
|
3217
|
+
y += parseShift(m[2], height);
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
return {
|
|
3221
|
+
x,
|
|
3222
|
+
y,
|
|
3223
|
+
width,
|
|
3224
|
+
height,
|
|
3225
|
+
opacity: css.opacity ?? 1,
|
|
3226
|
+
zIndex: css["z-index"] ?? 0
|
|
3227
|
+
};
|
|
3228
|
+
}
|
|
3229
|
+
var LUMIA_DEFAULT_SIZES = {
|
|
3230
|
+
text: { width: 600, height: 200 },
|
|
3231
|
+
image: { width: 200, height: 200 },
|
|
3232
|
+
video: { width: 400, height: 220 },
|
|
3233
|
+
audio: { width: 200, height: 200 },
|
|
3234
|
+
slideshow: { width: 400, height: 220 },
|
|
3235
|
+
alert: { width: 700, height: 600 },
|
|
3236
|
+
goal: { width: 740, height: 80 },
|
|
3237
|
+
timer: { width: 740, height: 80 },
|
|
3238
|
+
chatbox: { width: 375, height: 470 },
|
|
3239
|
+
eventlist: { width: 375, height: 470 },
|
|
3240
|
+
credits: { width: 700, height: 700 },
|
|
3241
|
+
custom: { width: 700, height: 700 },
|
|
3242
|
+
emotealert: { width: 600, height: 600 },
|
|
3243
|
+
emotebox: { width: 400, height: 400 },
|
|
3244
|
+
nowplaying: { width: 600, height: 250 },
|
|
3245
|
+
spotify: { width: 600, height: 250 },
|
|
3246
|
+
youtubemusic: { width: 600, height: 250 }
|
|
3247
|
+
};
|
|
3248
|
+
function translateVariationCondition(seType, seCondition, requirement) {
|
|
3249
|
+
if (seType === "gift") return { conditionType: "IS_GIFT", condition: 1 };
|
|
3250
|
+
if (seType === "communityGift") return { conditionType: "GIFT_SUB_GREATER", condition: requirement ?? 0 };
|
|
3251
|
+
if (seCondition === "EXACT" && requirement != null) return { conditionType: "EQUAL_NUMBER", condition: requirement };
|
|
3252
|
+
if (seCondition === "ATLEAST" && requirement != null) {
|
|
3253
|
+
return { conditionType: "GREATER_NUMBER", condition: requirement };
|
|
3254
|
+
}
|
|
3255
|
+
return null;
|
|
3256
|
+
}
|
|
3257
|
+
var LUMIA_LAYOUTS = /* @__PURE__ */ new Set(["column", "row", "onlyImage", "onlyText", "imageOver", "textOver"]);
|
|
3258
|
+
function translateLayout(seLayout) {
|
|
3259
|
+
if (seLayout && LUMIA_LAYOUTS.has(seLayout)) return seLayout;
|
|
3260
|
+
return "column";
|
|
3261
|
+
}
|
|
3262
|
+
|
|
3263
|
+
// src/se-import/mappers/build.ts
|
|
3264
|
+
import { nanoid } from "nanoid";
|
|
3265
|
+
var currentImportCanvas = null;
|
|
3266
|
+
function setImportCanvas(canvas) {
|
|
3267
|
+
currentImportCanvas = canvas;
|
|
3268
|
+
}
|
|
3269
|
+
function buildUnit(widget, lumiaType, moduleExtras) {
|
|
3270
|
+
const id = nanoid();
|
|
3271
|
+
const defaults = LUMIA_DEFAULT_SIZES[lumiaType] ?? { width: 400, height: 400 };
|
|
3272
|
+
const bounds = seCssToBounds(widget.css, defaults, currentImportCanvas ?? void 0);
|
|
3273
|
+
const layer = {
|
|
3274
|
+
id,
|
|
3275
|
+
state: { visible: widget.visible ?? true, locked: widget.locked ?? false },
|
|
3276
|
+
bounds: {
|
|
3277
|
+
x: bounds.x,
|
|
3278
|
+
y: bounds.y,
|
|
3279
|
+
width: bounds.width,
|
|
3280
|
+
height: bounds.height,
|
|
3281
|
+
scale: [1, 1],
|
|
3282
|
+
opacity: bounds.opacity,
|
|
3283
|
+
zIndex: bounds.zIndex
|
|
3284
|
+
}
|
|
3285
|
+
};
|
|
3286
|
+
const module = {
|
|
3287
|
+
id,
|
|
3288
|
+
version: 1,
|
|
3289
|
+
settings: {
|
|
3290
|
+
type: lumiaType,
|
|
3291
|
+
title: widget.name ?? null,
|
|
3292
|
+
locked: widget.locked ?? false
|
|
3293
|
+
},
|
|
3294
|
+
lights: [],
|
|
3295
|
+
css: {},
|
|
3296
|
+
content: {},
|
|
3297
|
+
variables: {},
|
|
3298
|
+
events: {},
|
|
3299
|
+
...moduleExtras
|
|
3300
|
+
};
|
|
3301
|
+
return { layer, module };
|
|
3302
|
+
}
|
|
3303
|
+
|
|
3304
|
+
// src/se-import/mappers/basic.ts
|
|
3305
|
+
function mapText(widget) {
|
|
3306
|
+
const value = translateSeText(widget.text?.value ?? "");
|
|
3307
|
+
const seCss = widget.text?.css ?? {};
|
|
3308
|
+
return buildUnit(widget, "text", {
|
|
3309
|
+
content: {
|
|
3310
|
+
value,
|
|
3311
|
+
highlightColor: "inherit"
|
|
3312
|
+
},
|
|
3313
|
+
css: {
|
|
3314
|
+
fontSize: seCss["font-size"] ?? 24,
|
|
3315
|
+
textAlign: seCss["text-align"] ?? "center",
|
|
3316
|
+
fontFamily: seCss["font-family"] ?? "Roboto",
|
|
3317
|
+
fontWeight: seCss["font-weight"] ?? "bold",
|
|
3318
|
+
color: seCss["color"] ?? "#ffffff",
|
|
3319
|
+
textShadow: seCss["text-shadow"] ?? "rgb(0, 0, 0) 1px 1px 1px",
|
|
3320
|
+
lineHeight: seCss["line-height"] ?? 1,
|
|
3321
|
+
background: "transparent"
|
|
3322
|
+
}
|
|
3323
|
+
});
|
|
3324
|
+
}
|
|
3325
|
+
function mapImage(widget) {
|
|
3326
|
+
return buildUnit(widget, "image", {
|
|
3327
|
+
content: {
|
|
3328
|
+
src: widget.image?.src ?? "",
|
|
3329
|
+
loop: true
|
|
3330
|
+
}
|
|
3331
|
+
});
|
|
3332
|
+
}
|
|
3333
|
+
function mapVideo(widget) {
|
|
3334
|
+
return buildUnit(widget, "video", {
|
|
3335
|
+
content: {
|
|
3336
|
+
src: widget.video?.src ?? "",
|
|
3337
|
+
volume: widget.video?.volume ?? 0.5,
|
|
3338
|
+
loop: true,
|
|
3339
|
+
muted: false
|
|
3340
|
+
}
|
|
3341
|
+
});
|
|
3342
|
+
}
|
|
3343
|
+
function mapReadout(widget, fallbackVar) {
|
|
3344
|
+
const explicitListener = widget.variables?.listener;
|
|
3345
|
+
const explicit = typeof explicitListener === "string" ? explicitListener : null;
|
|
3346
|
+
const widgetListener = typeof widget.listener === "string" ? widget.listener : null;
|
|
3347
|
+
const listener = explicit ?? widgetListener ?? fallbackVar;
|
|
3348
|
+
const variable = listenerToLumiaVariable(listener);
|
|
3349
|
+
const userTemplate = widget.text?.value ?? "";
|
|
3350
|
+
const inheritsText = userTemplate.trim().length > 0 && /\{[a-zA-Z]/.test(userTemplate);
|
|
3351
|
+
const value = inheritsText ? translateSeText(userTemplate, listener) : `{{${variable}}}`;
|
|
3352
|
+
const seCss = widget.text?.css ?? {};
|
|
3353
|
+
return buildUnit(widget, "text", {
|
|
3354
|
+
content: { value, highlightColor: "inherit" },
|
|
3355
|
+
css: {
|
|
3356
|
+
fontSize: seCss["font-size"] ?? 28,
|
|
3357
|
+
textAlign: seCss["text-align"] ?? "center",
|
|
3358
|
+
fontFamily: seCss["font-family"] ?? "Roboto",
|
|
3359
|
+
fontWeight: seCss["font-weight"] ?? "bold",
|
|
3360
|
+
color: seCss["color"] ?? "#ffffff",
|
|
3361
|
+
textShadow: seCss["text-shadow"] ?? "rgb(0, 0, 0) 1px 1px 1px",
|
|
3362
|
+
lineHeight: seCss["line-height"] ?? 1,
|
|
3363
|
+
background: "transparent"
|
|
3364
|
+
}
|
|
3365
|
+
});
|
|
3366
|
+
}
|
|
3367
|
+
|
|
3368
|
+
// src/se-import/mappers/alert.ts
|
|
3369
|
+
var SE_EVENT_TO_LUMIA_ALERT = {
|
|
3370
|
+
follower: "twitch-follower",
|
|
3371
|
+
subscriber: "twitch-subscriber",
|
|
3372
|
+
tip: "streamelements-donation",
|
|
3373
|
+
cheer: "twitch-bits",
|
|
3374
|
+
raid: "twitch-raid",
|
|
3375
|
+
// Merch / shop-order — Lumia's Fourthwall integration is the data path most
|
|
3376
|
+
// users now have wired up since SE deprecated their own merch flow in favor
|
|
3377
|
+
// of Fourthwall. `fourthwall-shopOrder` is the alert key from
|
|
3378
|
+
// LumiaAlertValues / activity.types.ts.
|
|
3379
|
+
merch: "fourthwall-shopOrder",
|
|
3380
|
+
purchase: "fourthwall-shopOrder",
|
|
3381
|
+
charityCampaignDonation: "twitch-charityDonation",
|
|
3382
|
+
host: "twitch-raid",
|
|
3383
|
+
redemption: "twitch-redemption"
|
|
3384
|
+
};
|
|
3385
|
+
function pickGraphics(g) {
|
|
3386
|
+
if (!g) return { type: "image", content: { src: "", loop: false, volume: 1 } };
|
|
3387
|
+
return {
|
|
3388
|
+
type: g.type === "video" ? "video" : "image",
|
|
3389
|
+
content: {
|
|
3390
|
+
src: g.src ?? "",
|
|
3391
|
+
loop: false,
|
|
3392
|
+
volume: g.volume ?? 0.5
|
|
3393
|
+
}
|
|
3394
|
+
};
|
|
3395
|
+
}
|
|
3396
|
+
var SE_DEFAULT_DURATION_BY_EVENT = {
|
|
3397
|
+
follower: 5,
|
|
3398
|
+
subscriber: 10,
|
|
3399
|
+
tip: 5,
|
|
3400
|
+
cheer: 5,
|
|
3401
|
+
raid: 8,
|
|
3402
|
+
host: 8,
|
|
3403
|
+
merch: 8,
|
|
3404
|
+
purchase: 8,
|
|
3405
|
+
charityCampaignDonation: 8,
|
|
3406
|
+
redemption: 5
|
|
3407
|
+
};
|
|
3408
|
+
function buildAlertEvent(seEvent, seEventType) {
|
|
3409
|
+
if (!seEvent) {
|
|
3410
|
+
return { on: false, variations: [] };
|
|
3411
|
+
}
|
|
3412
|
+
const text = seEvent.text ?? {};
|
|
3413
|
+
const css = text.css ?? {};
|
|
3414
|
+
const messageCss = css.message ?? {};
|
|
3415
|
+
const highlight = css.highlights ?? {};
|
|
3416
|
+
const variations = (seEvent.variations ?? []).map((variation) => buildAlertVariation(variation, seEventType)).filter((v) => v != null);
|
|
3417
|
+
const defaultDuration = (seEventType && SE_DEFAULT_DURATION_BY_EVENT[seEventType]) ?? 8;
|
|
3418
|
+
return {
|
|
3419
|
+
on: seEvent.enabled !== false,
|
|
3420
|
+
theme: "CUSTOM",
|
|
3421
|
+
themeSettings: {
|
|
3422
|
+
primaryColor: null,
|
|
3423
|
+
accentColor: null,
|
|
3424
|
+
highlightColor: highlight.color ?? null,
|
|
3425
|
+
firstMessageTemplate: translateSeText(text.message ?? "{{username}}"),
|
|
3426
|
+
secondMessageTemplate: "",
|
|
3427
|
+
thirdMessageTemplate: "",
|
|
3428
|
+
showAvatar: false,
|
|
3429
|
+
showAmount: true,
|
|
3430
|
+
showBrandIcon: true
|
|
3431
|
+
},
|
|
3432
|
+
settings: { duration: (seEvent.duration ?? defaultDuration) * 1e3 },
|
|
3433
|
+
layout: { value: translateLayout(seEvent.layout), css: {}, customCss: "" },
|
|
3434
|
+
text: {
|
|
3435
|
+
css: {
|
|
3436
|
+
fontFamily: css["font-family"] ?? "Roboto",
|
|
3437
|
+
fontSize: css["font-size"] ?? 30,
|
|
3438
|
+
color: css.color ?? "#ffffff",
|
|
3439
|
+
fontWeight: css["font-weight"] ?? "bold",
|
|
3440
|
+
textShadow: css["text-shadow"] ?? "rgba(0, 0, 0, 0.8) 1px 1px 1px",
|
|
3441
|
+
textAlign: css["text-align"] ?? "center"
|
|
3442
|
+
},
|
|
3443
|
+
messageCss,
|
|
3444
|
+
content: { value: translateSeText(text.message ?? "") }
|
|
3445
|
+
},
|
|
3446
|
+
media: pickGraphics(seEvent.graphics),
|
|
3447
|
+
audio: {
|
|
3448
|
+
content: {
|
|
3449
|
+
src: seEvent.audio?.src ?? "",
|
|
3450
|
+
volume: seEvent.audio?.volume ?? 0.5
|
|
3451
|
+
}
|
|
3452
|
+
},
|
|
3453
|
+
animations: {
|
|
3454
|
+
alertEnterAnimation: seEvent.animation?.in ?? "fadeIn",
|
|
3455
|
+
alertEnterAnimationDuration: (seEvent.animation?.inDuration ?? 1) * 1e3,
|
|
3456
|
+
alertExitAnimation: seEvent.animation?.out ?? "fadeOut",
|
|
3457
|
+
alertExitAnimationDuration: (seEvent.animation?.outDuration ?? 1) * 1e3,
|
|
3458
|
+
textEnterAnimation: text.animation ?? "",
|
|
3459
|
+
textEnterAnimationDuration: 1e3
|
|
3460
|
+
},
|
|
3461
|
+
tts: {
|
|
3462
|
+
enabled: !!seEvent.tts?.enabled,
|
|
3463
|
+
voice: seEvent.tts?.voice ?? "Brian",
|
|
3464
|
+
volume: seEvent.tts?.volume ?? 0.75,
|
|
3465
|
+
minAmount: seEvent.tts?.minAmount ?? 0
|
|
3466
|
+
},
|
|
3467
|
+
variations
|
|
3468
|
+
};
|
|
3469
|
+
}
|
|
3470
|
+
function buildAlertVariation(v, seEventType) {
|
|
3471
|
+
const translated = translateVariationCondition(v.type ?? null, v.condition ?? null, v.requirement ?? null);
|
|
3472
|
+
if (!translated) return null;
|
|
3473
|
+
const base = buildAlertEvent(v.settings, seEventType);
|
|
3474
|
+
return {
|
|
3475
|
+
name: v.name ?? "Variation",
|
|
3476
|
+
on: v.enabled !== false,
|
|
3477
|
+
randomChance: v.chance ?? 100,
|
|
3478
|
+
conditionType: translated.conditionType,
|
|
3479
|
+
condition: translated.condition,
|
|
3480
|
+
conditionExtra: null,
|
|
3481
|
+
...base
|
|
3482
|
+
};
|
|
3483
|
+
}
|
|
3484
|
+
function mapAlertBox(widget, opts = {}) {
|
|
3485
|
+
const v = widget.variables ?? {};
|
|
3486
|
+
const events = {};
|
|
3487
|
+
const eventKeys = opts.onlyEvents ?? ["follower", "subscriber", "tip", "cheer", "raid", "merch", "purchase", "charityCampaignDonation"];
|
|
3488
|
+
for (const seKey of eventKeys) {
|
|
3489
|
+
const ev = v[seKey];
|
|
3490
|
+
if (!ev || typeof ev !== "object") continue;
|
|
3491
|
+
const lumiaAlert = SE_EVENT_TO_LUMIA_ALERT[seKey];
|
|
3492
|
+
if (!lumiaAlert) continue;
|
|
3493
|
+
events[lumiaAlert] = buildAlertEvent(ev, seKey);
|
|
3494
|
+
}
|
|
3495
|
+
return buildUnit(widget, "alert", { alert: { events } });
|
|
3496
|
+
}
|
|
3497
|
+
function mapSingleAlert(widget, lumiaAlertKey) {
|
|
3498
|
+
const v = widget.variables ?? {};
|
|
3499
|
+
const events = {
|
|
3500
|
+
[lumiaAlertKey]: buildAlertEvent(v)
|
|
3501
|
+
};
|
|
3502
|
+
return buildUnit(widget, "alert", { alert: { events } });
|
|
3503
|
+
}
|
|
3504
|
+
|
|
3505
|
+
// src/se-import/mappers/goal.ts
|
|
3506
|
+
function currentForListener(listener) {
|
|
3507
|
+
if (!listener) return "0";
|
|
3508
|
+
if (listener.startsWith("follower-")) return "{{twitch_total_follower_count}}";
|
|
3509
|
+
if (listener.startsWith("subscriber-")) return "{{twitch_total_subscriber_count}}";
|
|
3510
|
+
if (listener.startsWith("cheer-")) return "{{twitch_total_bits_count}}";
|
|
3511
|
+
if (listener.startsWith("tip-")) return "{{total_donation_amount}}";
|
|
3512
|
+
if (listener.startsWith("merch-")) return "{{fourthwall_total_order_count}}";
|
|
3513
|
+
return "0";
|
|
3514
|
+
}
|
|
3515
|
+
function mapGoal(widget) {
|
|
3516
|
+
const v = widget.variables ?? {};
|
|
3517
|
+
const listener = v.goalListener ?? (typeof widget.listener === "string" ? widget.listener : null);
|
|
3518
|
+
return buildUnit(widget, "goal", {
|
|
3519
|
+
content: {
|
|
3520
|
+
version: 1,
|
|
3521
|
+
// Matches GoalTypes enum in components/Modules/Views/Goal/types.ts.
|
|
3522
|
+
type: "bar",
|
|
3523
|
+
label: translateSeText(v.title ?? "Goal"),
|
|
3524
|
+
subLabel: "",
|
|
3525
|
+
// The Goal module renders this template literal with {{current}} + {{goal}} substituted.
|
|
3526
|
+
display: "{{current}} / {{goal}}",
|
|
3527
|
+
// `current` is a template variable reference (resolved at render time from session variables).
|
|
3528
|
+
// `targetGoal` is the numeric ceiling. Both required by Goal/index.tsx:28-29.
|
|
3529
|
+
current: currentForListener(listener),
|
|
3530
|
+
targetGoal: String(v.goalAmount ?? 100),
|
|
3531
|
+
image: "",
|
|
3532
|
+
audio: { decrement: "", increment: "", goal: "", goalFailed: "", volume: 1 },
|
|
3533
|
+
// `null` (rather than `''`) is the cleaner contract — Goal/index.tsx:11's
|
|
3534
|
+
// `isGoalExpired` treats any falsy as not-expired so both work at render time,
|
|
3535
|
+
// but `null` survives JSON round-trips without ambiguity ('' vs unset).
|
|
3536
|
+
endDate: v.endDate ?? null,
|
|
3537
|
+
goalAnimation: "",
|
|
3538
|
+
goalAnimationLoop: true,
|
|
3539
|
+
unfilledColor: v.backgroundColor ?? "#400022",
|
|
3540
|
+
filledColor: v.fillColor ?? "#ff0055",
|
|
3541
|
+
alignItemsToEdges: false,
|
|
3542
|
+
border: "solid 1px transparent",
|
|
3543
|
+
borderRadius: "40px",
|
|
3544
|
+
highlightColor: "inherit",
|
|
3545
|
+
// SE-only fields preserved as provenance — no native Lumia equivalent.
|
|
3546
|
+
se_source_listener: listener,
|
|
3547
|
+
se_simple_design: !!v.simpleDesign
|
|
3548
|
+
},
|
|
3549
|
+
css: {
|
|
3550
|
+
borderRadius: "0px",
|
|
3551
|
+
borderStyle: "solid",
|
|
3552
|
+
borderWidth: "0px",
|
|
3553
|
+
borderColor: "transparent",
|
|
3554
|
+
lineHeight: 1,
|
|
3555
|
+
fontSize: 30,
|
|
3556
|
+
textAlign: "center",
|
|
3557
|
+
fontFamily: "Roboto",
|
|
3558
|
+
fontWeight: "bold",
|
|
3559
|
+
color: "#ffffff",
|
|
3560
|
+
textShadow: "rgb(0, 0, 0) 1px 1px 1px",
|
|
3561
|
+
background: "transparent"
|
|
3562
|
+
}
|
|
3563
|
+
});
|
|
3564
|
+
}
|
|
3565
|
+
|
|
3566
|
+
// src/se-import/mappers/custom.ts
|
|
3567
|
+
var SE_FIELD_TYPE_TO_LUMIA = {
|
|
3568
|
+
text: "input",
|
|
3569
|
+
number: "number",
|
|
3570
|
+
checkbox: "checkbox",
|
|
3571
|
+
dropdown: "dropdown",
|
|
3572
|
+
slider: "slider",
|
|
3573
|
+
colorpicker: "colorpicker",
|
|
3574
|
+
fontpicker: "fontpicker",
|
|
3575
|
+
image: "input"
|
|
3576
|
+
};
|
|
3577
|
+
function translateConfigs(seFields) {
|
|
3578
|
+
if (!seFields) return [];
|
|
3579
|
+
return Object.entries(seFields).map(([key, f]) => ({
|
|
3580
|
+
key,
|
|
3581
|
+
label: f.label ?? key,
|
|
3582
|
+
type: SE_FIELD_TYPE_TO_LUMIA[f.type ?? "text"] ?? "input",
|
|
3583
|
+
value: f.value,
|
|
3584
|
+
options: f.options
|
|
3585
|
+
}));
|
|
3586
|
+
}
|
|
3587
|
+
function mapCustom(widget) {
|
|
3588
|
+
const v = widget.variables ?? {};
|
|
3589
|
+
const parse = (x) => {
|
|
3590
|
+
if (x == null) return void 0;
|
|
3591
|
+
if (typeof x !== "string") return x;
|
|
3592
|
+
try {
|
|
3593
|
+
return JSON.parse(x);
|
|
3594
|
+
} catch {
|
|
3595
|
+
return void 0;
|
|
3596
|
+
}
|
|
3597
|
+
};
|
|
3598
|
+
const fields = parse(v.fields) ?? v.fields;
|
|
3599
|
+
const fieldData = parse(v.fieldData) ?? v.fieldData;
|
|
3600
|
+
return buildUnit(widget, "custom", {
|
|
3601
|
+
content: {
|
|
3602
|
+
codeId: String(widget.id),
|
|
3603
|
+
html: v.html ?? "",
|
|
3604
|
+
css: v.css ?? "",
|
|
3605
|
+
js: v.js ?? "",
|
|
3606
|
+
configs: translateConfigs(fields),
|
|
3607
|
+
data: fieldData ?? {},
|
|
3608
|
+
flavor: "streamelements"
|
|
3609
|
+
}
|
|
3610
|
+
});
|
|
3611
|
+
}
|
|
3612
|
+
var SEASONAL_TEMPLATE_HTML = '<canvas id="particles"></canvas>';
|
|
3613
|
+
var SEASONAL_TEMPLATE_CSS = `html, body { margin: 0; padding: 0; width: 100%; height: 100%; background: transparent; overflow: hidden; }
|
|
3614
|
+
#particles { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; }`;
|
|
3615
|
+
var SEASONAL_TEMPLATE_JS = `const SEASONS = {
|
|
3616
|
+
snow: { emoji: '\\u2744', count: 80, sizeMin: 14, sizeMax: 28, gravity: 1.0, drift: 0.6, sway: 1.2 },
|
|
3617
|
+
halloween: { emoji: '\\ud83d\\udc7b', count: 25, sizeMin: 28, sizeMax: 44, gravity: 0.6, drift: 0.4, sway: 0.8 },
|
|
3618
|
+
xmas: { emoji: '\\u2744', count: 120, sizeMin: 16, sizeMax: 32, gravity: 1.1, drift: 0.7, sway: 1.3 },
|
|
3619
|
+
valentine: { emoji: '\\u2764\\ufe0f', count: 50, sizeMin: 18, sizeMax: 34, gravity: 0.8, drift: 0.5, sway: 1.0 },
|
|
3620
|
+
easter: { emoji: '\\ud83e\\udd5a', count: 30, sizeMin: 22, sizeMax: 38, gravity: 0.9, drift: 0.3, sway: 0.4 },
|
|
3621
|
+
worldcup: { emoji: '\\u26bd', count: 25, sizeMin: 24, sizeMax: 40, gravity: 1.1, drift: 0.4, sway: 0.5 },
|
|
3622
|
+
};
|
|
3623
|
+
const cfg = SEASONS[(window.DATA && window.DATA.season) || 'snow'] || SEASONS.snow;
|
|
3624
|
+
const canvas = document.getElementById('particles');
|
|
3625
|
+
const ctx = canvas.getContext('2d');
|
|
3626
|
+
const dpr = window.devicePixelRatio || 1;
|
|
3627
|
+
function resize() {
|
|
3628
|
+
canvas.width = window.innerWidth * dpr;
|
|
3629
|
+
canvas.height = window.innerHeight * dpr;
|
|
3630
|
+
canvas.style.width = window.innerWidth + 'px';
|
|
3631
|
+
canvas.style.height = window.innerHeight + 'px';
|
|
3632
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
3633
|
+
}
|
|
3634
|
+
resize();
|
|
3635
|
+
window.addEventListener('resize', resize);
|
|
3636
|
+
const particles = [];
|
|
3637
|
+
for (let i = 0; i < cfg.count; i++) {
|
|
3638
|
+
particles.push({
|
|
3639
|
+
x: Math.random() * window.innerWidth,
|
|
3640
|
+
y: Math.random() * window.innerHeight - window.innerHeight,
|
|
3641
|
+
size: cfg.sizeMin + Math.random() * (cfg.sizeMax - cfg.sizeMin),
|
|
3642
|
+
speed: 0.5 + Math.random() * 1.5,
|
|
3643
|
+
phase: Math.random() * Math.PI * 2,
|
|
3644
|
+
});
|
|
3645
|
+
}
|
|
3646
|
+
function tick(now) {
|
|
3647
|
+
ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
|
|
3648
|
+
const t = now / 1000;
|
|
3649
|
+
for (const p of particles) {
|
|
3650
|
+
p.y += p.speed * cfg.gravity;
|
|
3651
|
+
const sway = Math.sin(t + p.phase) * cfg.sway;
|
|
3652
|
+
if (p.y > window.innerHeight + 40) {
|
|
3653
|
+
p.y = -40;
|
|
3654
|
+
p.x = Math.random() * window.innerWidth;
|
|
3655
|
+
}
|
|
3656
|
+
ctx.font = p.size + 'px serif';
|
|
3657
|
+
ctx.fillText(cfg.emoji, p.x + sway * 20, p.y);
|
|
3658
|
+
}
|
|
3659
|
+
requestAnimationFrame(tick);
|
|
3660
|
+
}
|
|
3661
|
+
requestAnimationFrame(tick);`;
|
|
3662
|
+
function mapSeasonal(widget, season) {
|
|
3663
|
+
return buildUnit(widget, "custom", {
|
|
3664
|
+
content: {
|
|
3665
|
+
codeId: `seasonal-${season}-${widget.id}`,
|
|
3666
|
+
html: SEASONAL_TEMPLATE_HTML,
|
|
3667
|
+
css: SEASONAL_TEMPLATE_CSS,
|
|
3668
|
+
js: SEASONAL_TEMPLATE_JS,
|
|
3669
|
+
configs: [
|
|
3670
|
+
{
|
|
3671
|
+
key: "season",
|
|
3672
|
+
label: "Season",
|
|
3673
|
+
type: "dropdown",
|
|
3674
|
+
value: season,
|
|
3675
|
+
options: { snow: "Snow", halloween: "Halloween", xmas: "Christmas", valentine: "Valentine's", easter: "Easter", worldcup: "World Cup" }
|
|
3676
|
+
}
|
|
3677
|
+
],
|
|
3678
|
+
data: { season },
|
|
3679
|
+
flavor: "lumia-seasonal"
|
|
3680
|
+
}
|
|
3681
|
+
});
|
|
3682
|
+
}
|
|
3683
|
+
|
|
3684
|
+
// src/se-import/mappers/misc.ts
|
|
3685
|
+
function mapChatbox(widget) {
|
|
3686
|
+
const v = widget.variables ?? {};
|
|
3687
|
+
const fadeOutSeconds = typeof v.fadeOut === "number" ? v.fadeOut : 0;
|
|
3688
|
+
return buildUnit(widget, "chatbox", {
|
|
3689
|
+
content: {
|
|
3690
|
+
theme: v.theme ?? "default",
|
|
3691
|
+
fadeOutAfterDelay: fadeOutSeconds > 0,
|
|
3692
|
+
fadeOutDelayTime: fadeOutSeconds,
|
|
3693
|
+
showAvatar: true,
|
|
3694
|
+
// SE `messageDelay` (between-message delay) and `delay` (initial delay) have no
|
|
3695
|
+
// Lumia equivalent today — kept as provenance so users can wire them later if
|
|
3696
|
+
// Lumia adds the feature.
|
|
3697
|
+
se_message_delay: v.messageDelay,
|
|
3698
|
+
se_initial_delay: v.delay,
|
|
3699
|
+
// SE `ignored` (per-user ignore) and `highlight` (per-user emphasis) likewise
|
|
3700
|
+
// have no Lumia equivalent — preserved as provenance only.
|
|
3701
|
+
se_ignored_users: v.ignored,
|
|
3702
|
+
se_highlight_users: v.highlight
|
|
3703
|
+
}
|
|
3704
|
+
});
|
|
3705
|
+
}
|
|
3706
|
+
var SE_LISTENER_TO_LUMIA_CATEGORY = {
|
|
3707
|
+
"follower-latest": "follower",
|
|
3708
|
+
"subscriber-latest": "subscribers",
|
|
3709
|
+
"subscriber-new-latest": "subscribers",
|
|
3710
|
+
"subscriber-resub-latest": "subscribers",
|
|
3711
|
+
"subscriber-gifted-latest": "gifts",
|
|
3712
|
+
"community-gift-latest": "gifts",
|
|
3713
|
+
"cheer-latest": "bits",
|
|
3714
|
+
"cheerPurchase-latest": "bits",
|
|
3715
|
+
"tip-latest": "donation",
|
|
3716
|
+
"raid-latest": "raids",
|
|
3717
|
+
"host-latest": "hosts",
|
|
3718
|
+
"redemption-latest": "redemption",
|
|
3719
|
+
"merch-latest": "purchases",
|
|
3720
|
+
"purchase-latest": "purchases",
|
|
3721
|
+
"superchat-latest": "superchats",
|
|
3722
|
+
"hypetrain-latest": "hypetrain"
|
|
3723
|
+
};
|
|
3724
|
+
var ALL_LUMIA_EVENTLIST_CATEGORIES = [
|
|
3725
|
+
"redemption",
|
|
3726
|
+
"follower",
|
|
3727
|
+
"bits",
|
|
3728
|
+
"kicks",
|
|
3729
|
+
"extension",
|
|
3730
|
+
"points",
|
|
3731
|
+
"donation",
|
|
3732
|
+
"subscribers",
|
|
3733
|
+
"gifts",
|
|
3734
|
+
"hosts",
|
|
3735
|
+
"raids",
|
|
3736
|
+
"hypetrain",
|
|
3737
|
+
"spells",
|
|
3738
|
+
"retweets",
|
|
3739
|
+
"likes",
|
|
3740
|
+
"purchases",
|
|
3741
|
+
"superstickers",
|
|
3742
|
+
"superchats",
|
|
3743
|
+
"stars",
|
|
3744
|
+
"fans",
|
|
3745
|
+
"shares",
|
|
3746
|
+
"raffles",
|
|
3747
|
+
"others"
|
|
3748
|
+
];
|
|
3749
|
+
function computeListenerFilters(seListeners, explicitListener) {
|
|
3750
|
+
const enabled = [];
|
|
3751
|
+
if (seListeners && typeof seListeners === "object" && !Array.isArray(seListeners)) {
|
|
3752
|
+
for (const [k, v] of Object.entries(seListeners)) {
|
|
3753
|
+
if (v) enabled.push(k);
|
|
3754
|
+
}
|
|
3755
|
+
} else if (Array.isArray(seListeners)) {
|
|
3756
|
+
enabled.push(...seListeners);
|
|
3757
|
+
}
|
|
3758
|
+
if (typeof explicitListener === "string" && explicitListener && !enabled.includes(explicitListener)) {
|
|
3759
|
+
enabled.push(explicitListener);
|
|
3760
|
+
}
|
|
3761
|
+
if (enabled.length === 0) return [];
|
|
3762
|
+
const allowed = /* @__PURE__ */ new Set();
|
|
3763
|
+
for (const listener of enabled) {
|
|
3764
|
+
const category = SE_LISTENER_TO_LUMIA_CATEGORY[listener];
|
|
3765
|
+
if (category) allowed.add(category);
|
|
3766
|
+
}
|
|
3767
|
+
if (allowed.size === 0) return [];
|
|
3768
|
+
return ALL_LUMIA_EVENTLIST_CATEGORIES.filter((c) => !allowed.has(c));
|
|
3769
|
+
}
|
|
3770
|
+
function mapEventList(widget) {
|
|
3771
|
+
const v = widget.variables ?? {};
|
|
3772
|
+
const filters = computeListenerFilters(widget.listeners, widget.listener);
|
|
3773
|
+
const maxItems = v.visibleEvents ?? v.visibleItems ?? 5;
|
|
3774
|
+
return buildUnit(widget, "eventlist", {
|
|
3775
|
+
content: {
|
|
3776
|
+
theme: v.theme ?? "simple",
|
|
3777
|
+
direction: v.direction ?? "top",
|
|
3778
|
+
maxItemsToShow: maxItems,
|
|
3779
|
+
visibleEvents: maxItems,
|
|
3780
|
+
// legacy field name kept for back-compat
|
|
3781
|
+
themeBgOpacity: v.themeBgOpacity ?? 0,
|
|
3782
|
+
highlight: v.highlight,
|
|
3783
|
+
// `filters` is a blacklist: every category here is HIDDEN. Empty = show all.
|
|
3784
|
+
filters,
|
|
3785
|
+
// `sites` is a platform blacklist (same shape). Default to "no platforms hidden".
|
|
3786
|
+
sites: [],
|
|
3787
|
+
// Eventlist Manager assumes these objects exist; provide an empty stub so
|
|
3788
|
+
// imported overlays render without throwing.
|
|
3789
|
+
themeConfig: {},
|
|
3790
|
+
eventListType: {},
|
|
3791
|
+
condensedText: false,
|
|
3792
|
+
horizontal: false,
|
|
3793
|
+
showAlertIcon: true,
|
|
3794
|
+
showSiteIcon: true,
|
|
3795
|
+
showUserAvatar: true,
|
|
3796
|
+
showDetailedText: false,
|
|
3797
|
+
hideAlertMessage: false
|
|
3798
|
+
}
|
|
3799
|
+
});
|
|
3800
|
+
}
|
|
3801
|
+
var CREDITS_DEFAULT_EVENTS_TO_SHOW = {
|
|
3802
|
+
mods: false,
|
|
3803
|
+
subscribers: true,
|
|
3804
|
+
gifts: true,
|
|
3805
|
+
donations: true,
|
|
3806
|
+
purchases: true,
|
|
3807
|
+
bits: true,
|
|
3808
|
+
kicks: true,
|
|
3809
|
+
raids: true,
|
|
3810
|
+
hosts: true,
|
|
3811
|
+
superstickers: true,
|
|
3812
|
+
superchats: true,
|
|
3813
|
+
redemptions: true,
|
|
3814
|
+
stars: true,
|
|
3815
|
+
fans: true,
|
|
3816
|
+
shares: false,
|
|
3817
|
+
spells: true,
|
|
3818
|
+
likes: false,
|
|
3819
|
+
followers: true,
|
|
3820
|
+
others: false,
|
|
3821
|
+
topGifts: true,
|
|
3822
|
+
topBits: true,
|
|
3823
|
+
topKicks: true,
|
|
3824
|
+
topDonations: true,
|
|
3825
|
+
topSuperstickers: true,
|
|
3826
|
+
topSuperchats: true,
|
|
3827
|
+
topRedemptions: true
|
|
3828
|
+
};
|
|
3829
|
+
function mapCredits(widget) {
|
|
3830
|
+
const v = widget.variables ?? {};
|
|
3831
|
+
const itemGap = typeof v.padding === "number" ? v.padding : void 0;
|
|
3832
|
+
const reverseFlow = v.direction === "bottom";
|
|
3833
|
+
return buildUnit(widget, "credits", {
|
|
3834
|
+
content: {
|
|
3835
|
+
type: "basic",
|
|
3836
|
+
title: "Stream Credits",
|
|
3837
|
+
subtitle: "",
|
|
3838
|
+
speed: 1,
|
|
3839
|
+
loop: false,
|
|
3840
|
+
eventsToShow: { ...CREDITS_DEFAULT_EVENTS_TO_SHOW },
|
|
3841
|
+
itemGap,
|
|
3842
|
+
reverseFlow,
|
|
3843
|
+
// SE-specific knobs preserved as provenance; no direct Lumia equivalent for
|
|
3844
|
+
// these. `chosenFilter` would narrow eventsToShow if we had a clean mapping;
|
|
3845
|
+
// `separator` would join entries but Lumia credits uses sectioned cards instead.
|
|
3846
|
+
se_chosen_filter: v.chosenFilter,
|
|
3847
|
+
se_separator: v.separator,
|
|
3848
|
+
se_amount: v.amount
|
|
3849
|
+
}
|
|
3850
|
+
});
|
|
3851
|
+
}
|
|
3852
|
+
function mapSlideshow(widget) {
|
|
3853
|
+
const v = widget.variables ?? {};
|
|
3854
|
+
const sources = (v.images ?? []).map((i) => typeof i === "string" ? i : i.src ?? "").filter(Boolean);
|
|
3855
|
+
const seAnim = typeof v.animation === "object" && v.animation !== null ? v.animation : {};
|
|
3856
|
+
return buildUnit(widget, "slideshow", {
|
|
3857
|
+
content: {
|
|
3858
|
+
items: sources.map((src) => ({ src })),
|
|
3859
|
+
// `interval` of 0 = "rapid cycle" in SE (no delay between images); Lumia's
|
|
3860
|
+
// `imageDuration` is the total ms per image. Distinguish three cases:
|
|
3861
|
+
// - undefined → use 5000ms default
|
|
3862
|
+
// - 0 → minimum sane cycle of 100ms (browsers can't render faster than ~60fps anyway)
|
|
3863
|
+
// - >0 → SE seconds * 1000
|
|
3864
|
+
imageDuration: typeof v.interval === "number" ? v.interval === 0 ? 100 : v.interval * 1e3 : 5e3,
|
|
3865
|
+
loop: v.loop !== false,
|
|
3866
|
+
loopDelay: 0,
|
|
3867
|
+
delay: 0,
|
|
3868
|
+
playAudio: !!v.playAudio,
|
|
3869
|
+
random: !!v.random,
|
|
3870
|
+
animation: {
|
|
3871
|
+
enterAnimation: typeof v.animation === "string" ? v.animation : seAnim.in ?? "fadeIn",
|
|
3872
|
+
exitAnimation: typeof v.animation === "string" ? v.animation : seAnim.out ?? "fadeOut",
|
|
3873
|
+
enterAnimationDuration: (seAnim.inDuration ?? 1) * 1e3,
|
|
3874
|
+
exitAnimationDuration: (seAnim.outDuration ?? 1) * 1e3,
|
|
3875
|
+
enterAnimationDelay: (seAnim.inDelay ?? 0) * 1e3,
|
|
3876
|
+
exitAnimationDelay: (seAnim.outDelay ?? 0) * 1e3
|
|
3877
|
+
},
|
|
3878
|
+
se_interval: v.interval,
|
|
3879
|
+
se_raw_duration: v.duration
|
|
3880
|
+
}
|
|
3881
|
+
});
|
|
3882
|
+
}
|
|
3883
|
+
function mapTimer(widget) {
|
|
3884
|
+
const v = widget.variables ?? {};
|
|
3885
|
+
let days = 0, hours = 0, minutes = 5, seconds = 0;
|
|
3886
|
+
let absoluteDate = v.date ?? v.endsAt ?? v.endDate;
|
|
3887
|
+
let resolved = false;
|
|
3888
|
+
if (absoluteDate) {
|
|
3889
|
+
const target = Date.parse(absoluteDate);
|
|
3890
|
+
if (Number.isFinite(target)) {
|
|
3891
|
+
let remainingMs = target - Date.now();
|
|
3892
|
+
if (remainingMs > 0) {
|
|
3893
|
+
const ONE_DAY = 24 * 60 * 60 * 1e3;
|
|
3894
|
+
days = Math.floor(remainingMs / ONE_DAY);
|
|
3895
|
+
remainingMs -= days * ONE_DAY;
|
|
3896
|
+
hours = Math.floor(remainingMs / (60 * 60 * 1e3));
|
|
3897
|
+
remainingMs -= hours * 60 * 60 * 1e3;
|
|
3898
|
+
minutes = Math.floor(remainingMs / (60 * 1e3));
|
|
3899
|
+
remainingMs -= minutes * 60 * 1e3;
|
|
3900
|
+
seconds = Math.floor(remainingMs / 1e3);
|
|
3901
|
+
resolved = true;
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3904
|
+
}
|
|
3905
|
+
if (!resolved && v.duration != null) {
|
|
3906
|
+
if (typeof v.duration === "number" && Number.isFinite(v.duration) && v.duration > 0) {
|
|
3907
|
+
const totalSeconds = Math.floor(v.duration * 60);
|
|
3908
|
+
days = Math.floor(totalSeconds / 86400);
|
|
3909
|
+
hours = Math.floor(totalSeconds % 86400 / 3600);
|
|
3910
|
+
minutes = Math.floor(totalSeconds % 3600 / 60);
|
|
3911
|
+
seconds = totalSeconds % 60;
|
|
3912
|
+
resolved = true;
|
|
3913
|
+
} else if (typeof v.duration === "object" && v.duration !== null) {
|
|
3914
|
+
const d = v.duration;
|
|
3915
|
+
days = typeof d.days === "number" ? d.days : 0;
|
|
3916
|
+
hours = typeof d.hours === "number" ? d.hours : 0;
|
|
3917
|
+
minutes = typeof d.minutes === "number" ? d.minutes : 0;
|
|
3918
|
+
seconds = typeof d.seconds === "number" ? d.seconds : 0;
|
|
3919
|
+
if (days || hours || minutes || seconds) resolved = true;
|
|
3920
|
+
}
|
|
3921
|
+
}
|
|
3922
|
+
if (!resolved) {
|
|
3923
|
+
days = 0;
|
|
3924
|
+
hours = 0;
|
|
3925
|
+
minutes = 5;
|
|
3926
|
+
seconds = 0;
|
|
3927
|
+
}
|
|
3928
|
+
const parts = [];
|
|
3929
|
+
if (v.days !== false) parts.push("{{days}} days");
|
|
3930
|
+
if (v.hours !== false || v.minutes !== false || v.seconds !== false) {
|
|
3931
|
+
const clockBits = [];
|
|
3932
|
+
if (v.hours !== false) clockBits.push("{{hours}}");
|
|
3933
|
+
if (v.minutes !== false) clockBits.push("{{minutes}}");
|
|
3934
|
+
if (v.seconds !== false) clockBits.push("{{seconds}}");
|
|
3935
|
+
if (clockBits.length) parts.push(clockBits.join(":"));
|
|
3936
|
+
}
|
|
3937
|
+
return buildUnit(widget, "timer", {
|
|
3938
|
+
content: {
|
|
3939
|
+
version: 1,
|
|
3940
|
+
type: "countdown",
|
|
3941
|
+
value: { days, hours, minutes, seconds },
|
|
3942
|
+
display: parts.join(" ") || "{{minutes}}:{{seconds}}",
|
|
3943
|
+
showMilliseconds: false,
|
|
3944
|
+
endAnimation: "",
|
|
3945
|
+
hideAfter: 0,
|
|
3946
|
+
messageAfterCountdown: translateSeText(v.messageAfterCountdown ?? ""),
|
|
3947
|
+
changeMessageAfter: !!v.changeMessageAfterCountdown,
|
|
3948
|
+
se_date: v.date,
|
|
3949
|
+
se_exact_time: v.exactTime
|
|
3950
|
+
}
|
|
3951
|
+
});
|
|
3952
|
+
}
|
|
3953
|
+
function mapNowPlaying(widget) {
|
|
3954
|
+
const v = widget.variables ?? {};
|
|
3955
|
+
const source = v.provider === "youtube" ? "youtubemusic" : "spotify";
|
|
3956
|
+
return buildUnit(widget, "nowplaying", {
|
|
3957
|
+
content: {
|
|
3958
|
+
version: 1,
|
|
3959
|
+
type: "nowplaying",
|
|
3960
|
+
source,
|
|
3961
|
+
theme: "basic",
|
|
3962
|
+
borderRadius: "30px",
|
|
3963
|
+
songTitle: `{{${source}_now_playing_song=Lumia Dream}}`,
|
|
3964
|
+
songArtist: `{{${source}_now_playing_artist}}`,
|
|
3965
|
+
songImg: `{{${source}_now_playing_image}}`,
|
|
3966
|
+
showImg: true,
|
|
3967
|
+
oneLineTitle: false,
|
|
3968
|
+
highlightColor: "inherit",
|
|
3969
|
+
se_simple_design: !!v.simpleDesign
|
|
3970
|
+
},
|
|
3971
|
+
css: {
|
|
3972
|
+
borderRadius: "0px",
|
|
3973
|
+
borderStyle: "solid",
|
|
3974
|
+
borderWidth: "0px",
|
|
3975
|
+
borderColor: "transparent",
|
|
3976
|
+
lineHeight: 1,
|
|
3977
|
+
textAlign: "left",
|
|
3978
|
+
fontFamily: "Be Vietnam Pro",
|
|
3979
|
+
color: "#ffffff",
|
|
3980
|
+
textShadow: "rgb(0, 0, 0) 1px 1px 1px",
|
|
3981
|
+
background: "transparent"
|
|
3982
|
+
}
|
|
3983
|
+
});
|
|
3984
|
+
}
|
|
3985
|
+
var SE_KAPPAGEN_EVENT_TO_LUMIA_ALERT = {
|
|
3986
|
+
follower: "twitch-follower",
|
|
3987
|
+
subscriber: "twitch-subscriber",
|
|
3988
|
+
cheer: "twitch-bits",
|
|
3989
|
+
raid: "twitch-raid",
|
|
3990
|
+
host: "twitch-host",
|
|
3991
|
+
tip: "streamelements-donation",
|
|
3992
|
+
purchase: "streamlabs-merch",
|
|
3993
|
+
embers: "youtube-superchat"
|
|
3994
|
+
};
|
|
3995
|
+
function mapKappagen(widget) {
|
|
3996
|
+
const v = widget.variables ?? {};
|
|
3997
|
+
const eventsFromNested = v.eventsConfig ? {
|
|
3998
|
+
subscriber: v.eventsConfig.subscriber?.enabled ?? true,
|
|
3999
|
+
follower: v.eventsConfig.follower?.enabled ?? true,
|
|
4000
|
+
cheer: v.eventsConfig.cheer?.enabled ?? true,
|
|
4001
|
+
raid: v.eventsConfig.raid?.enabled ?? true,
|
|
4002
|
+
tip: v.eventsConfig.tip?.enabled ?? true
|
|
4003
|
+
} : null;
|
|
4004
|
+
const events = v.events ?? eventsFromNested ?? { subscriber: true, follower: true, cheer: true, raid: true, tip: true };
|
|
4005
|
+
const alertTriggers = Object.entries(events).filter(([, enabled]) => !!enabled).map(([seKey]) => SE_KAPPAGEN_EVENT_TO_LUMIA_ALERT[seKey]).filter((x) => !!x);
|
|
4006
|
+
const alertEmotes = ["Kappa", "<3", "imGlitch"];
|
|
4007
|
+
return buildUnit(
|
|
4008
|
+
widget,
|
|
4009
|
+
"emotealert",
|
|
4010
|
+
{
|
|
4011
|
+
content: {
|
|
4012
|
+
version: 1,
|
|
4013
|
+
// Lumia's animation type ('random', 'rise', 'fall', etc.). SE only has rough
|
|
4014
|
+
// equivalents — `direction` maps closest. Default to 'random'.
|
|
4015
|
+
type: v.direction === "up" ? "rise" : v.direction === "down" ? "fall" : "random",
|
|
4016
|
+
excludedAnimations: [],
|
|
4017
|
+
src: "",
|
|
4018
|
+
userLevels: [1, 2, 3, 4, 5, 6, 7, 8, 9],
|
|
4019
|
+
ignoredList: [],
|
|
4020
|
+
emojis: !!v.emoji,
|
|
4021
|
+
background: "transparent",
|
|
4022
|
+
theme: "dark",
|
|
4023
|
+
imageSize: typeof v.size === "number" ? v.size : 30,
|
|
4024
|
+
animationTime: typeof v.duration === "number" ? v.duration : 5,
|
|
4025
|
+
duration: typeof v.duration === "number" ? v.duration : 5,
|
|
4026
|
+
useAnimatedEmotes: true,
|
|
4027
|
+
alertNumberEmotes: typeof v.limit === "number" && v.limit > 0 ? v.limit : 30,
|
|
4028
|
+
alertEmotes,
|
|
4029
|
+
alertTriggers,
|
|
4030
|
+
// Lumia BTTV/FFZ/7TV per-source toggles — read by Emotealert/index.tsx:48.
|
|
4031
|
+
emoteSources: {
|
|
4032
|
+
bttv: v.bttv !== false,
|
|
4033
|
+
ffz: v.ffz !== false,
|
|
4034
|
+
sevenTv: v.sevenTv !== false
|
|
4035
|
+
},
|
|
4036
|
+
// SE-only knobs preserved as provenance; no Lumia rendering for these.
|
|
4037
|
+
se_mode: v.mode,
|
|
4038
|
+
se_cheersplosions: !!v.cheersplosions,
|
|
4039
|
+
se_emotesplosion: v.emotesplosion,
|
|
4040
|
+
se_emotesplosion_dir: v.emotesplosiondir,
|
|
4041
|
+
se_emotesplosion_duration: v.emotesplosionduration,
|
|
4042
|
+
se_spawn_zone: v.spawnzone,
|
|
4043
|
+
se_fullscreen: !!v.fullscreen,
|
|
4044
|
+
se_direction: v.direction
|
|
4045
|
+
},
|
|
4046
|
+
css: { background: "transparent" }
|
|
4047
|
+
}
|
|
4048
|
+
);
|
|
4049
|
+
}
|
|
4050
|
+
function mapLeaderboardFromVariables(widget, currency) {
|
|
4051
|
+
const v = widget.variables ?? {};
|
|
4052
|
+
const count = v.limit ?? v.visibleItems ?? 10;
|
|
4053
|
+
const window = v.period === "weekly" ? "week" : v.period === "monthly" ? "month" : "alltime";
|
|
4054
|
+
const title = currency === "tips" ? "Top Tippers" : currency === "cheers" ? "Top Cheerers" : "Top Gifters";
|
|
4055
|
+
return buildUnit(widget, "loyaltyleaderboard", {
|
|
4056
|
+
content: {
|
|
4057
|
+
source: "variables",
|
|
4058
|
+
currency,
|
|
4059
|
+
window,
|
|
4060
|
+
count,
|
|
4061
|
+
title,
|
|
4062
|
+
showTitle: true,
|
|
4063
|
+
showHeader: false,
|
|
4064
|
+
showCurrentPoints: false,
|
|
4065
|
+
showAllTimePoints: true,
|
|
4066
|
+
itemGap: 8,
|
|
4067
|
+
// Preserve SE knobs that don't map cleanly so they survive the round-trip
|
|
4068
|
+
// and the user can re-introspect later if behaviour differs.
|
|
4069
|
+
se_period: v.period,
|
|
4070
|
+
se_offset: v.offset,
|
|
4071
|
+
se_layout: v.layout
|
|
4072
|
+
}
|
|
4073
|
+
});
|
|
4074
|
+
}
|
|
4075
|
+
function mapGiveaway(widget) {
|
|
4076
|
+
const v = widget.variables ?? {};
|
|
4077
|
+
const primary = v.colors?.primary ?? "#393853";
|
|
4078
|
+
const accent = v.colors?.accent ?? "#FF4076";
|
|
4079
|
+
return buildUnit(widget, "raffle", {
|
|
4080
|
+
content: {
|
|
4081
|
+
version: 1,
|
|
4082
|
+
type: "basic",
|
|
4083
|
+
title: "Play to win",
|
|
4084
|
+
subtitle: "",
|
|
4085
|
+
wonTitle: "{{winner}} just won",
|
|
4086
|
+
showTitle: true,
|
|
4087
|
+
showSubTitle: false,
|
|
4088
|
+
// SE `displayRunningTime` toggles the running-timer label. Lumia's equivalent
|
|
4089
|
+
// is `showTimeSince`. SE `enableTimeOut` enables auto-end which Lumia honours
|
|
4090
|
+
// via raffle.auto_end on the raffle state itself, not the module — best we can
|
|
4091
|
+
// do is leave Lumia's `showTimeSince` on so the countdown is visible.
|
|
4092
|
+
showTimeSince: v.displayRunningTime ?? true,
|
|
4093
|
+
// SE `displayEntrants: false` means "never show the entrant list" (persistent).
|
|
4094
|
+
// Lumia's `hideParticipantOnStart` is "hide until spin starts, then show" (transient).
|
|
4095
|
+
// Mapping one to the other reverses semantics: SE-hidden entrants would briefly
|
|
4096
|
+
// flash on screen the moment the spin starts. Since Lumia has no permanent
|
|
4097
|
+
// hide-entrants knob, keep Lumia at its default (show) and surface the SE
|
|
4098
|
+
// preference via provenance — a future renderer can read it without us
|
|
4099
|
+
// having lied about the toggle. Same for `displayTicketsPurchased`.
|
|
4100
|
+
hideParticipantOnStart: false,
|
|
4101
|
+
se_displayEntrants: v.displayEntrants !== false,
|
|
4102
|
+
se_displayTicketsPurchased: v.displayTicketsPurchased !== false,
|
|
4103
|
+
removeWhenRedeemed: false,
|
|
4104
|
+
showWinningModal: true,
|
|
4105
|
+
playSoundFx: true,
|
|
4106
|
+
spinSound: "https://storage.lumiastream.com/overlays/lumia/audio/Wheel_of_Fortune.mp3",
|
|
4107
|
+
winSound: "https://storage.lumiastream.com/overlays/lumia/audio/crowdClap.mp3",
|
|
4108
|
+
spinDuration: 4,
|
|
4109
|
+
transparent: false,
|
|
4110
|
+
backgroundColor: primary,
|
|
4111
|
+
borderColor: accent,
|
|
4112
|
+
border: "solid 1px transparent",
|
|
4113
|
+
borderRadius: "10px",
|
|
4114
|
+
flashOnNewEntry: true,
|
|
4115
|
+
flashColor: accent,
|
|
4116
|
+
raffleEndedText: "The raffle has ended, and the selection of the winner will take place shortly.",
|
|
4117
|
+
raffleTimerText: "Time since raffle started",
|
|
4118
|
+
raffleCountdownText: "Raffle will end after",
|
|
4119
|
+
// SE-specific knobs with no Lumia equivalent — preserved as provenance.
|
|
4120
|
+
se_timeout: v.timeout,
|
|
4121
|
+
se_enable_timeout: v.enableTimeOut,
|
|
4122
|
+
se_display_entrants: v.displayEntrants,
|
|
4123
|
+
se_display_tickets_purchased: v.displayTicketsPurchased,
|
|
4124
|
+
se_image_style_width: v.imageStyle?.width
|
|
4125
|
+
}
|
|
4126
|
+
});
|
|
4127
|
+
}
|
|
4128
|
+
function mapUnsupportedAsText(widget) {
|
|
4129
|
+
return buildUnit(widget, "text", {
|
|
4130
|
+
content: {
|
|
4131
|
+
value: `[Unsupported SE widget: ${widget.type}]`,
|
|
4132
|
+
highlightColor: "inherit"
|
|
4133
|
+
},
|
|
4134
|
+
css: {
|
|
4135
|
+
color: "#ff8c00",
|
|
4136
|
+
fontSize: 18,
|
|
4137
|
+
textAlign: "center",
|
|
4138
|
+
fontFamily: "Roboto",
|
|
4139
|
+
fontWeight: "bold",
|
|
4140
|
+
background: "rgba(0,0,0,0.4)"
|
|
4141
|
+
}
|
|
4142
|
+
});
|
|
4143
|
+
}
|
|
4144
|
+
|
|
4145
|
+
// src/se-import/feature-flags.ts
|
|
4146
|
+
var SE_IMPORT_FLAGS = {
|
|
4147
|
+
// (Removed) IMPORT_CUSTOM_EMBED: custom-event-list now routes to native eventlist
|
|
4148
|
+
// by default with a one-click "switch to custom HTML" option in the review step.
|
|
4149
|
+
// (Removed) IMPORT_MERCH_GOAL: Fourthwall integration provides session/total order
|
|
4150
|
+
// counters now (see fourthwall.manager.ts ORDER_PLACED handler); merch goal maps
|
|
4151
|
+
// to {{fourthwall_total_order_count}} via the goal mapper.
|
|
4152
|
+
// Merch products rotator — Lumia has no Fourthwall product-list API yet. The
|
|
4153
|
+
// Fourthwall integration is webhook-driven (events flow in) but doesn't fetch
|
|
4154
|
+
// the user's shop catalog. Adding it requires a separate Fourthwall API auth
|
|
4155
|
+
// flow + product-fetch endpoint + periodic refresh. Until then a static stub
|
|
4156
|
+
// is unhelpful, so users are routed to review for AI/skip/marketplace-when-
|
|
4157
|
+
// available replacements.
|
|
4158
|
+
IMPORT_MERCH_PRODUCTS: false,
|
|
4159
|
+
// Seasonal effects (snow/halloween/xmas/valentine/easter/worldcup). The
|
|
4160
|
+
// generic canvas-particle template is approximate, not pixel-accurate vs
|
|
4161
|
+
// SE's polished versions. Flagging off so users get the option to grab a
|
|
4162
|
+
// AI-generated replacement or a curated marketplace seasonal overlay when one
|
|
4163
|
+
// is configured.
|
|
4164
|
+
IMPORT_SEASONAL: false
|
|
4165
|
+
};
|
|
4166
|
+
function isWidgetFlaggedOff(seType) {
|
|
4167
|
+
if (seType === "se-widget-merch-products-rotator") return !SE_IMPORT_FLAGS.IMPORT_MERCH_PRODUCTS;
|
|
4168
|
+
if (seType === "se-widget-snow" || seType === "se-widget-halloween" || seType === "se-widget-halloween-2019" || seType === "se-widget-xmas" || seType === "se-widget-valentine" || seType === "se-widget-easter" || seType === "se-widget-world-cup") {
|
|
4169
|
+
return !SE_IMPORT_FLAGS.IMPORT_SEASONAL;
|
|
4170
|
+
}
|
|
4171
|
+
return false;
|
|
4172
|
+
}
|
|
4173
|
+
var FLAG_OFF_REASONS = {
|
|
4174
|
+
"se-widget-merch-products-rotator": "Merch products rotator \u2014 Lumia tracks Fourthwall orders but doesn't fetch the full product catalog yet. Generate a replacement with AI, skip it, or use Marketplace when a curated replacement is configured.",
|
|
4175
|
+
"se-widget-snow": "Seasonal effect \u2014 the generic auto-import template is approximate. Generate a replacement with AI, skip it, or use Marketplace when a curated version is configured.",
|
|
4176
|
+
"se-widget-halloween": "Seasonal effect \u2014 the generic auto-import template is approximate. Generate a replacement with AI, skip it, or use Marketplace when a curated version is configured.",
|
|
4177
|
+
"se-widget-halloween-2019": "Seasonal effect \u2014 the generic auto-import template is approximate. Generate a replacement with AI, skip it, or use Marketplace when a curated version is configured.",
|
|
4178
|
+
"se-widget-xmas": "Seasonal effect \u2014 the generic auto-import template is approximate. Generate a replacement with AI, skip it, or use Marketplace when a curated version is configured.",
|
|
4179
|
+
"se-widget-valentine": "Seasonal effect \u2014 the generic auto-import template is approximate. Generate a replacement with AI, skip it, or use Marketplace when a curated version is configured.",
|
|
4180
|
+
"se-widget-easter": "Seasonal effect \u2014 the generic auto-import template is approximate. Generate a replacement with AI, skip it, or use Marketplace when a curated version is configured.",
|
|
4181
|
+
"se-widget-world-cup": "Seasonal effect \u2014 the generic auto-import template is approximate. Generate a replacement with AI, skip it, or use Marketplace when a curated version is configured."
|
|
4182
|
+
};
|
|
4183
|
+
|
|
4184
|
+
// src/se-import/dispatcher.ts
|
|
4185
|
+
var READOUT_TYPES = {
|
|
4186
|
+
"follower-latest": "follower-latest",
|
|
4187
|
+
"subscriber-latest": "subscriber-latest",
|
|
4188
|
+
"subscriber-new-latest": "subscriber-new-latest",
|
|
4189
|
+
"subscriber-resub-latest": "subscriber-resub-latest",
|
|
4190
|
+
"subscriber-gifted-latest": "subscriber-gifted-latest",
|
|
4191
|
+
"subscriber-alltime-gifter": "subscriber-alltime-gifter",
|
|
4192
|
+
"cheer-total": "cheer-total",
|
|
4193
|
+
"tip-count": "tip-count",
|
|
4194
|
+
"se-widget-follower-count": "follower-session",
|
|
4195
|
+
"se-widget-follower-total": "follower-total",
|
|
4196
|
+
"se-widget-subscriber-count": "subscriber-session",
|
|
4197
|
+
"se-widget-subscriber-total": "subscriber-total",
|
|
4198
|
+
"se-widget-cheer-amount": "cheer-session",
|
|
4199
|
+
"se-widget-cheer-latest": "cheer-latest",
|
|
4200
|
+
"se-widget-tip-amount": "tip-session",
|
|
4201
|
+
"se-widget-tip-latest": "tip-latest",
|
|
4202
|
+
"se-widget-raid-latest": "raid-latest",
|
|
4203
|
+
"se-widget-top-cheer": "cheer-session-top-donation",
|
|
4204
|
+
"se-widget-top-cheerer": "cheer-session-top-donator",
|
|
4205
|
+
"se-widget-top-donation": "tip-session-top-donation",
|
|
4206
|
+
"se-widget-top-donator": "tip-session-top-donator",
|
|
4207
|
+
// SE's botcounter is just a counter of chat messages; Lumia exposes this directly via
|
|
4208
|
+
// twitch_session_chat_count, so we render it as a text layer with the variable inline.
|
|
4209
|
+
"se-widget-botcounter": "twitch_session_chat_count"
|
|
4210
|
+
};
|
|
4211
|
+
var SEASONAL_TYPES = {
|
|
4212
|
+
"se-widget-snow": "snow",
|
|
4213
|
+
"se-widget-halloween": "halloween",
|
|
4214
|
+
"se-widget-halloween-2019": "halloween",
|
|
4215
|
+
"se-widget-xmas": "xmas",
|
|
4216
|
+
"se-widget-valentine": "valentine",
|
|
4217
|
+
"se-widget-easter": "easter",
|
|
4218
|
+
"se-widget-world-cup": "worldcup"
|
|
4219
|
+
};
|
|
4220
|
+
var GOAL_TYPES = /* @__PURE__ */ new Set([
|
|
4221
|
+
"se-widget-follower-goal",
|
|
4222
|
+
"se-widget-subscriber-goal",
|
|
4223
|
+
"se-widget-cheer-goal",
|
|
4224
|
+
"se-widget-tip-goal",
|
|
4225
|
+
"se-widget-donor-drive-goal",
|
|
4226
|
+
"se-widget-extralife-goal",
|
|
4227
|
+
"se-widget-tiltify-goal",
|
|
4228
|
+
"se-widget-merch-goal"
|
|
4229
|
+
]);
|
|
4230
|
+
var EVENTLIST_TYPES = /* @__PURE__ */ new Set(["se-widget-event-list", "se-widget-follower-recent", "se-widget-subscriber-recent", "se-widget-cheer-recent", "se-widget-tip-recent"]);
|
|
4231
|
+
function dispatch(widget) {
|
|
4232
|
+
const t = widget.type;
|
|
4233
|
+
if (isWidgetFlaggedOff(t)) {
|
|
4234
|
+
return { unit: mapUnsupportedAsText(widget), status: "placeholder", lumiaType: "text", flaggedOff: true };
|
|
4235
|
+
}
|
|
4236
|
+
if (t === "text") return { unit: mapText(widget), status: "direct", lumiaType: "text" };
|
|
4237
|
+
if (t === "image") return { unit: mapImage(widget), status: "direct", lumiaType: "image" };
|
|
4238
|
+
if (t === "video") return { unit: mapVideo(widget), status: "direct", lumiaType: "video" };
|
|
4239
|
+
if (t in READOUT_TYPES) {
|
|
4240
|
+
return { unit: mapReadout(widget, READOUT_TYPES[t]), status: "direct", lumiaType: "text" };
|
|
4241
|
+
}
|
|
4242
|
+
if (GOAL_TYPES.has(t)) return { unit: mapGoal(widget), status: "direct", lumiaType: "goal" };
|
|
4243
|
+
if (t === "se-widget-alert-box") return { unit: mapAlertBox(widget), status: "direct", lumiaType: "alert" };
|
|
4244
|
+
if (t === "se-widget-alert-box-merch") return { unit: mapAlertBox(widget, { onlyEvents: ["merch"] }), status: "direct", lumiaType: "alert" };
|
|
4245
|
+
if (t === "se-widget-store-redemptions") return { unit: mapSingleAlert(widget, "twitch-redemption"), status: "direct", lumiaType: "alert" };
|
|
4246
|
+
if (t === "se-widget-donor-drive-alert") return { unit: mapSingleAlert(widget, "donordrive-donation"), status: "direct", lumiaType: "alert" };
|
|
4247
|
+
if (t === "se-widget-extralife-alert") return { unit: mapSingleAlert(widget, "extralife-donation"), status: "direct", lumiaType: "alert" };
|
|
4248
|
+
if (t === "se-widget-tiltify-alert") return { unit: mapSingleAlert(widget, "tiltify-campaignDonation"), status: "direct", lumiaType: "alert" };
|
|
4249
|
+
if (EVENTLIST_TYPES.has(t)) return { unit: mapEventList(widget), status: "direct", lumiaType: "eventlist" };
|
|
4250
|
+
if (t === "se-widget-top-tippers-list") return { unit: mapLeaderboardFromVariables(widget, "tips"), status: "direct", lumiaType: "loyaltyleaderboard" };
|
|
4251
|
+
if (t === "se-widget-top-cheerers-list") return { unit: mapLeaderboardFromVariables(widget, "cheers"), status: "direct", lumiaType: "loyaltyleaderboard" };
|
|
4252
|
+
if (t === "se-widget-top-gifters-list") return { unit: mapLeaderboardFromVariables(widget, "gifts"), status: "direct", lumiaType: "loyaltyleaderboard" };
|
|
4253
|
+
if (t === "se-widget-credit-roll") return { unit: mapCredits(widget), status: "partial", lumiaType: "credits" };
|
|
4254
|
+
if (t === "se-widget-twitch-chat") return { unit: mapChatbox(widget), status: "partial", lumiaType: "chatbox" };
|
|
4255
|
+
if (t === "se-widget-image-rotator" || t === "se-widget-merch-products-rotator") return { unit: mapSlideshow(widget), status: t === "se-widget-merch-products-rotator" ? "partial" : "direct", lumiaType: "slideshow" };
|
|
4256
|
+
if (t === "se-widget-countdown") return { unit: mapTimer(widget), status: "partial", lumiaType: "timer" };
|
|
4257
|
+
if (t === "se-widget-current-song") return { unit: mapNowPlaying(widget), status: "partial", lumiaType: "nowplaying" };
|
|
4258
|
+
if (t === "se-widget-kappagen") return { unit: mapKappagen(widget), status: "partial", lumiaType: "emotealert" };
|
|
4259
|
+
if (t === "se-widget-giveaway") return { unit: mapGiveaway(widget), status: "direct", lumiaType: "raffle" };
|
|
4260
|
+
if (t === "se-widget-custom-event-list") return { unit: mapCustom(widget), status: "partial", lumiaType: "custom" };
|
|
4261
|
+
if (t in SEASONAL_TYPES) {
|
|
4262
|
+
return { unit: mapSeasonal(widget, SEASONAL_TYPES[t]), status: "direct", lumiaType: "custom" };
|
|
4263
|
+
}
|
|
4264
|
+
return { unit: mapUnsupportedAsText(widget), status: "placeholder", lumiaType: "text" };
|
|
4265
|
+
}
|
|
4266
|
+
function recordCoverage(coverage, result, seType) {
|
|
4267
|
+
const existing = coverage.mappings.find((m) => m.seType === seType);
|
|
4268
|
+
if (existing) {
|
|
4269
|
+
existing.count += 1;
|
|
4270
|
+
return;
|
|
4271
|
+
}
|
|
4272
|
+
coverage.mappings.push({ seType, lumiaType: result.lumiaType, status: result.status, count: 1 });
|
|
4273
|
+
}
|
|
4274
|
+
|
|
4275
|
+
// src/se-import/assets.ts
|
|
4276
|
+
var SE_CDN_REGEX = /https?:\/\/(?:cdn|static)\.streamelements\.com\/[^\s"'\\)]+/g;
|
|
4277
|
+
var SE_CDN_REGEX_ALT = /https?:\/\/streamelements-cdn\.com\/[^\s"'\\)]+/g;
|
|
4278
|
+
var CSS_URL_REGEX = /url\(\s*['"]?([^'")]+)['"]?\s*\)/g;
|
|
4279
|
+
function isSEUrl(url) {
|
|
4280
|
+
return /^https?:\/\/(?:cdn|static)\.streamelements\.com\//.test(url) || /^https?:\/\/streamelements-cdn\.com\//.test(url);
|
|
4281
|
+
}
|
|
4282
|
+
function findSEAssetURLs(overlay) {
|
|
4283
|
+
const settings = overlay.settings ?? {};
|
|
4284
|
+
const found = /* @__PURE__ */ new Set();
|
|
4285
|
+
const serialized = JSON.stringify(settings);
|
|
4286
|
+
for (const m of serialized.match(SE_CDN_REGEX) ?? []) found.add(m);
|
|
4287
|
+
for (const m of serialized.match(SE_CDN_REGEX_ALT) ?? []) found.add(m);
|
|
4288
|
+
const modulesRecord = settings.modules;
|
|
4289
|
+
if (modulesRecord && typeof modulesRecord === "object") {
|
|
4290
|
+
for (const mod of Object.values(modulesRecord)) {
|
|
4291
|
+
const content = mod?.content;
|
|
4292
|
+
if (!content) continue;
|
|
4293
|
+
for (const key of ["html", "css", "js"]) {
|
|
4294
|
+
const blob = content[key];
|
|
4295
|
+
if (typeof blob !== "string" || !blob) continue;
|
|
4296
|
+
CSS_URL_REGEX.lastIndex = 0;
|
|
4297
|
+
let match;
|
|
4298
|
+
while ((match = CSS_URL_REGEX.exec(blob)) !== null) {
|
|
4299
|
+
const inner = match[1];
|
|
4300
|
+
if (inner && isSEUrl(inner)) found.add(inner);
|
|
4301
|
+
}
|
|
4302
|
+
}
|
|
4303
|
+
}
|
|
4304
|
+
}
|
|
4305
|
+
return Array.from(found);
|
|
4306
|
+
}
|
|
4307
|
+
function escapeRegex(s) {
|
|
4308
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
4309
|
+
}
|
|
4310
|
+
function rewriteAssetURLs(overlay, mapping) {
|
|
4311
|
+
const oldUrls = Object.keys(mapping).filter((oldUrl) => oldUrl && mapping[oldUrl] && oldUrl !== mapping[oldUrl]);
|
|
4312
|
+
if (oldUrls.length === 0) return overlay;
|
|
4313
|
+
oldUrls.sort((a, b) => b.length - a.length);
|
|
4314
|
+
const pattern = new RegExp(oldUrls.map(escapeRegex).join("|"), "g");
|
|
4315
|
+
const serialized = JSON.stringify(overlay.settings);
|
|
4316
|
+
const rewritten = serialized.replace(pattern, (match) => mapping[match] ?? match);
|
|
4317
|
+
return {
|
|
4318
|
+
...overlay,
|
|
4319
|
+
settings: JSON.parse(rewritten)
|
|
4320
|
+
};
|
|
4321
|
+
}
|
|
4322
|
+
async function mirrorOneAsset(url, upload, signal) {
|
|
4323
|
+
const res = await fetch(url, { mode: "cors", signal });
|
|
4324
|
+
if (!res.ok) throw new Error(`Source returned HTTP ${res.status}`);
|
|
4325
|
+
const blob = await res.blob();
|
|
4326
|
+
if (signal?.aborted) throw new DOMException("Aborted", "AbortError");
|
|
4327
|
+
const filename = filenameFromURL(url);
|
|
4328
|
+
const type = blob.type || guessMime(filename);
|
|
4329
|
+
const file = new File([blob], filename, { type });
|
|
4330
|
+
const uploaded = await upload(file);
|
|
4331
|
+
const newUrl = uploaded?.asset?.url ?? uploaded?.url;
|
|
4332
|
+
if (!newUrl) throw new Error("Upload succeeded but no URL returned.");
|
|
4333
|
+
return newUrl;
|
|
4334
|
+
}
|
|
4335
|
+
function filenameFromURL(url) {
|
|
4336
|
+
try {
|
|
4337
|
+
const u = new URL(url);
|
|
4338
|
+
const last = u.pathname.split("/").filter(Boolean).pop() || "asset";
|
|
4339
|
+
return decodeURIComponent(last.split("?")[0]);
|
|
4340
|
+
} catch {
|
|
4341
|
+
return "asset";
|
|
4342
|
+
}
|
|
4343
|
+
}
|
|
4344
|
+
function guessMime(name) {
|
|
4345
|
+
const ext = name.split(".").pop()?.toLowerCase() ?? "";
|
|
4346
|
+
switch (ext) {
|
|
4347
|
+
case "webm":
|
|
4348
|
+
return "video/webm";
|
|
4349
|
+
case "mp4":
|
|
4350
|
+
return "video/mp4";
|
|
4351
|
+
case "gif":
|
|
4352
|
+
return "image/gif";
|
|
4353
|
+
case "png":
|
|
4354
|
+
return "image/png";
|
|
4355
|
+
case "jpg":
|
|
4356
|
+
case "jpeg":
|
|
4357
|
+
return "image/jpeg";
|
|
4358
|
+
case "svg":
|
|
4359
|
+
return "image/svg+xml";
|
|
4360
|
+
case "ogg":
|
|
4361
|
+
return "audio/ogg";
|
|
4362
|
+
case "mp3":
|
|
4363
|
+
return "audio/mpeg";
|
|
4364
|
+
case "wav":
|
|
4365
|
+
return "audio/wav";
|
|
4366
|
+
default:
|
|
4367
|
+
return "application/octet-stream";
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
|
|
4371
|
+
// src/se-import/transplant.ts
|
|
4372
|
+
import { nanoid as nanoid2 } from "nanoid";
|
|
4373
|
+
function cloneModuleForTransplant(srcModule, newId) {
|
|
4374
|
+
const clonedContent = srcModule.content ? structuredClone(srcModule.content) : srcModule.content;
|
|
4375
|
+
if (srcModule.settings?.type === "custom" && clonedContent) {
|
|
4376
|
+
clonedContent.codeId = `marketplace-${newId}`;
|
|
4377
|
+
}
|
|
4378
|
+
return {
|
|
4379
|
+
...srcModule,
|
|
4380
|
+
id: newId,
|
|
4381
|
+
content: clonedContent
|
|
4382
|
+
};
|
|
4383
|
+
}
|
|
4384
|
+
function transplantLayer(source, sourceLayerId) {
|
|
4385
|
+
const layers = source.settings?.layers ?? [];
|
|
4386
|
+
const modules = source.settings?.modules ?? {};
|
|
4387
|
+
const srcLayer = layers.find((l) => l.id === sourceLayerId);
|
|
4388
|
+
const srcModule = modules[sourceLayerId];
|
|
4389
|
+
if (!srcLayer || !srcModule) return null;
|
|
4390
|
+
const rootNewId = nanoid2();
|
|
4391
|
+
if (srcLayer.type !== "group") {
|
|
4392
|
+
const layer = { ...srcLayer, id: rootNewId };
|
|
4393
|
+
const module = cloneModuleForTransplant(srcModule, rootNewId);
|
|
4394
|
+
return { layer, module };
|
|
4395
|
+
}
|
|
4396
|
+
const idRemap = /* @__PURE__ */ new Map();
|
|
4397
|
+
idRemap.set(srcLayer.id, rootNewId);
|
|
4398
|
+
const descendants = [];
|
|
4399
|
+
const queue = [srcLayer.id];
|
|
4400
|
+
const seen = /* @__PURE__ */ new Set([srcLayer.id]);
|
|
4401
|
+
while (queue.length > 0) {
|
|
4402
|
+
const parentId = queue.shift();
|
|
4403
|
+
const children = layers.filter((l) => l.group === parentId);
|
|
4404
|
+
for (const child of children) {
|
|
4405
|
+
if (seen.has(child.id)) continue;
|
|
4406
|
+
seen.add(child.id);
|
|
4407
|
+
descendants.push(child);
|
|
4408
|
+
idRemap.set(child.id, nanoid2());
|
|
4409
|
+
if (child.type === "group") queue.push(child.id);
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
const rootLayer = { ...srcLayer, id: rootNewId };
|
|
4413
|
+
const rootModule = cloneModuleForTransplant(srcModule, rootNewId);
|
|
4414
|
+
const extras = [];
|
|
4415
|
+
for (const descLayer of descendants) {
|
|
4416
|
+
const descModule = modules[descLayer.id];
|
|
4417
|
+
if (!descModule) continue;
|
|
4418
|
+
const newDescId = idRemap.get(descLayer.id);
|
|
4419
|
+
const remappedGroup = descLayer.group != null ? idRemap.get(descLayer.group) ?? null : null;
|
|
4420
|
+
const newLayer = {
|
|
4421
|
+
...descLayer,
|
|
4422
|
+
id: newDescId,
|
|
4423
|
+
group: remappedGroup
|
|
4424
|
+
};
|
|
4425
|
+
const newModule = cloneModuleForTransplant(descModule, newDescId);
|
|
4426
|
+
extras.push({ layer: newLayer, module: newModule });
|
|
4427
|
+
}
|
|
4428
|
+
return { layer: rootLayer, module: rootModule, extras };
|
|
4429
|
+
}
|
|
4430
|
+
function listTransplantableLayers(source) {
|
|
4431
|
+
const layers = source.settings?.layers ?? [];
|
|
4432
|
+
const modules = source.settings?.modules ?? {};
|
|
4433
|
+
return layers.map((l) => {
|
|
4434
|
+
const m = modules[l.id];
|
|
4435
|
+
if (!m) return null;
|
|
4436
|
+
return {
|
|
4437
|
+
id: l.id,
|
|
4438
|
+
label: m.settings?.title ?? m.settings?.type ?? "Untitled",
|
|
4439
|
+
type: m.settings?.type ?? "unknown"
|
|
4440
|
+
};
|
|
4441
|
+
}).filter((x) => x !== null);
|
|
4442
|
+
}
|
|
4443
|
+
|
|
4444
|
+
// src/se-import/marketplace-candidates.ts
|
|
4445
|
+
var SE_WIDGET_TO_MARKETPLACE_CANDIDATES = {
|
|
4446
|
+
// Hard widgets — gamified animations with state machines or physics. Highest
|
|
4447
|
+
// value for marketplace replacements since AI generation rarely produces
|
|
4448
|
+
// satisfying results for these.
|
|
4449
|
+
"se-widget-hype-cup": [],
|
|
4450
|
+
"se-widget-bit-boss": [],
|
|
4451
|
+
"se-widget-train": [],
|
|
4452
|
+
// Medium-difficulty widgets — possible to AI-generate but a curated overlay
|
|
4453
|
+
// will usually look better.
|
|
4454
|
+
"se-widget-media-share": [],
|
|
4455
|
+
"se-widget-contest": [],
|
|
4456
|
+
// Bot counters, custom event lists, and one-off SE widgets users sometimes
|
|
4457
|
+
// have curated replacements for.
|
|
4458
|
+
"se-widget-custom-event-list": [],
|
|
4459
|
+
"se-widget-botcounter": [],
|
|
4460
|
+
// Flagged-off in feature-flags.ts — the auto-import is disabled because
|
|
4461
|
+
// Lumia has no merch data source. Marketplace overlays here would be
|
|
4462
|
+
// curated static merch-style goals/sliders that don't depend on a feed.
|
|
4463
|
+
"se-widget-merch-goal": [],
|
|
4464
|
+
"se-widget-merch-products-rotator": [],
|
|
4465
|
+
// Flagged-off seasonal effects — generic canvas-particle template is too
|
|
4466
|
+
// approximate. Marketplace candidates should be polished season-specific
|
|
4467
|
+
// overlays (e.g. a curated snow scene, a haunted-house halloween scene).
|
|
4468
|
+
"se-widget-snow": [],
|
|
4469
|
+
"se-widget-halloween": [],
|
|
4470
|
+
"se-widget-halloween-2019": [],
|
|
4471
|
+
"se-widget-xmas": [],
|
|
4472
|
+
"se-widget-valentine": [],
|
|
4473
|
+
"se-widget-easter": [],
|
|
4474
|
+
"se-widget-world-cup": []
|
|
4475
|
+
};
|
|
4476
|
+
function getMarketplaceCandidates(seWidgetType) {
|
|
4477
|
+
return SE_WIDGET_TO_MARKETPLACE_CANDIDATES[seWidgetType] ?? [];
|
|
4478
|
+
}
|
|
4479
|
+
function hasMarketplaceCandidates(seWidgetType) {
|
|
4480
|
+
return getMarketplaceCandidates(seWidgetType).length > 0;
|
|
4481
|
+
}
|
|
4482
|
+
|
|
4483
|
+
// src/se-import/ui/SEImportWizard.tsx
|
|
4484
|
+
import { useCallback as useCallback3, useEffect as useEffect6, useMemo as useMemo5, useRef as useRef4, useState as useState6 } from "react";
|
|
4485
|
+
|
|
4486
|
+
// src/se-import/ui/MarketplacePicker.tsx
|
|
4487
|
+
import { useEffect as useEffect5, useMemo as useMemo4, useState as useState5 } from "react";
|
|
4488
|
+
import { jsx as jsx12, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
4489
|
+
function MarketplacePicker({ seWidgetType, fetchMarketplaceOverlay, CustomEmbed, onPick, onCancel }) {
|
|
4490
|
+
const candidateIds = useMemo4(() => getMarketplaceCandidates(seWidgetType), [seWidgetType]);
|
|
4491
|
+
const [candidates, setCandidates] = useState5(() => candidateIds.map((id) => ({ id, loading: true })));
|
|
4492
|
+
const [activeId, setActiveId] = useState5(candidateIds[0] ?? null);
|
|
4493
|
+
const [activeLayerId, setActiveLayerId] = useState5(null);
|
|
4494
|
+
useEffect5(() => {
|
|
4495
|
+
let cancelled = false;
|
|
4496
|
+
candidateIds.forEach(async (id) => {
|
|
4497
|
+
try {
|
|
4498
|
+
const overlay = await fetchMarketplaceOverlay(id);
|
|
4499
|
+
if (cancelled) return;
|
|
4500
|
+
setCandidates((prev) => prev.map((c) => c.id === id ? { ...c, loading: false, overlay } : c));
|
|
4501
|
+
} catch (err) {
|
|
4502
|
+
if (cancelled) return;
|
|
4503
|
+
setCandidates((prev) => prev.map((c) => c.id === id ? { ...c, loading: false, error: err?.message ?? "Failed to fetch overlay." } : c));
|
|
4504
|
+
}
|
|
4505
|
+
});
|
|
4506
|
+
return () => {
|
|
4507
|
+
cancelled = true;
|
|
4508
|
+
};
|
|
4509
|
+
}, [candidateIds, fetchMarketplaceOverlay]);
|
|
4510
|
+
const activeCandidate = candidates.find((c) => c.id === activeId);
|
|
4511
|
+
const activeLayers = useMemo4(() => activeCandidate?.overlay ? listTransplantableLayers(activeCandidate.overlay) : [], [activeCandidate?.overlay]);
|
|
4512
|
+
useEffect5(() => {
|
|
4513
|
+
if (activeLayers.length > 0 && !activeLayerId) {
|
|
4514
|
+
setActiveLayerId(activeLayers[0].id);
|
|
4515
|
+
}
|
|
4516
|
+
}, [activeLayers, activeLayerId]);
|
|
4517
|
+
const handleConfirm = () => {
|
|
4518
|
+
if (!activeCandidate?.overlay || !activeLayerId) return;
|
|
4519
|
+
const transplant = transplantLayer(activeCandidate.overlay, activeLayerId);
|
|
4520
|
+
if (!transplant) return;
|
|
4521
|
+
onPick(transplant);
|
|
4522
|
+
};
|
|
4523
|
+
if (candidateIds.length === 0) {
|
|
4524
|
+
return /* @__PURE__ */ jsxs6("div", { className: "ui-flex-column ui-gap-2", style: { padding: 16 }, children: [
|
|
4525
|
+
/* @__PURE__ */ jsx12("div", { style: { fontWeight: 600 }, children: "No marketplace replacements yet" }),
|
|
4526
|
+
/* @__PURE__ */ jsxs6("div", { style: { fontSize: 13, opacity: 0.8 }, children: [
|
|
4527
|
+
"No curated marketplace overlays are listed for ",
|
|
4528
|
+
/* @__PURE__ */ jsx12("code", { children: seWidgetType }),
|
|
4529
|
+
" yet. Use AI generation or skip the widget for now."
|
|
4530
|
+
] }),
|
|
4531
|
+
/* @__PURE__ */ jsx12("div", { className: "ui-flex-row", style: { marginTop: 8 }, children: /* @__PURE__ */ jsx12("button", { type: "button", className: "ui-button", onClick: onCancel, children: "Close" }) })
|
|
4532
|
+
] });
|
|
4533
|
+
}
|
|
4534
|
+
return /* @__PURE__ */ jsxs6("div", { className: "ui-flex-column ui-gap-2", style: { padding: 16, minHeight: 420 }, children: [
|
|
4535
|
+
/* @__PURE__ */ jsx12("div", { style: { fontWeight: 600, fontSize: 16 }, children: "Pick a marketplace replacement" }),
|
|
4536
|
+
/* @__PURE__ */ jsxs6("div", { style: { fontSize: 13, opacity: 0.8 }, children: [
|
|
4537
|
+
"Replacing ",
|
|
4538
|
+
/* @__PURE__ */ jsx12("code", { children: seWidgetType }),
|
|
4539
|
+
" with a layer from a curated Lumia Marketplace overlay."
|
|
4540
|
+
] }),
|
|
4541
|
+
/* @__PURE__ */ jsx12("div", { className: "ui-flex-row ui-gap-2", style: { flexWrap: "wrap", marginTop: 4 }, children: candidates.map((c) => /* @__PURE__ */ jsx12(
|
|
4542
|
+
"button",
|
|
4543
|
+
{
|
|
4544
|
+
type: "button",
|
|
4545
|
+
className: `ui-button ${c.id === activeId ? "ui-button-purple" : ""}`,
|
|
4546
|
+
onClick: () => {
|
|
4547
|
+
setActiveId(c.id);
|
|
4548
|
+
setActiveLayerId(null);
|
|
4549
|
+
},
|
|
4550
|
+
children: c.loading ? `Loading #${c.id}\u2026` : c.error ? `#${c.id} (error)` : c.overlay?.name ?? `Overlay #${c.id}`
|
|
4551
|
+
},
|
|
4552
|
+
c.id
|
|
4553
|
+
)) }),
|
|
4554
|
+
activeCandidate?.error && /* @__PURE__ */ jsxs6("div", { style: { padding: 12, borderRadius: 6, background: "rgba(220,38,38,0.15)", color: "#fecaca", fontSize: 13 }, children: [
|
|
4555
|
+
"Failed to load overlay #",
|
|
4556
|
+
activeCandidate.id,
|
|
4557
|
+
": ",
|
|
4558
|
+
activeCandidate.error
|
|
4559
|
+
] }),
|
|
4560
|
+
activeCandidate?.loading && /* @__PURE__ */ jsx12("div", { style: { padding: 12, fontSize: 13, opacity: 0.8 }, children: "Loading overlay\u2026" }),
|
|
4561
|
+
activeCandidate?.overlay && /* @__PURE__ */ jsxs6("div", { className: "ui-flex-row ui-gap-2", style: { alignItems: "stretch" }, children: [
|
|
4562
|
+
/* @__PURE__ */ jsxs6("div", { style: { flex: "0 0 200px", display: "flex", flexDirection: "column", gap: 4, maxHeight: 320, overflowY: "auto" }, children: [
|
|
4563
|
+
/* @__PURE__ */ jsx12("div", { style: { fontSize: 12, fontWeight: 600, opacity: 0.8 }, children: "Layers" }),
|
|
4564
|
+
activeLayers.map((l) => /* @__PURE__ */ jsx12(
|
|
4565
|
+
"button",
|
|
4566
|
+
{
|
|
4567
|
+
type: "button",
|
|
4568
|
+
className: `ui-button ${l.id === activeLayerId ? "ui-button-purple" : ""}`,
|
|
4569
|
+
style: { justifyContent: "flex-start", textAlign: "left" },
|
|
4570
|
+
onClick: () => setActiveLayerId(l.id),
|
|
4571
|
+
children: /* @__PURE__ */ jsxs6("div", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: [
|
|
4572
|
+
/* @__PURE__ */ jsx12("div", { style: { fontSize: 12, fontWeight: 600 }, children: l.label }),
|
|
4573
|
+
/* @__PURE__ */ jsx12("div", { style: { fontSize: 10, opacity: 0.7 }, children: l.type })
|
|
4574
|
+
] })
|
|
4575
|
+
},
|
|
4576
|
+
l.id
|
|
4577
|
+
)),
|
|
4578
|
+
activeLayers.length === 0 && /* @__PURE__ */ jsx12("div", { style: { fontSize: 12, opacity: 0.7 }, children: "No transplantable layers." })
|
|
4579
|
+
] }),
|
|
4580
|
+
/* @__PURE__ */ jsx12("div", { style: { flex: 1, minHeight: 240, background: "rgba(0,0,0,0.3)", borderRadius: 6, overflow: "hidden" }, children: /* @__PURE__ */ jsx12(ActiveLayerPreview, { overlay: activeCandidate.overlay, layerId: activeLayerId, CustomEmbed }) })
|
|
4581
|
+
] }),
|
|
4582
|
+
/* @__PURE__ */ jsxs6("div", { className: "ui-flex-row ui-gap-2", style: { marginTop: 12, justifyContent: "flex-end" }, children: [
|
|
4583
|
+
/* @__PURE__ */ jsx12("button", { type: "button", className: "ui-button", onClick: onCancel, children: "Cancel" }),
|
|
4584
|
+
/* @__PURE__ */ jsx12(
|
|
4585
|
+
"button",
|
|
4586
|
+
{
|
|
4587
|
+
type: "button",
|
|
4588
|
+
className: "ui-button ui-button-purple",
|
|
4589
|
+
onClick: handleConfirm,
|
|
4590
|
+
disabled: !activeCandidate?.overlay || !activeLayerId,
|
|
4591
|
+
children: "Use this layer"
|
|
4592
|
+
}
|
|
4593
|
+
)
|
|
4594
|
+
] })
|
|
4595
|
+
] });
|
|
4596
|
+
}
|
|
4597
|
+
function ActiveLayerPreview({ overlay, layerId, CustomEmbed }) {
|
|
4598
|
+
if (!layerId) return /* @__PURE__ */ jsx12("div", { style: { padding: 16, fontSize: 12, opacity: 0.7 }, children: "Select a layer to preview." });
|
|
4599
|
+
const module = overlay.settings?.modules?.[layerId];
|
|
4600
|
+
if (!module) return /* @__PURE__ */ jsx12("div", { style: { padding: 16, fontSize: 12, opacity: 0.7 }, children: "Layer not found." });
|
|
4601
|
+
const type = module.settings?.type;
|
|
4602
|
+
if (type === "custom" && module.content && CustomEmbed) {
|
|
4603
|
+
const c = module.content;
|
|
4604
|
+
return /* @__PURE__ */ jsx12(
|
|
4605
|
+
CustomEmbed,
|
|
4606
|
+
{
|
|
4607
|
+
codeId: c.codeId ?? layerId,
|
|
4608
|
+
html: c.html ?? "",
|
|
4609
|
+
css: c.css ?? "",
|
|
4610
|
+
js: c.js ?? "",
|
|
4611
|
+
data: c.data ?? {}
|
|
4612
|
+
}
|
|
4613
|
+
);
|
|
4614
|
+
}
|
|
4615
|
+
return /* @__PURE__ */ jsxs6("div", { style: { padding: 16, fontSize: 12 }, children: [
|
|
4616
|
+
/* @__PURE__ */ jsx12("div", { style: { fontWeight: 600, marginBottom: 8 }, children: module.settings?.title ?? type }),
|
|
4617
|
+
/* @__PURE__ */ jsxs6("div", { style: { opacity: 0.8 }, children: [
|
|
4618
|
+
"Preview not available for module type ",
|
|
4619
|
+
/* @__PURE__ */ jsx12("code", { children: String(type) }),
|
|
4620
|
+
'. Click "Use this layer" to transplant it anyway.'
|
|
4621
|
+
] })
|
|
4622
|
+
] });
|
|
4623
|
+
}
|
|
4624
|
+
|
|
4625
|
+
// src/se-import/ui/SEImportWizard.tsx
|
|
4626
|
+
import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
4627
|
+
function StepDot({ active, done, label, num }) {
|
|
4628
|
+
const bg = done ? "#22c55e" : active ? "#6a6ffc" : "var(--ui-bg-elevated, #2a2c31)";
|
|
4629
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ui-flex-row", style: { alignItems: "center", gap: 8, opacity: active || done ? 1 : 0.6 }, children: [
|
|
4630
|
+
/* @__PURE__ */ jsx13("div", { style: { width: 22, height: 22, borderRadius: "50%", background: bg, color: "#fff", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 11, fontWeight: 700 }, children: done ? "\u2713" : num }),
|
|
4631
|
+
/* @__PURE__ */ jsx13("span", { style: { fontSize: 12, fontWeight: active ? 600 : 400 }, children: label })
|
|
4632
|
+
] });
|
|
4633
|
+
}
|
|
4634
|
+
function ProgressBar({ value, max }) {
|
|
4635
|
+
const pct = max > 0 ? Math.min(100, Math.round(value / max * 100)) : 0;
|
|
4636
|
+
return /* @__PURE__ */ jsx13("div", { style: { height: 6, borderRadius: 3, background: "var(--ui-bg-elevated, #2a2c31)", overflow: "hidden" }, children: /* @__PURE__ */ jsx13("div", { style: { height: "100%", width: `${pct}%`, background: "#6a6ffc", transition: "width 240ms" } }) });
|
|
4637
|
+
}
|
|
4638
|
+
function ErrorPanel({ message, hint }) {
|
|
4639
|
+
return /* @__PURE__ */ jsxs7("div", { style: { padding: 10, borderRadius: 6, background: "rgba(220, 38, 38, 0.12)", border: "1px solid rgba(220, 38, 38, 0.4)", color: "#fca5a5", fontSize: 13 }, children: [
|
|
4640
|
+
/* @__PURE__ */ jsx13("div", { style: { fontWeight: 600 }, children: message }),
|
|
4641
|
+
hint && /* @__PURE__ */ jsx13("div", { style: { marginTop: 6, whiteSpace: "pre-wrap", opacity: 0.85 }, children: hint })
|
|
4642
|
+
] });
|
|
4643
|
+
}
|
|
4644
|
+
function StatusBadge({ label, count, pct, tone }) {
|
|
4645
|
+
const colors = { success: "#22c55e", info: "#6a6ffc", warn: "#f59e0b", muted: "#9ca3af" };
|
|
4646
|
+
return /* @__PURE__ */ jsxs7("div", { style: { flex: "1 1 120px", padding: "10px 12px", borderRadius: 6, background: "var(--ui-bg-elevated, #1d1f24)", borderLeft: `3px solid ${colors[tone]}` }, children: [
|
|
4647
|
+
/* @__PURE__ */ jsx13("div", { style: { fontSize: 11, textTransform: "uppercase", letterSpacing: 0.5, opacity: 0.7 }, children: label }),
|
|
4648
|
+
/* @__PURE__ */ jsx13("div", { style: { fontSize: 22, fontWeight: 700 }, children: count }),
|
|
4649
|
+
/* @__PURE__ */ jsxs7("div", { style: { fontSize: 12, opacity: 0.7 }, children: [
|
|
4650
|
+
pct,
|
|
4651
|
+
"%"
|
|
4652
|
+
] })
|
|
4653
|
+
] });
|
|
4654
|
+
}
|
|
4655
|
+
function CoverageCards({ coverage }) {
|
|
4656
|
+
const byStatus = useMemo5(() => {
|
|
4657
|
+
const acc = { direct: 0, partial: 0, template: 0, placeholder: 0 };
|
|
4658
|
+
for (const m of coverage.mappings) acc[m.status] += m.count;
|
|
4659
|
+
return acc;
|
|
4660
|
+
}, [coverage]);
|
|
4661
|
+
const pct = (n) => coverage.totalWidgets > 0 ? Math.round(n / coverage.totalWidgets * 100) : 0;
|
|
4662
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ui-flex-row ui-gap-2", style: { flexWrap: "wrap" }, children: [
|
|
4663
|
+
/* @__PURE__ */ jsx13(StatusBadge, { label: "Direct", count: byStatus.direct, pct: pct(byStatus.direct), tone: "success" }),
|
|
4664
|
+
/* @__PURE__ */ jsx13(StatusBadge, { label: "Partial", count: byStatus.partial, pct: pct(byStatus.partial), tone: "info" }),
|
|
4665
|
+
/* @__PURE__ */ jsx13(StatusBadge, { label: "Template", count: byStatus.template, pct: pct(byStatus.template), tone: "warn" }),
|
|
4666
|
+
/* @__PURE__ */ jsx13(StatusBadge, { label: "Placeholder", count: byStatus.placeholder, pct: pct(byStatus.placeholder), tone: "muted" })
|
|
4667
|
+
] });
|
|
4668
|
+
}
|
|
4669
|
+
function CustomOverlayPreview({ html, css, js, data, width, height }) {
|
|
4670
|
+
const srcdoc = useMemo5(() => {
|
|
4671
|
+
const safeData = JSON.stringify(data ?? {});
|
|
4672
|
+
const safeJs = JSON.stringify(`(async () => { ${js || ""} })()`);
|
|
4673
|
+
const safeHtml = (html || "").replace(/<\/script>/gi, "<\\/script>");
|
|
4674
|
+
const safeCss = (css || "").replace(/<\/style>/gi, "<\\/style>");
|
|
4675
|
+
return `<!DOCTYPE html><html><head><meta charset="utf-8"/><style>html,body{margin:0;padding:0;width:100%;height:100%;overflow:hidden;background:transparent;}${safeCss}</style></head><body>${safeHtml}<script>
|
|
4676
|
+
window.DATA = ${safeData};
|
|
4677
|
+
window.Overlay = window.Overlay || { on:()=>{}, callCommand:()=>Promise.resolve(), chatbot:()=>Promise.resolve(), setVariable:()=>Promise.resolve(), getVariable:()=>Promise.resolve(), saveStorage:()=>Promise.resolve(), getStorage:()=>Promise.resolve(), deleteStorage:()=>Promise.resolve(), addLoyaltyPoints:()=>Promise.resolve(), getLoyaltyPoints:()=>Promise.resolve() };
|
|
4678
|
+
try { eval(${safeJs}); } catch(e) { document.body.insertAdjacentHTML('beforeend','<pre style=\\"color:#fca5a5;font:11px monospace;padding:8px;\\">' + (e && e.message ? e.message : e) + '</pre>'); }
|
|
4679
|
+
</script></body></html>`;
|
|
4680
|
+
}, [html, css, js, data]);
|
|
4681
|
+
return /* @__PURE__ */ jsx13(
|
|
4682
|
+
"iframe",
|
|
4683
|
+
{
|
|
4684
|
+
title: "ai-preview",
|
|
4685
|
+
sandbox: "allow-scripts",
|
|
4686
|
+
srcDoc: srcdoc,
|
|
4687
|
+
style: { width: "100%", height: 260, border: "1px solid var(--ui-border, #2a2c31)", borderRadius: 6, background: "repeating-conic-gradient(#1a1c20 0% 25%, #1d1f24 0% 50%) 50% / 20px 20px" },
|
|
4688
|
+
"data-canvas-width": width,
|
|
4689
|
+
"data-canvas-height": height
|
|
4690
|
+
}
|
|
4691
|
+
);
|
|
4692
|
+
}
|
|
4693
|
+
function StepURL({ url, setUrl, error, busy }) {
|
|
4694
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ui-flex-column ui-gap-2", children: [
|
|
4695
|
+
/* @__PURE__ */ jsxs7("p", { style: { margin: 0, opacity: 0.85 }, children: [
|
|
4696
|
+
"Paste the public ",
|
|
4697
|
+
/* @__PURE__ */ jsx13("strong", { children: "preview URL" }),
|
|
4698
|
+
" for your StreamElements overlay. The URL contains the access token, so no StreamElements login is required."
|
|
4699
|
+
] }),
|
|
4700
|
+
/* @__PURE__ */ jsx13(LSInput, { label: "StreamElements overlay URL", value: url, onChange: (e) => setUrl(e.target.value), placeholder: "https://streamelements.com/overlay/<id>/<token>", disabled: busy }),
|
|
4701
|
+
/* @__PURE__ */ jsxs7("details", { children: [
|
|
4702
|
+
/* @__PURE__ */ jsx13("summary", { style: { cursor: "pointer", fontWeight: 600, fontSize: 13 }, children: "How to find the overlay URL" }),
|
|
4703
|
+
/* @__PURE__ */ jsxs7("ol", { style: { paddingLeft: 18, marginTop: 8, fontSize: 13, opacity: 0.9 }, children: [
|
|
4704
|
+
/* @__PURE__ */ jsxs7("li", { children: [
|
|
4705
|
+
"Open ",
|
|
4706
|
+
/* @__PURE__ */ jsx13("a", { href: "https://streamelements.com/dashboard/overlays", target: "_blank", rel: "noreferrer", children: "streamelements.com/dashboard/overlays" }),
|
|
4707
|
+
"."
|
|
4708
|
+
] }),
|
|
4709
|
+
/* @__PURE__ */ jsx13("li", { children: "Click the overlay you want to bring over." }),
|
|
4710
|
+
/* @__PURE__ */ jsxs7("li", { children: [
|
|
4711
|
+
"Click ",
|
|
4712
|
+
/* @__PURE__ */ jsx13("strong", { children: "Copy URL" }),
|
|
4713
|
+
" in the top-right of the editor."
|
|
4714
|
+
] }),
|
|
4715
|
+
/* @__PURE__ */ jsx13("li", { children: "Paste it above." })
|
|
4716
|
+
] })
|
|
4717
|
+
] }),
|
|
4718
|
+
error && /* @__PURE__ */ jsx13(ErrorPanel, { message: error.message, hint: error.hint })
|
|
4719
|
+
] });
|
|
4720
|
+
}
|
|
4721
|
+
function StepDiscovery({ result, assetCount }) {
|
|
4722
|
+
const widgets = result.coverage.totalWidgets;
|
|
4723
|
+
const reviewCount = result.reviewItems.length;
|
|
4724
|
+
const customCount = result.coverage.mappings.find((m) => m.seType === "se-widget-custom-event-list")?.count ?? 0;
|
|
4725
|
+
const alertCount = result.coverage.mappings.filter((m) => m.lumiaType === "alert").reduce((a, m) => a + m.count, 0);
|
|
4726
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ui-flex-column ui-gap-2", children: [
|
|
4727
|
+
/* @__PURE__ */ jsx13("div", { style: { fontWeight: 600, fontSize: 16 }, children: "Here's what we found" }),
|
|
4728
|
+
/* @__PURE__ */ jsxs7("div", { className: "ui-flex-row ui-gap-2", style: { flexWrap: "wrap" }, children: [
|
|
4729
|
+
/* @__PURE__ */ jsx13(DiscoveryStat, { label: "Total widgets", value: widgets }),
|
|
4730
|
+
/* @__PURE__ */ jsx13(DiscoveryStat, { label: "Alerts", value: alertCount }),
|
|
4731
|
+
/* @__PURE__ */ jsx13(DiscoveryStat, { label: "Custom widgets", value: customCount, sub: customCount > 0 ? "will need the SE compatibility shim" : void 0 }),
|
|
4732
|
+
/* @__PURE__ */ jsx13(DiscoveryStat, { label: "SE-hosted assets", value: assetCount, sub: assetCount > 0 ? "can be mirrored to Lumia storage" : "no migration needed" }),
|
|
4733
|
+
/* @__PURE__ */ jsx13(DiscoveryStat, { label: "Need review", value: reviewCount, sub: reviewCount > 0 ? "no native Lumia equivalent yet" : "everything maps cleanly", highlight: reviewCount > 0 })
|
|
4734
|
+
] }),
|
|
4735
|
+
/* @__PURE__ */ jsx13("div", { style: { marginTop: 8 }, children: /* @__PURE__ */ jsx13(CoverageCards, { coverage: result.coverage }) })
|
|
4736
|
+
] });
|
|
4737
|
+
}
|
|
4738
|
+
function DiscoveryStat({ label, value, sub, highlight }) {
|
|
4739
|
+
return /* @__PURE__ */ jsxs7("div", { style: { flex: "1 1 160px", padding: "12px 14px", borderRadius: 6, background: "var(--ui-bg-elevated, #1d1f24)", border: highlight ? "1px solid #f59e0b" : "1px solid transparent" }, children: [
|
|
4740
|
+
/* @__PURE__ */ jsx13("div", { style: { fontSize: 11, textTransform: "uppercase", letterSpacing: 0.5, opacity: 0.7 }, children: label }),
|
|
4741
|
+
/* @__PURE__ */ jsx13("div", { style: { fontSize: 26, fontWeight: 700 }, children: value }),
|
|
4742
|
+
sub && /* @__PURE__ */ jsx13("div", { style: { fontSize: 11, opacity: 0.65, marginTop: 4 }, children: sub })
|
|
4743
|
+
] });
|
|
4744
|
+
}
|
|
4745
|
+
function StepOptions({ options, setOptions, assetCount }) {
|
|
4746
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ui-flex-column ui-gap-2", children: [
|
|
4747
|
+
/* @__PURE__ */ jsx13("div", { style: { fontWeight: 600, fontSize: 16 }, children: "Import options" }),
|
|
4748
|
+
/* @__PURE__ */ jsxs7("label", { className: "ui-flex-row", style: { gap: 10, padding: 12, borderRadius: 6, background: "var(--ui-bg-elevated, #1d1f24)", cursor: assetCount === 0 ? "not-allowed" : "pointer", opacity: assetCount === 0 ? 0.5 : 1 }, children: [
|
|
4749
|
+
/* @__PURE__ */ jsx13("input", { type: "checkbox", checked: options.mirrorAssets, disabled: assetCount === 0, onChange: (e) => setOptions({ ...options, mirrorAssets: e.target.checked }), style: { marginTop: 2 } }),
|
|
4750
|
+
/* @__PURE__ */ jsxs7("div", { children: [
|
|
4751
|
+
/* @__PURE__ */ jsxs7("div", { style: { fontWeight: 600 }, children: [
|
|
4752
|
+
"Mirror StreamElements assets to Lumia storage ",
|
|
4753
|
+
assetCount > 0 && /* @__PURE__ */ jsxs7("span", { style: { opacity: 0.7, fontWeight: 400 }, children: [
|
|
4754
|
+
"(",
|
|
4755
|
+
assetCount,
|
|
4756
|
+
" files)"
|
|
4757
|
+
] })
|
|
4758
|
+
] }),
|
|
4759
|
+
/* @__PURE__ */ jsxs7("div", { style: { fontSize: 12, opacity: 0.8, marginTop: 4 }, children: [
|
|
4760
|
+
"Downloads every ",
|
|
4761
|
+
`cdn.streamelements.com`,
|
|
4762
|
+
" URL referenced in the overlay and re-uploads it to your Lumia asset library, then rewrites the URLs. Recommended \u2014 if StreamElements rotates their CDN or removes a file, your overlay keeps working."
|
|
4763
|
+
] })
|
|
4764
|
+
] })
|
|
4765
|
+
] }),
|
|
4766
|
+
/* @__PURE__ */ jsx13(LSInput, { label: "Overlay name", value: options.name, onChange: (e) => setOptions({ ...options, name: e.target.value }) })
|
|
4767
|
+
] });
|
|
4768
|
+
}
|
|
4769
|
+
function StepMirror({ rows, running, onRetry }) {
|
|
4770
|
+
const done = rows.filter((r) => r.state === "done").length;
|
|
4771
|
+
const reused = rows.filter((r) => r.state === "reused").length;
|
|
4772
|
+
const keptOnCdn = rows.filter((r) => r.state === "kept-on-cdn").length;
|
|
4773
|
+
const failed = rows.filter((r) => r.state === "failed").length;
|
|
4774
|
+
const summary = running ? `Downloading from StreamElements and uploading to Lumia\u2026 (${done + reused + keptOnCdn}/${rows.length})` : `Finished. ${done} mirrored${reused ? `, ${reused} reused from your library` : ""}${keptOnCdn ? `, ${keptOnCdn} SVG kept on SE CDN` : ""}${failed ? `, ${failed} failed (left pointing at SE).` : "."}`;
|
|
4775
|
+
const stateColor = (s) => s === "done" ? "#22c55e" : s === "reused" ? "#60a5fa" : s === "kept-on-cdn" ? "#a78bfa" : s === "failed" ? "#ef4444" : "#6a6ffc";
|
|
4776
|
+
const stateLabel = (s) => s === "pending" ? "\u2026" : s === "fetching" ? "Fetching\u2026" : s === "reused" ? "\u21BA reused" : s === "kept-on-cdn" ? "\u2297 kept on SE CDN" : s === "done" ? "\u2713" : "\u2717";
|
|
4777
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ui-flex-column ui-gap-2", children: [
|
|
4778
|
+
/* @__PURE__ */ jsx13("div", { style: { fontWeight: 600, fontSize: 16 }, children: "Mirroring assets" }),
|
|
4779
|
+
/* @__PURE__ */ jsx13("div", { style: { fontSize: 13, opacity: 0.8 }, children: summary }),
|
|
4780
|
+
/* @__PURE__ */ jsx13(ProgressBar, { value: done + reused + failed + keptOnCdn, max: rows.length }),
|
|
4781
|
+
/* @__PURE__ */ jsx13("div", { className: "ui-flex-column", style: { maxHeight: 320, overflowY: "auto", border: "1px solid var(--ui-border, #2a2c31)", borderRadius: 6 }, children: rows.map((row, i) => /* @__PURE__ */ jsxs7("div", { style: { padding: "8px 12px", borderTop: i === 0 ? "none" : "1px solid var(--ui-border, #2a2c31)", fontSize: 12 }, children: [
|
|
4782
|
+
/* @__PURE__ */ jsxs7("div", { className: "ui-flex-row", style: { justifyContent: "space-between", gap: 8, alignItems: "center" }, children: [
|
|
4783
|
+
/* @__PURE__ */ jsx13("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", flex: 1, fontFamily: "ui-monospace, monospace" }, title: row.url, children: row.url }),
|
|
4784
|
+
/* @__PURE__ */ jsx13("span", { style: { color: stateColor(row.state), fontWeight: 600 }, children: stateLabel(row.state) }),
|
|
4785
|
+
row.state === "failed" && /* @__PURE__ */ jsx13(
|
|
4786
|
+
"button",
|
|
4787
|
+
{
|
|
4788
|
+
type: "button",
|
|
4789
|
+
className: "ui-button ui-button-secondary",
|
|
4790
|
+
style: { padding: "2px 10px", fontSize: 11, minWidth: 0 },
|
|
4791
|
+
onClick: () => onRetry(i),
|
|
4792
|
+
title: "Retry this asset",
|
|
4793
|
+
children: "Retry"
|
|
4794
|
+
}
|
|
4795
|
+
)
|
|
4796
|
+
] }),
|
|
4797
|
+
row.error && /* @__PURE__ */ jsx13("div", { style: { marginTop: 4, color: "#fca5a5" }, children: row.error })
|
|
4798
|
+
] }, row.url)) })
|
|
4799
|
+
] });
|
|
4800
|
+
}
|
|
4801
|
+
function StepReview({ item, index, total, state, error, generated, canvas, onSkip, onKeep, onGenerate, onAccept, onRetry, onPickMarketplace, onKeepAllPlaceholders, onSkipAll, remainingCount, marketplaceAvailable }) {
|
|
4802
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ui-flex-column ui-gap-2", children: [
|
|
4803
|
+
/* @__PURE__ */ jsxs7("div", { className: "ui-flex-row", style: { justifyContent: "space-between", alignItems: "center" }, children: [
|
|
4804
|
+
/* @__PURE__ */ jsxs7("div", { style: { fontWeight: 600, fontSize: 16 }, children: [
|
|
4805
|
+
"Reviewing widget ",
|
|
4806
|
+
index + 1,
|
|
4807
|
+
" of ",
|
|
4808
|
+
total
|
|
4809
|
+
] }),
|
|
4810
|
+
/* @__PURE__ */ jsxs7("div", { className: "ui-flex-row ui-gap-2", style: { alignItems: "center" }, children: [
|
|
4811
|
+
item.flaggedOff && /* @__PURE__ */ jsx13("div", { style: { fontSize: 10, padding: "2px 8px", borderRadius: 4, background: "rgba(234, 179, 8, 0.2)", color: "#facc15", textTransform: "uppercase", letterSpacing: 0.5, fontWeight: 600 }, children: "Auto-import disabled" }),
|
|
4812
|
+
/* @__PURE__ */ jsx13("div", { style: { fontSize: 11, opacity: 0.7, textTransform: "uppercase", letterSpacing: 0.5 }, children: item.status })
|
|
4813
|
+
] })
|
|
4814
|
+
] }),
|
|
4815
|
+
remainingCount > 1 && /* @__PURE__ */ jsxs7("div", { className: "ui-flex-row ui-gap-2", style: { justifyContent: "flex-end", alignItems: "center", fontSize: 12 }, children: [
|
|
4816
|
+
/* @__PURE__ */ jsxs7("span", { style: { opacity: 0.7 }, children: [
|
|
4817
|
+
remainingCount,
|
|
4818
|
+
" remaining"
|
|
4819
|
+
] }),
|
|
4820
|
+
/* @__PURE__ */ jsx13("button", { type: "button", className: "ui-button ui-button-secondary", style: { padding: "4px 10px", fontSize: 12 }, onClick: onKeepAllPlaceholders, title: "Keep every remaining placeholder/template widget as-is (skips flagged-off widgets that should go to marketplace/AI)", children: "Keep all placeholders" }),
|
|
4821
|
+
/* @__PURE__ */ jsx13("button", { type: "button", className: "ui-button ui-button-secondary", style: { padding: "4px 10px", fontSize: 12 }, onClick: onSkipAll, title: "Drop every remaining widget entirely", children: "Skip all" })
|
|
4822
|
+
] }),
|
|
4823
|
+
/* @__PURE__ */ jsxs7("div", { style: { padding: 12, borderRadius: 6, background: "var(--ui-bg-elevated, #1d1f24)" }, children: [
|
|
4824
|
+
/* @__PURE__ */ jsx13("div", { style: { fontFamily: "ui-monospace, monospace", fontWeight: 600, fontSize: 13 }, children: item.seWidget.type }),
|
|
4825
|
+
/* @__PURE__ */ jsx13("div", { style: { fontSize: 13, opacity: 0.85, marginTop: 4 }, children: item.reason })
|
|
4826
|
+
] }),
|
|
4827
|
+
state === "generating" && /* @__PURE__ */ jsx13("div", { style: { padding: 12, fontSize: 13, opacity: 0.85 }, children: "Generating with AI\u2026 this can take 30\u201390 seconds." }),
|
|
4828
|
+
state === "generated" && generated && /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
4829
|
+
/* @__PURE__ */ jsx13("div", { style: { fontSize: 13, fontWeight: 600, marginTop: 4 }, children: "Preview" }),
|
|
4830
|
+
(() => {
|
|
4831
|
+
const landing = getAILandingBounds(item.seWidget, canvas);
|
|
4832
|
+
return /* @__PURE__ */ jsx13(CustomOverlayPreview, { html: generated.html ?? "", css: generated.css ?? "", js: generated.js ?? "", data: generated.data ?? {}, width: landing.width, height: landing.height });
|
|
4833
|
+
})(),
|
|
4834
|
+
/* @__PURE__ */ jsxs7("details", { children: [
|
|
4835
|
+
/* @__PURE__ */ jsx13("summary", { style: { cursor: "pointer", fontSize: 12, opacity: 0.8 }, children: "Generated code" }),
|
|
4836
|
+
/* @__PURE__ */ jsxs7("details", { style: { marginLeft: 12, marginTop: 8 }, children: [
|
|
4837
|
+
/* @__PURE__ */ jsx13("summary", { style: { cursor: "pointer", fontSize: 12 }, children: "HTML" }),
|
|
4838
|
+
/* @__PURE__ */ jsx13("pre", { style: { fontSize: 11, padding: 8, background: "rgba(0,0,0,0.25)", borderRadius: 4, maxHeight: 160, overflow: "auto" }, children: generated.html || "" })
|
|
4839
|
+
] }),
|
|
4840
|
+
/* @__PURE__ */ jsxs7("details", { style: { marginLeft: 12 }, children: [
|
|
4841
|
+
/* @__PURE__ */ jsx13("summary", { style: { cursor: "pointer", fontSize: 12 }, children: "CSS" }),
|
|
4842
|
+
/* @__PURE__ */ jsx13("pre", { style: { fontSize: 11, padding: 8, background: "rgba(0,0,0,0.25)", borderRadius: 4, maxHeight: 160, overflow: "auto" }, children: generated.css || "" })
|
|
4843
|
+
] }),
|
|
4844
|
+
/* @__PURE__ */ jsxs7("details", { style: { marginLeft: 12 }, children: [
|
|
4845
|
+
/* @__PURE__ */ jsx13("summary", { style: { cursor: "pointer", fontSize: 12 }, children: "JS" }),
|
|
4846
|
+
/* @__PURE__ */ jsx13("pre", { style: { fontSize: 11, padding: 8, background: "rgba(0,0,0,0.25)", borderRadius: 4, maxHeight: 160, overflow: "auto" }, children: generated.js || "" })
|
|
4847
|
+
] })
|
|
4848
|
+
] })
|
|
4849
|
+
] }),
|
|
4850
|
+
error && /* @__PURE__ */ jsx13(ErrorPanel, { message: error }),
|
|
4851
|
+
/* @__PURE__ */ jsxs7("details", { children: [
|
|
4852
|
+
/* @__PURE__ */ jsx13("summary", { style: { cursor: "pointer", fontSize: 12, opacity: 0.8 }, children: "Original StreamElements config" }),
|
|
4853
|
+
/* @__PURE__ */ jsx13("pre", { style: { marginTop: 6, fontSize: 11, padding: 8, background: "rgba(0,0,0,0.25)", borderRadius: 4, maxHeight: 180, overflow: "auto" }, children: JSON.stringify(item.seWidget.variables ?? {}, null, 2) })
|
|
4854
|
+
] }),
|
|
4855
|
+
/* @__PURE__ */ jsx13("div", { className: "ui-flex-row ui-gap-2", style: { marginTop: 8 }, children: state === "generated" ? /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
4856
|
+
/* @__PURE__ */ jsx13("button", { type: "button", className: "ui-button", onClick: onRetry, children: "Try again" }),
|
|
4857
|
+
/* @__PURE__ */ jsx13("button", { type: "button", className: "ui-button", onClick: onSkip, children: "Skip this widget" }),
|
|
4858
|
+
/* @__PURE__ */ jsx13("button", { type: "button", className: "ui-button ui-button-purple", onClick: onAccept, children: "Use this and continue" })
|
|
4859
|
+
] }) : /* @__PURE__ */ jsxs7(Fragment3, { children: [
|
|
4860
|
+
!item.flaggedOff && /* @__PURE__ */ jsx13("button", { type: "button", className: "ui-button", onClick: onKeep, disabled: state === "generating", children: "Keep placeholder" }),
|
|
4861
|
+
/* @__PURE__ */ jsx13("button", { type: "button", className: "ui-button", onClick: onSkip, disabled: state === "generating", children: "Skip" }),
|
|
4862
|
+
marketplaceAvailable && /* @__PURE__ */ jsx13("button", { type: "button", className: "ui-button", onClick: onPickMarketplace, disabled: state === "generating", children: "Pick from Marketplace" }),
|
|
4863
|
+
/* @__PURE__ */ jsx13("button", { type: "button", className: "ui-button ui-button-purple", onClick: onGenerate, disabled: state === "generating", children: state === "generating" ? "Generating\u2026" : "Generate with AI" })
|
|
4864
|
+
] }) }),
|
|
4865
|
+
item.flaggedOff && !marketplaceAvailable && state !== "generated" && /* @__PURE__ */ jsx13("div", { style: { fontSize: 12, opacity: 0.75 }, children: "No curated Marketplace replacement is configured for this widget yet." })
|
|
4866
|
+
] });
|
|
4867
|
+
}
|
|
4868
|
+
function StepConfirm({ result, options, mirrorRows, rowStates }) {
|
|
4869
|
+
const total = result.overlay.settings.layers.length;
|
|
4870
|
+
const mirrored = mirrorRows.filter((r) => r.state === "done" || r.state === "reused" || r.state === "kept-on-cdn").length;
|
|
4871
|
+
const mirrorFailed = mirrorRows.filter((r) => r.state === "failed").length;
|
|
4872
|
+
const reviewBuckets = Object.values(rowStates).reduce(
|
|
4873
|
+
(acc, s) => {
|
|
4874
|
+
acc[s.state] = (acc[s.state] ?? 0) + 1;
|
|
4875
|
+
return acc;
|
|
4876
|
+
},
|
|
4877
|
+
{}
|
|
4878
|
+
);
|
|
4879
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ui-flex-column ui-gap-2", children: [
|
|
4880
|
+
/* @__PURE__ */ jsx13("div", { style: { fontWeight: 600, fontSize: 16 }, children: "Ready to import" }),
|
|
4881
|
+
/* @__PURE__ */ jsxs7("div", { className: "ui-flex-column ui-gap-2", style: { padding: 12, borderRadius: 6, background: "var(--ui-bg-elevated, #1d1f24)" }, children: [
|
|
4882
|
+
/* @__PURE__ */ jsx13(Row, { label: "Overlay name", value: options.name || result.overlay.name }),
|
|
4883
|
+
/* @__PURE__ */ jsx13(Row, { label: "Layers", value: `${total}` }),
|
|
4884
|
+
/* @__PURE__ */ jsx13(Row, { label: "Assets mirrored", value: options.mirrorAssets ? `${mirrored} / ${mirrorRows.length}${mirrorFailed ? ` (${mirrorFailed} kept on SE CDN)` : ""}` : "skipped" }),
|
|
4885
|
+
/* @__PURE__ */ jsx13(Row, { label: "Generated with AI", value: `${reviewBuckets.generated ?? 0}` }),
|
|
4886
|
+
/* @__PURE__ */ jsx13(Row, { label: "Skipped", value: `${reviewBuckets.skipped ?? 0}` }),
|
|
4887
|
+
/* @__PURE__ */ jsx13(Row, { label: "Kept as placeholder", value: `${reviewBuckets.kept ?? 0}` })
|
|
4888
|
+
] })
|
|
4889
|
+
] });
|
|
4890
|
+
}
|
|
4891
|
+
function Row({ label, value }) {
|
|
4892
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ui-flex-row", style: { justifyContent: "space-between" }, children: [
|
|
4893
|
+
/* @__PURE__ */ jsx13("span", { style: { opacity: 0.75 }, children: label }),
|
|
4894
|
+
/* @__PURE__ */ jsx13("span", { style: { fontWeight: 600 }, children: value })
|
|
4895
|
+
] });
|
|
4896
|
+
}
|
|
4897
|
+
function SEImportWizard({ bindings }) {
|
|
4898
|
+
const {
|
|
4899
|
+
fetchMarketplaceOverlay,
|
|
4900
|
+
generateAICustomCode,
|
|
4901
|
+
uploadAsset,
|
|
4902
|
+
existingAssets,
|
|
4903
|
+
saveOverlay,
|
|
4904
|
+
onComplete,
|
|
4905
|
+
onClose,
|
|
4906
|
+
notify,
|
|
4907
|
+
CustomEmbed,
|
|
4908
|
+
t
|
|
4909
|
+
} = bindings;
|
|
4910
|
+
const translate = (key, fallback) => t ? t(key) ?? fallback : fallback;
|
|
4911
|
+
const [step, setStep] = useState6("url");
|
|
4912
|
+
const [url, setUrl] = useState6("");
|
|
4913
|
+
const [loadError, setLoadError] = useState6(null);
|
|
4914
|
+
const [loading, setLoading] = useState6(false);
|
|
4915
|
+
const [result, setResult] = useState6(null);
|
|
4916
|
+
const [originalReviewItems, setOriginalReviewItems] = useState6([]);
|
|
4917
|
+
const [options, setOptions] = useState6({ mirrorAssets: true, name: "" });
|
|
4918
|
+
const assetUrls = useMemo5(() => result ? findSEAssetURLs(result.overlay) : [], [result]);
|
|
4919
|
+
const [mirrorRows, setMirrorRows] = useState6([]);
|
|
4920
|
+
const [mirrorRunning, setMirrorRunning] = useState6(false);
|
|
4921
|
+
const mirrorStartedRef = useRef4(false);
|
|
4922
|
+
const [rowStates, setRowStates] = useState6({});
|
|
4923
|
+
const [reviewIndex, setReviewIndex] = useState6(0);
|
|
4924
|
+
const [importing, setImporting] = useState6(false);
|
|
4925
|
+
const handleLoad = useCallback3(async () => {
|
|
4926
|
+
setLoadError(null);
|
|
4927
|
+
const parts = extractSEPreviewParts(url);
|
|
4928
|
+
if (!parts) {
|
|
4929
|
+
setLoadError({ message: "That doesn't look like a StreamElements overlay URL.", hint: "Expected: https://streamelements.com/overlay/<overlayId>/<token>" });
|
|
4930
|
+
return;
|
|
4931
|
+
}
|
|
4932
|
+
setLoading(true);
|
|
4933
|
+
try {
|
|
4934
|
+
const bootstrap = await fetchSEBootstrap(parts);
|
|
4935
|
+
const imported = importSEBootstrap(bootstrap);
|
|
4936
|
+
setResult(imported);
|
|
4937
|
+
setOptions((o) => ({ ...o, name: imported.overlay.name }));
|
|
4938
|
+
setOriginalReviewItems(imported.reviewItems);
|
|
4939
|
+
setRowStates(Object.fromEntries(imported.reviewItems.map((r) => [r.moduleId, { state: "pending" }])));
|
|
4940
|
+
setReviewIndex(0);
|
|
4941
|
+
setStep("discovery");
|
|
4942
|
+
} catch (e) {
|
|
4943
|
+
setLoadError({ message: "Could not load the overlay.", hint: e?.message });
|
|
4944
|
+
} finally {
|
|
4945
|
+
setLoading(false);
|
|
4946
|
+
}
|
|
4947
|
+
}, [url]);
|
|
4948
|
+
const mirrorAbortRef = useRef4(null);
|
|
4949
|
+
const processAssetRow = useCallback3(
|
|
4950
|
+
async (assetUrl, idx, existingByFilename, signal) => {
|
|
4951
|
+
const filename = filenameFromURL(assetUrl);
|
|
4952
|
+
const reuseUrl = existingByFilename.get(filename);
|
|
4953
|
+
if (reuseUrl) {
|
|
4954
|
+
setResult((curr) => curr ? { ...curr, overlay: rewriteAssetURLs(curr.overlay, { [assetUrl]: reuseUrl }) } : curr);
|
|
4955
|
+
return { state: "reused", newUrl: reuseUrl };
|
|
4956
|
+
}
|
|
4957
|
+
if (filename.toLowerCase().endsWith(".svg")) {
|
|
4958
|
+
return { state: "kept-on-cdn", newUrl: assetUrl };
|
|
4959
|
+
}
|
|
4960
|
+
setMirrorRows((prev) => prev.map((r, i) => i === idx ? { ...r, state: "fetching", error: void 0 } : r));
|
|
4961
|
+
try {
|
|
4962
|
+
const newUrl = await mirrorOneAsset(assetUrl, (file) => uploadAsset(file), signal);
|
|
4963
|
+
existingByFilename.set(filename, newUrl);
|
|
4964
|
+
setResult((curr) => curr ? { ...curr, overlay: rewriteAssetURLs(curr.overlay, { [assetUrl]: newUrl }) } : curr);
|
|
4965
|
+
return { state: "done", newUrl };
|
|
4966
|
+
} catch (err) {
|
|
4967
|
+
if (err?.name === "AbortError" || signal?.aborted) {
|
|
4968
|
+
return { state: "pending" };
|
|
4969
|
+
}
|
|
4970
|
+
return { state: "failed", error: extractErrorMessage(err) };
|
|
4971
|
+
}
|
|
4972
|
+
},
|
|
4973
|
+
[uploadAsset]
|
|
4974
|
+
);
|
|
4975
|
+
const filenameCacheRef = useRef4(/* @__PURE__ */ new Map());
|
|
4976
|
+
const runMirror = useCallback3(async () => {
|
|
4977
|
+
if (!result) return;
|
|
4978
|
+
mirrorAbortRef.current = new AbortController();
|
|
4979
|
+
const signal = mirrorAbortRef.current.signal;
|
|
4980
|
+
setMirrorRunning(true);
|
|
4981
|
+
const initialRows = assetUrls.map((u) => ({ url: u, state: "pending" }));
|
|
4982
|
+
setMirrorRows(initialRows);
|
|
4983
|
+
const existingByFilename = /* @__PURE__ */ new Map();
|
|
4984
|
+
for (const asset of existingAssets ?? []) {
|
|
4985
|
+
const name = asset.file_name || asset.name;
|
|
4986
|
+
if (name && asset.url) existingByFilename.set(name, asset.url);
|
|
4987
|
+
}
|
|
4988
|
+
filenameCacheRef.current = existingByFilename;
|
|
4989
|
+
for (let i = 0; i < initialRows.length; i += 1) {
|
|
4990
|
+
if (signal.aborted) {
|
|
4991
|
+
setMirrorRunning(false);
|
|
4992
|
+
return;
|
|
4993
|
+
}
|
|
4994
|
+
const row = initialRows[i];
|
|
4995
|
+
const outcome = await processAssetRow(row.url, i, existingByFilename, signal);
|
|
4996
|
+
if (signal.aborted) {
|
|
4997
|
+
setMirrorRunning(false);
|
|
4998
|
+
return;
|
|
4999
|
+
}
|
|
5000
|
+
setMirrorRows((prev) => prev.map((r, idx) => idx === i ? { ...r, ...outcome } : r));
|
|
5001
|
+
}
|
|
5002
|
+
setMirrorRunning(false);
|
|
5003
|
+
}, [assetUrls, existingAssets, processAssetRow, result]);
|
|
5004
|
+
const retryMirrorRow = useCallback3(
|
|
5005
|
+
async (idx) => {
|
|
5006
|
+
const rowUrl = mirrorRows[idx]?.url;
|
|
5007
|
+
if (!rowUrl) return;
|
|
5008
|
+
const outcome = await processAssetRow(rowUrl, idx, filenameCacheRef.current, mirrorAbortRef.current?.signal);
|
|
5009
|
+
setMirrorRows((prev) => prev.map((r, i) => i === idx ? { ...r, ...outcome } : r));
|
|
5010
|
+
},
|
|
5011
|
+
[mirrorRows, processAssetRow]
|
|
5012
|
+
);
|
|
5013
|
+
useEffect6(() => {
|
|
5014
|
+
if (step === "mirror" && !mirrorStartedRef.current) {
|
|
5015
|
+
mirrorStartedRef.current = true;
|
|
5016
|
+
void runMirror();
|
|
5017
|
+
}
|
|
5018
|
+
}, [step, runMirror]);
|
|
5019
|
+
const currentItem = originalReviewItems[reviewIndex];
|
|
5020
|
+
const currentRow = currentItem ? rowStates[currentItem.moduleId] ?? { state: "pending" } : void 0;
|
|
5021
|
+
const advanceReview = useCallback3(() => {
|
|
5022
|
+
if (reviewIndex + 1 < originalReviewItems.length) setReviewIndex(reviewIndex + 1);
|
|
5023
|
+
else setStep("confirm");
|
|
5024
|
+
}, [originalReviewItems.length, reviewIndex]);
|
|
5025
|
+
const setRow = useCallback3((moduleId, patch) => {
|
|
5026
|
+
setRowStates((prev) => ({ ...prev, [moduleId]: { ...prev[moduleId] ?? { state: "pending" }, ...patch } }));
|
|
5027
|
+
}, []);
|
|
5028
|
+
const handleKeep = () => {
|
|
5029
|
+
if (!result || !currentItem) return;
|
|
5030
|
+
setResult(applyReviewAction(result, currentItem.moduleId, "keep"));
|
|
5031
|
+
setRow(currentItem.moduleId, { state: "kept" });
|
|
5032
|
+
advanceReview();
|
|
5033
|
+
};
|
|
5034
|
+
const handleSkip = () => {
|
|
5035
|
+
if (!result || !currentItem) return;
|
|
5036
|
+
setResult(applyReviewAction(result, currentItem.moduleId, "skip"));
|
|
5037
|
+
setRow(currentItem.moduleId, { state: "skipped" });
|
|
5038
|
+
advanceReview();
|
|
5039
|
+
};
|
|
5040
|
+
const handleGenerate = async () => {
|
|
5041
|
+
if (!currentItem || !result) return;
|
|
5042
|
+
setRow(currentItem.moduleId, { state: "generating", error: void 0 });
|
|
5043
|
+
try {
|
|
5044
|
+
const canvas = { width: result.overlay.settings.metadata.width, height: result.overlay.settings.metadata.height };
|
|
5045
|
+
const generated = await generateAICustomCode(buildAIPromptForSEWidget(currentItem.seWidget, canvas));
|
|
5046
|
+
setRow(currentItem.moduleId, { state: "generated", generated });
|
|
5047
|
+
} catch (e) {
|
|
5048
|
+
setRow(currentItem.moduleId, { state: "failed", error: e?.message ?? "AI generation failed." });
|
|
5049
|
+
}
|
|
5050
|
+
};
|
|
5051
|
+
const handleAcceptGenerated = () => {
|
|
5052
|
+
if (!result || !currentItem || !currentRow?.generated) return;
|
|
5053
|
+
setResult(applyReviewAction(result, currentItem.moduleId, "ai", currentRow.generated));
|
|
5054
|
+
advanceReview();
|
|
5055
|
+
};
|
|
5056
|
+
const [marketplacePickerOpen, setMarketplacePickerOpen] = useState6(false);
|
|
5057
|
+
const handlePickMarketplace = (transplant) => {
|
|
5058
|
+
if (!result || !currentItem) return;
|
|
5059
|
+
setResult(applyReviewAction(result, currentItem.moduleId, "marketplace", transplant));
|
|
5060
|
+
setRow(currentItem.moduleId, { state: "kept" });
|
|
5061
|
+
setMarketplacePickerOpen(false);
|
|
5062
|
+
advanceReview();
|
|
5063
|
+
};
|
|
5064
|
+
const handleKeepAllPlaceholders = () => {
|
|
5065
|
+
if (!result) return;
|
|
5066
|
+
const patch = {};
|
|
5067
|
+
for (const item of originalReviewItems) {
|
|
5068
|
+
const rowState = rowStates[item.moduleId]?.state ?? "pending";
|
|
5069
|
+
if (rowState !== "pending") continue;
|
|
5070
|
+
if (item.flaggedOff) continue;
|
|
5071
|
+
if (item.status !== "placeholder" && item.status !== "template") continue;
|
|
5072
|
+
patch[item.moduleId] = { state: "kept" };
|
|
5073
|
+
}
|
|
5074
|
+
if (Object.keys(patch).length) setRowStates((prev) => ({ ...prev, ...patch }));
|
|
5075
|
+
const remainingIndex = originalReviewItems.findIndex((item) => (patch[item.moduleId]?.state ?? rowStates[item.moduleId]?.state ?? "pending") === "pending");
|
|
5076
|
+
if (remainingIndex >= 0) {
|
|
5077
|
+
setReviewIndex(remainingIndex);
|
|
5078
|
+
const remainingItem = originalReviewItems[remainingIndex];
|
|
5079
|
+
if (remainingItem?.flaggedOff) {
|
|
5080
|
+
const actionText = hasMarketplaceCandidates(remainingItem.seWidget.type) ? "Skip, Marketplace, or Generate with AI" : "Skip or Generate with AI";
|
|
5081
|
+
notify.warning(`Choose ${actionText} for the flagged-off widget.`);
|
|
5082
|
+
} else {
|
|
5083
|
+
notify.warning("Review the remaining widget before continuing.");
|
|
5084
|
+
}
|
|
5085
|
+
return;
|
|
5086
|
+
}
|
|
5087
|
+
setStep("confirm");
|
|
5088
|
+
};
|
|
5089
|
+
const handleSkipAll = () => {
|
|
5090
|
+
if (!result) return;
|
|
5091
|
+
const toSkip = /* @__PURE__ */ new Set();
|
|
5092
|
+
const patch = {};
|
|
5093
|
+
for (const item of originalReviewItems) {
|
|
5094
|
+
const rowState = rowStates[item.moduleId]?.state ?? "pending";
|
|
5095
|
+
if (rowState !== "pending") continue;
|
|
5096
|
+
toSkip.add(item.moduleId);
|
|
5097
|
+
patch[item.moduleId] = { state: "skipped" };
|
|
5098
|
+
}
|
|
5099
|
+
if (toSkip.size === 0) {
|
|
5100
|
+
setStep("confirm");
|
|
5101
|
+
return;
|
|
5102
|
+
}
|
|
5103
|
+
const nextLayers = (result.overlay.settings.layers ?? []).filter((l) => !toSkip.has(l.id));
|
|
5104
|
+
const modules = { ...result.overlay.settings.modules ?? {} };
|
|
5105
|
+
for (const id of toSkip) delete modules[id];
|
|
5106
|
+
const reviewItems = result.reviewItems.filter((r) => !toSkip.has(r.moduleId));
|
|
5107
|
+
setResult({
|
|
5108
|
+
...result,
|
|
5109
|
+
overlay: {
|
|
5110
|
+
...result.overlay,
|
|
5111
|
+
settings: { ...result.overlay.settings, layers: nextLayers, modules },
|
|
5112
|
+
layers_count: nextLayers.length
|
|
5113
|
+
},
|
|
5114
|
+
reviewItems
|
|
5115
|
+
});
|
|
5116
|
+
setRowStates((prev) => ({ ...prev, ...patch }));
|
|
5117
|
+
setStep("confirm");
|
|
5118
|
+
};
|
|
5119
|
+
const handleFinalImport = useCallback3(async () => {
|
|
5120
|
+
if (!result) return;
|
|
5121
|
+
setImporting(true);
|
|
5122
|
+
try {
|
|
5123
|
+
const body = {
|
|
5124
|
+
name: options.name.trim() || result.overlay.name,
|
|
5125
|
+
description: result.overlay.description,
|
|
5126
|
+
settings: result.overlay.settings
|
|
5127
|
+
};
|
|
5128
|
+
const { uuid } = await saveOverlay(body);
|
|
5129
|
+
notify.success(`Imported overlay from StreamElements.`);
|
|
5130
|
+
mirrorAbortRef.current?.abort();
|
|
5131
|
+
onClose();
|
|
5132
|
+
if (uuid) onComplete({ overlayId: uuid });
|
|
5133
|
+
} catch (err) {
|
|
5134
|
+
notify.error(`Import failed: ${extractErrorMessage(err)}`);
|
|
5135
|
+
} finally {
|
|
5136
|
+
setImporting(false);
|
|
5137
|
+
}
|
|
5138
|
+
}, [notify, onClose, onComplete, options.name, result, saveOverlay]);
|
|
5139
|
+
const stepOrder = ["url", "discovery", "options", "mirror", "review", "confirm"];
|
|
5140
|
+
const goBack = () => {
|
|
5141
|
+
if (step === "review" && reviewIndex > 0) {
|
|
5142
|
+
setReviewIndex(reviewIndex - 1);
|
|
5143
|
+
return;
|
|
5144
|
+
}
|
|
5145
|
+
const idx = stepOrder.indexOf(step);
|
|
5146
|
+
if (idx <= 0) return;
|
|
5147
|
+
let prev = stepOrder[idx - 1];
|
|
5148
|
+
if (prev === "mirror" && !options.mirrorAssets) prev = stepOrder[idx - 2];
|
|
5149
|
+
if (prev) setStep(prev);
|
|
5150
|
+
};
|
|
5151
|
+
const goNext = () => {
|
|
5152
|
+
if (step === "url") {
|
|
5153
|
+
void handleLoad();
|
|
5154
|
+
return;
|
|
5155
|
+
}
|
|
5156
|
+
if (step === "discovery") {
|
|
5157
|
+
setStep("options");
|
|
5158
|
+
return;
|
|
5159
|
+
}
|
|
5160
|
+
if (step === "options") {
|
|
5161
|
+
if (options.mirrorAssets && assetUrls.length > 0) setStep("mirror");
|
|
5162
|
+
else if (originalReviewItems.length > 0) setStep("review");
|
|
5163
|
+
else setStep("confirm");
|
|
5164
|
+
return;
|
|
5165
|
+
}
|
|
5166
|
+
if (step === "mirror") {
|
|
5167
|
+
if (originalReviewItems.length > 0) setStep("review");
|
|
5168
|
+
else setStep("confirm");
|
|
5169
|
+
return;
|
|
5170
|
+
}
|
|
5171
|
+
if (step === "review") {
|
|
5172
|
+
if (currentItem) {
|
|
5173
|
+
if (currentRow?.state === "generated") {
|
|
5174
|
+
handleAcceptGenerated();
|
|
5175
|
+
} else if (currentRow?.state === "pending") {
|
|
5176
|
+
if (currentItem.flaggedOff) {
|
|
5177
|
+
const actionText = hasMarketplaceCandidates(currentItem.seWidget.type) ? "Skip, Marketplace, or Generate with AI" : "Skip or Generate with AI";
|
|
5178
|
+
notify.warning(`Choose ${actionText} for the flagged-off widget.`);
|
|
5179
|
+
return;
|
|
5180
|
+
}
|
|
5181
|
+
handleKeep();
|
|
5182
|
+
} else {
|
|
5183
|
+
advanceReview();
|
|
5184
|
+
}
|
|
5185
|
+
}
|
|
5186
|
+
return;
|
|
5187
|
+
}
|
|
5188
|
+
if (step === "confirm") {
|
|
5189
|
+
void handleFinalImport();
|
|
5190
|
+
return;
|
|
5191
|
+
}
|
|
5192
|
+
};
|
|
5193
|
+
const nextLabel = (() => {
|
|
5194
|
+
if (step === "url") return loading ? "Loading\u2026" : "Load overlay";
|
|
5195
|
+
if (step === "discovery") return "Continue";
|
|
5196
|
+
if (step === "options") return "Continue";
|
|
5197
|
+
if (step === "mirror") return mirrorRunning ? "Working\u2026" : "Continue";
|
|
5198
|
+
if (step === "review") return currentRow?.state === "generated" ? "Use & continue" : "Continue";
|
|
5199
|
+
if (step === "confirm") return importing ? "Importing\u2026" : "Create overlay";
|
|
5200
|
+
return "Next";
|
|
5201
|
+
})();
|
|
5202
|
+
const nextDisabled = (() => {
|
|
5203
|
+
if (step === "url") return loading || !url.trim();
|
|
5204
|
+
if (step === "mirror") return mirrorRunning;
|
|
5205
|
+
if (step === "review") return currentRow?.state === "generating" || currentRow?.state === "pending" && currentItem?.flaggedOff;
|
|
5206
|
+
if (step === "confirm") return importing;
|
|
5207
|
+
return false;
|
|
5208
|
+
})();
|
|
5209
|
+
const stepperIndex = stepOrder.indexOf(step);
|
|
5210
|
+
const visibleSteps = [
|
|
5211
|
+
{ key: "url", label: "Load" },
|
|
5212
|
+
{ key: "discovery", label: "Discovery" },
|
|
5213
|
+
{ key: "options", label: "Options" },
|
|
5214
|
+
...options.mirrorAssets && assetUrls.length > 0 ? [{ key: "mirror", label: "Assets" }] : [],
|
|
5215
|
+
...originalReviewItems.length > 0 ? [{ key: "review", label: `Review (${originalReviewItems.length})` }] : [],
|
|
5216
|
+
{ key: "confirm", label: "Confirm" }
|
|
5217
|
+
];
|
|
5218
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ui-flex-column ui-gap-2", style: { minWidth: 680 }, children: [
|
|
5219
|
+
result && /* @__PURE__ */ jsx13("div", { className: "ui-flex-row ui-gap-2", style: { flexWrap: "wrap", paddingBottom: 8, borderBottom: "1px solid var(--ui-border, #2a2c31)" }, children: visibleSteps.map((s, i) => /* @__PURE__ */ jsx13(StepDot, { num: i + 1, label: s.label, active: s.key === step, done: visibleSteps.findIndex((v) => v.key === step) > i }, s.key)) }),
|
|
5220
|
+
step === "url" && /* @__PURE__ */ jsx13(StepURL, { url, setUrl, error: loadError, busy: loading }),
|
|
5221
|
+
step === "discovery" && result && /* @__PURE__ */ jsx13(StepDiscovery, { result, assetCount: assetUrls.length }),
|
|
5222
|
+
step === "options" && /* @__PURE__ */ jsx13(StepOptions, { options, setOptions, assetCount: assetUrls.length }),
|
|
5223
|
+
step === "mirror" && /* @__PURE__ */ jsx13(StepMirror, { rows: mirrorRows, running: mirrorRunning, onRetry: retryMirrorRow }),
|
|
5224
|
+
step === "review" && currentItem && result && !marketplacePickerOpen && /* @__PURE__ */ jsx13(
|
|
5225
|
+
StepReview,
|
|
5226
|
+
{
|
|
5227
|
+
item: currentItem,
|
|
5228
|
+
index: reviewIndex,
|
|
5229
|
+
total: originalReviewItems.length,
|
|
5230
|
+
state: currentRow?.state ?? "pending",
|
|
5231
|
+
error: currentRow?.error,
|
|
5232
|
+
generated: currentRow?.generated,
|
|
5233
|
+
canvas: { width: result.overlay.settings.metadata.width, height: result.overlay.settings.metadata.height },
|
|
5234
|
+
onSkip: handleSkip,
|
|
5235
|
+
onKeep: handleKeep,
|
|
5236
|
+
onGenerate: handleGenerate,
|
|
5237
|
+
onAccept: handleAcceptGenerated,
|
|
5238
|
+
onRetry: handleGenerate,
|
|
5239
|
+
onPickMarketplace: () => setMarketplacePickerOpen(true),
|
|
5240
|
+
onKeepAllPlaceholders: handleKeepAllPlaceholders,
|
|
5241
|
+
onSkipAll: handleSkipAll,
|
|
5242
|
+
remainingCount: originalReviewItems.filter((r) => (rowStates[r.moduleId]?.state ?? "pending") === "pending").length,
|
|
5243
|
+
marketplaceAvailable: hasMarketplaceCandidates(currentItem.seWidget.type)
|
|
5244
|
+
}
|
|
5245
|
+
),
|
|
5246
|
+
step === "review" && currentItem && marketplacePickerOpen && /* @__PURE__ */ jsx13(
|
|
5247
|
+
MarketplacePicker,
|
|
5248
|
+
{
|
|
5249
|
+
seWidgetType: currentItem.seWidget.type,
|
|
5250
|
+
fetchMarketplaceOverlay,
|
|
5251
|
+
CustomEmbed,
|
|
5252
|
+
onPick: handlePickMarketplace,
|
|
5253
|
+
onCancel: () => setMarketplacePickerOpen(false)
|
|
5254
|
+
}
|
|
5255
|
+
),
|
|
5256
|
+
step === "confirm" && result && /* @__PURE__ */ jsx13(StepConfirm, { result, options, mirrorRows, rowStates }),
|
|
5257
|
+
/* @__PURE__ */ jsxs7("div", { className: "ui-flex-row ui-gap-2", style: { justifyContent: "flex-end", marginTop: 12 }, children: [
|
|
5258
|
+
/* @__PURE__ */ jsx13(
|
|
5259
|
+
"button",
|
|
5260
|
+
{
|
|
5261
|
+
type: "button",
|
|
5262
|
+
className: "ui-button",
|
|
5263
|
+
onClick: () => {
|
|
5264
|
+
mirrorAbortRef.current?.abort();
|
|
5265
|
+
onClose();
|
|
5266
|
+
},
|
|
5267
|
+
disabled: loading || importing,
|
|
5268
|
+
children: translate("action.cancel", "Cancel")
|
|
5269
|
+
}
|
|
5270
|
+
),
|
|
5271
|
+
stepperIndex > 0 && /* @__PURE__ */ jsx13("button", { type: "button", className: "ui-button", onClick: goBack, disabled: loading || importing || mirrorRunning || currentRow?.state === "generating", children: "Back" }),
|
|
5272
|
+
/* @__PURE__ */ jsx13("button", { type: "button", className: "ui-button ui-button-purple", onClick: goNext, disabled: nextDisabled, children: nextLabel })
|
|
5273
|
+
] })
|
|
5274
|
+
] });
|
|
5275
|
+
}
|
|
5276
|
+
function extractErrorMessage(err) {
|
|
5277
|
+
if (!err) return "Failed";
|
|
5278
|
+
const e = err;
|
|
5279
|
+
return e?.response?.data?.message || e?.response?.data?.error || e?.message || "Failed";
|
|
5280
|
+
}
|
|
5281
|
+
|
|
5282
|
+
// src/se-import/index.ts
|
|
5283
|
+
var REVIEW_REASONS = {
|
|
5284
|
+
"se-widget-bit-boss": "No native Lumia equivalent \u2014 bit boss fight bar with HP/damage states.",
|
|
5285
|
+
"se-widget-hype-cup": "No native Lumia equivalent \u2014 Box2D physics stacking animation.",
|
|
5286
|
+
"se-widget-train": "No native Lumia equivalent \u2014 animated subscriber/event train.",
|
|
5287
|
+
"se-widget-media-share": "No native Lumia equivalent \u2014 viewer-submitted media player.",
|
|
5288
|
+
"se-widget-contest": "No native Lumia equivalent \u2014 SE-specific contest widget.",
|
|
5289
|
+
"se-widget-giveaway": "No native Lumia equivalent \u2014 SE giveaway service.",
|
|
5290
|
+
"se-widget-botcounter": "No native Lumia equivalent \u2014 chatter/message counter.",
|
|
5291
|
+
"se-widget-top-cheerers-list": 'Lumia loyaltyleaderboard needs a "source" extension before it can render cheer rankings.',
|
|
5292
|
+
"se-widget-top-gifters-list": 'Lumia loyaltyleaderboard needs a "source" extension before it can render gifter rankings.',
|
|
5293
|
+
"se-widget-top-tippers-list": 'Lumia loyaltyleaderboard needs a "source" extension before it can render tipper rankings.',
|
|
5294
|
+
"se-widget-snow": "Seasonal effect \u2014 needs a particle template in Lumia.",
|
|
5295
|
+
"se-widget-halloween": "Seasonal effect \u2014 needs a Lumia template.",
|
|
5296
|
+
"se-widget-halloween-2019": "Seasonal effect \u2014 needs a Lumia template.",
|
|
5297
|
+
"se-widget-xmas": "Seasonal effect \u2014 needs a Lumia template.",
|
|
5298
|
+
"se-widget-valentine": "Seasonal effect \u2014 needs a Lumia template.",
|
|
5299
|
+
"se-widget-easter": "Seasonal effect \u2014 needs a Lumia template.",
|
|
5300
|
+
"se-widget-world-cup": "Seasonal effect \u2014 needs a Lumia template."
|
|
5301
|
+
};
|
|
5302
|
+
function reasonFor(seType, status, flaggedOff) {
|
|
5303
|
+
if (flaggedOff && FLAG_OFF_REASONS[seType]) return FLAG_OFF_REASONS[seType];
|
|
5304
|
+
return REVIEW_REASONS[seType] ?? (status === "template" ? "Imported as a generic template stub." : "No native mapping yet \u2014 imported as a labelled text placeholder.");
|
|
5305
|
+
}
|
|
5306
|
+
function extractSEOverlayId(input) {
|
|
5307
|
+
const trimmed = input.trim();
|
|
5308
|
+
const m = trimmed.match(/[0-9a-f]{24}/i);
|
|
5309
|
+
return m ? m[0] : null;
|
|
5310
|
+
}
|
|
5311
|
+
function extractSEPreviewParts(input) {
|
|
5312
|
+
const trimmed = input.trim();
|
|
5313
|
+
const m = trimmed.match(/streamelements\.com\/overlay\/([0-9a-f]{24})\/([A-Za-z0-9_-]+)/i);
|
|
5314
|
+
if (!m) return null;
|
|
5315
|
+
return { overlayId: m[1], apikey: m[2] };
|
|
5316
|
+
}
|
|
5317
|
+
function buildBootstrapUrl(overlayId) {
|
|
5318
|
+
return `https://api.streamelements.com/kappa/v2/overlays/${overlayId}/bootstrap?isEditor=false&isMobile=false&isObs=false&isObsLive=false&isXsplit=false`;
|
|
5319
|
+
}
|
|
5320
|
+
async function fetchSEBootstrap({ overlayId, apikey }) {
|
|
5321
|
+
const res = await fetch(buildBootstrapUrl(overlayId), {
|
|
5322
|
+
method: "GET",
|
|
5323
|
+
headers: { Accept: "application/json", Authorization: `apikey ${apikey}` }
|
|
5324
|
+
});
|
|
5325
|
+
if (!res.ok) {
|
|
5326
|
+
let detail = "";
|
|
5327
|
+
try {
|
|
5328
|
+
const body = await res.json();
|
|
5329
|
+
detail = body?.message ? ` \u2014 ${body.message}` : "";
|
|
5330
|
+
} catch {
|
|
5331
|
+
}
|
|
5332
|
+
const reason = res.status === 401 || res.status === 403 ? "StreamElements rejected the URL token. The preview link may have been revoked." : res.status === 404 ? "Overlay not found. Double-check the URL." : `HTTP ${res.status}`;
|
|
5333
|
+
throw new Error(`${reason}${detail}`);
|
|
5334
|
+
}
|
|
5335
|
+
const json = await res.json();
|
|
5336
|
+
if (!isSEBootstrap(json)) {
|
|
5337
|
+
throw new Error("Server returned a response that does not look like an SE bootstrap payload.");
|
|
5338
|
+
}
|
|
5339
|
+
return json;
|
|
5340
|
+
}
|
|
5341
|
+
function isSEBootstrap(value) {
|
|
5342
|
+
if (!value || typeof value !== "object") return false;
|
|
5343
|
+
const v = value;
|
|
5344
|
+
if (!v.overlay || typeof v.overlay !== "object") return false;
|
|
5345
|
+
const o = v.overlay;
|
|
5346
|
+
return Array.isArray(o.widgets);
|
|
5347
|
+
}
|
|
5348
|
+
function importSEBootstrap(bootstrap) {
|
|
5349
|
+
const seOverlay = bootstrap.overlay;
|
|
5350
|
+
const widgets = seOverlay?.widgets ?? [];
|
|
5351
|
+
const coverage = {
|
|
5352
|
+
totalWidgets: widgets.length,
|
|
5353
|
+
mappings: [],
|
|
5354
|
+
notes: []
|
|
5355
|
+
};
|
|
5356
|
+
const importCanvas = {
|
|
5357
|
+
width: seOverlay?.settings?.width ?? 1920,
|
|
5358
|
+
height: seOverlay?.settings?.height ?? 1080
|
|
5359
|
+
};
|
|
5360
|
+
setImportCanvas(importCanvas);
|
|
5361
|
+
const layers = [];
|
|
5362
|
+
const modules = {};
|
|
5363
|
+
const reviewItems = [];
|
|
5364
|
+
try {
|
|
5365
|
+
const seUidToLumiaGroupId = {};
|
|
5366
|
+
const groupWidgetByUid = {};
|
|
5367
|
+
for (const w of widgets) {
|
|
5368
|
+
if (w.type !== "se-widget-group") continue;
|
|
5369
|
+
const uid = w.variables?.uid;
|
|
5370
|
+
if (typeof uid !== "string") continue;
|
|
5371
|
+
const lumiaGroupId = nanoid3();
|
|
5372
|
+
seUidToLumiaGroupId[uid] = lumiaGroupId;
|
|
5373
|
+
groupWidgetByUid[uid] = w;
|
|
5374
|
+
}
|
|
5375
|
+
for (const uid of Object.keys(groupWidgetByUid)) {
|
|
5376
|
+
const w = groupWidgetByUid[uid];
|
|
5377
|
+
const lumiaGroupId = seUidToLumiaGroupId[uid];
|
|
5378
|
+
const parentUid = typeof w.group === "string" ? w.group : null;
|
|
5379
|
+
const parentLumiaGroupId = parentUid ? seUidToLumiaGroupId[parentUid] ?? null : null;
|
|
5380
|
+
const bounds = seCssToBounds(w.css, { width: 200, height: 200 }, importCanvas);
|
|
5381
|
+
const layer = {
|
|
5382
|
+
id: lumiaGroupId,
|
|
5383
|
+
type: "group",
|
|
5384
|
+
group: parentLumiaGroupId,
|
|
5385
|
+
bounds: {
|
|
5386
|
+
x: bounds.x,
|
|
5387
|
+
y: bounds.y,
|
|
5388
|
+
width: bounds.width,
|
|
5389
|
+
height: bounds.height,
|
|
5390
|
+
opacity: bounds.opacity,
|
|
5391
|
+
zIndex: bounds.zIndex,
|
|
5392
|
+
rotate: 0,
|
|
5393
|
+
scale: [1, 1],
|
|
5394
|
+
matrix: ""
|
|
5395
|
+
},
|
|
5396
|
+
state: {
|
|
5397
|
+
locked: w.locked ?? false,
|
|
5398
|
+
visible: w.visible ?? true,
|
|
5399
|
+
// SE's `variables.expanded` is the editor's collapsed/open state.
|
|
5400
|
+
expanded: w.variables?.expanded ?? true
|
|
5401
|
+
}
|
|
5402
|
+
};
|
|
5403
|
+
const module = {
|
|
5404
|
+
id: lumiaGroupId,
|
|
5405
|
+
loaded: true,
|
|
5406
|
+
settings: { title: w.name ?? "Group", type: "group" },
|
|
5407
|
+
lights: [],
|
|
5408
|
+
css: {},
|
|
5409
|
+
content: {
|
|
5410
|
+
se_provenance: { widget: w, reason: "Imported as native group", status: "group" }
|
|
5411
|
+
},
|
|
5412
|
+
events: {},
|
|
5413
|
+
variables: {}
|
|
5414
|
+
};
|
|
5415
|
+
layers.push(layer);
|
|
5416
|
+
modules[lumiaGroupId] = module;
|
|
5417
|
+
recordCoverage(coverage, { unit: { layer, module }, status: "direct", lumiaType: "group" }, w.type);
|
|
5418
|
+
}
|
|
5419
|
+
for (const w of widgets) {
|
|
5420
|
+
if (w.type === "se-widget-group") continue;
|
|
5421
|
+
const result = dispatch(w);
|
|
5422
|
+
if (typeof w.group === "string") {
|
|
5423
|
+
const parentLumiaGroupId = seUidToLumiaGroupId[w.group];
|
|
5424
|
+
if (parentLumiaGroupId) {
|
|
5425
|
+
result.unit.layer.group = parentLumiaGroupId;
|
|
5426
|
+
}
|
|
5427
|
+
}
|
|
5428
|
+
layers.push(result.unit.layer);
|
|
5429
|
+
const module = result.unit.module;
|
|
5430
|
+
if (result.status === "placeholder" || result.status === "template") {
|
|
5431
|
+
module.content = {
|
|
5432
|
+
...module.content ?? {},
|
|
5433
|
+
se_provenance: {
|
|
5434
|
+
widget: w,
|
|
5435
|
+
reason: reasonFor(w.type, result.status, result.flaggedOff),
|
|
5436
|
+
status: result.status,
|
|
5437
|
+
flaggedOff: result.flaggedOff
|
|
5438
|
+
}
|
|
5439
|
+
};
|
|
5440
|
+
reviewItems.push({
|
|
5441
|
+
moduleId: module.id,
|
|
5442
|
+
seWidget: w,
|
|
5443
|
+
status: result.status,
|
|
5444
|
+
reason: reasonFor(w.type, result.status, result.flaggedOff),
|
|
5445
|
+
flaggedOff: result.flaggedOff
|
|
5446
|
+
});
|
|
5447
|
+
}
|
|
5448
|
+
modules[module.id] = module;
|
|
5449
|
+
recordCoverage(coverage, result, w.type);
|
|
5450
|
+
}
|
|
5451
|
+
if (coverage.mappings.some((m) => m.status === "placeholder")) {
|
|
5452
|
+
coverage.notes.push("Some widgets imported as placeholder text layers \u2014 see SE/05-widget-to-module-mapping.md for status.");
|
|
5453
|
+
}
|
|
5454
|
+
if (coverage.mappings.some((m) => m.seType === "se-widget-merch-goal")) {
|
|
5455
|
+
coverage.notes.push("Merch-goal widgets imported as generic goals \u2014 see SE/03-missing-variables.md \xA78 for the missing data source.");
|
|
5456
|
+
}
|
|
5457
|
+
if (coverage.mappings.some((m) => m.seType === "se-widget-custom-event-list")) {
|
|
5458
|
+
coverage.notes.push("\u26A0 Custom widgets are experimental \u2014 they run under the SE compatibility shim (Embed.tsx) which handles most SE APIs but may not cover every edge case. Verify each custom layer renders correctly in the editor.");
|
|
5459
|
+
}
|
|
5460
|
+
const overlay = {
|
|
5461
|
+
uuid: "",
|
|
5462
|
+
listen_id: "",
|
|
5463
|
+
name: seOverlay?.name ? `[SE] ${seOverlay.name}` : `Imported from StreamElements (${seOverlay?._id ?? ""})`,
|
|
5464
|
+
description: seOverlay?._id ? `Imported from StreamElements overlay ${seOverlay._id}` : "Imported from StreamElements",
|
|
5465
|
+
settings: {
|
|
5466
|
+
metadata: {
|
|
5467
|
+
width: seOverlay?.settings?.width ?? 1920,
|
|
5468
|
+
height: seOverlay?.settings?.height ?? 1080
|
|
5469
|
+
},
|
|
5470
|
+
layers,
|
|
5471
|
+
modules
|
|
5472
|
+
},
|
|
5473
|
+
metadata: {
|
|
5474
|
+
width: seOverlay?.settings?.width ?? null,
|
|
5475
|
+
height: seOverlay?.settings?.height ?? null
|
|
5476
|
+
},
|
|
5477
|
+
layers_count: layers.length,
|
|
5478
|
+
hasFullSettings: true
|
|
5479
|
+
};
|
|
5480
|
+
return { overlay, coverage, reviewItems };
|
|
5481
|
+
} finally {
|
|
5482
|
+
setImportCanvas(null);
|
|
5483
|
+
}
|
|
5484
|
+
}
|
|
5485
|
+
function applyReviewAction(result, moduleId, action, payload) {
|
|
5486
|
+
if (action === "keep") return result;
|
|
5487
|
+
const layers = result.overlay.settings.layers ?? [];
|
|
5488
|
+
const modules = { ...result.overlay.settings.modules ?? {} };
|
|
5489
|
+
if (action === "skip") {
|
|
5490
|
+
delete modules[moduleId];
|
|
5491
|
+
const nextLayers = layers.filter((l) => l.id !== moduleId);
|
|
5492
|
+
const reviewItems2 = result.reviewItems.filter((r) => r.moduleId !== moduleId);
|
|
5493
|
+
return {
|
|
5494
|
+
...result,
|
|
5495
|
+
overlay: { ...result.overlay, settings: { ...result.overlay.settings, layers: nextLayers, modules }, layers_count: nextLayers.length },
|
|
5496
|
+
reviewItems: reviewItems2
|
|
5497
|
+
};
|
|
5498
|
+
}
|
|
5499
|
+
if (action === "marketplace") {
|
|
5500
|
+
const transplant = payload;
|
|
5501
|
+
const existing2 = modules[moduleId];
|
|
5502
|
+
const existingLayer = layers.find((l) => l.id === moduleId);
|
|
5503
|
+
if (!existing2 || !existingLayer || !transplant) return result;
|
|
5504
|
+
const newLayer = {
|
|
5505
|
+
...transplant.layer,
|
|
5506
|
+
id: moduleId,
|
|
5507
|
+
group: existingLayer.group ?? null,
|
|
5508
|
+
bounds: existingLayer.bounds,
|
|
5509
|
+
state: existingLayer.state
|
|
5510
|
+
};
|
|
5511
|
+
const provenance2 = existing2.content?.se_provenance;
|
|
5512
|
+
const newModule = {
|
|
5513
|
+
...transplant.module,
|
|
5514
|
+
id: moduleId,
|
|
5515
|
+
content: { ...transplant.module.content ?? {}, se_provenance: provenance2 }
|
|
5516
|
+
};
|
|
5517
|
+
const rootOldNewId = transplant.layer.id;
|
|
5518
|
+
const remappedExtras = (transplant.extras ?? []).map((e) => ({
|
|
5519
|
+
layer: e.layer.group === rootOldNewId ? { ...e.layer, group: moduleId } : e.layer,
|
|
5520
|
+
module: e.module
|
|
5521
|
+
}));
|
|
5522
|
+
const nextLayers = layers.map((l) => l.id === moduleId ? newLayer : l);
|
|
5523
|
+
for (const extra of remappedExtras) {
|
|
5524
|
+
nextLayers.push(extra.layer);
|
|
5525
|
+
modules[extra.module.id] = extra.module;
|
|
5526
|
+
}
|
|
5527
|
+
modules[moduleId] = newModule;
|
|
5528
|
+
const reviewItems2 = result.reviewItems.filter((r) => r.moduleId !== moduleId);
|
|
5529
|
+
return {
|
|
5530
|
+
...result,
|
|
5531
|
+
overlay: {
|
|
5532
|
+
...result.overlay,
|
|
5533
|
+
settings: { ...result.overlay.settings, layers: nextLayers, modules },
|
|
5534
|
+
layers_count: nextLayers.length
|
|
5535
|
+
},
|
|
5536
|
+
reviewItems: reviewItems2
|
|
5537
|
+
};
|
|
5538
|
+
}
|
|
5539
|
+
const existing = modules[moduleId];
|
|
5540
|
+
const generated = payload;
|
|
5541
|
+
if (!existing || !generated) return result;
|
|
5542
|
+
const provenance = existing.content?.se_provenance;
|
|
5543
|
+
const replaced = {
|
|
5544
|
+
...existing,
|
|
5545
|
+
settings: { ...existing.settings ?? {}, type: "custom" },
|
|
5546
|
+
css: {},
|
|
5547
|
+
// discard the placeholder's red-warning styling
|
|
5548
|
+
content: {
|
|
5549
|
+
codeId: generated.codeId ?? `ai-${moduleId}`,
|
|
5550
|
+
html: generated.html ?? "",
|
|
5551
|
+
css: generated.css ?? "",
|
|
5552
|
+
js: generated.js ?? "",
|
|
5553
|
+
data: parseLooseJson(generated.data) ?? {},
|
|
5554
|
+
configs: parseLooseJson(generated.configs) ?? [],
|
|
5555
|
+
flavor: "ai-generated",
|
|
5556
|
+
se_provenance: provenance
|
|
5557
|
+
}
|
|
5558
|
+
};
|
|
5559
|
+
modules[moduleId] = replaced;
|
|
5560
|
+
const reviewItems = result.reviewItems.filter((r) => r.moduleId !== moduleId);
|
|
5561
|
+
return {
|
|
5562
|
+
...result,
|
|
5563
|
+
overlay: { ...result.overlay, settings: { ...result.overlay.settings, modules } },
|
|
5564
|
+
reviewItems
|
|
5565
|
+
};
|
|
5566
|
+
}
|
|
5567
|
+
function parseLooseJson(value) {
|
|
5568
|
+
if (value == null) return void 0;
|
|
5569
|
+
if (typeof value !== "string") return value;
|
|
5570
|
+
try {
|
|
5571
|
+
return JSON.parse(value);
|
|
5572
|
+
} catch {
|
|
5573
|
+
return value;
|
|
5574
|
+
}
|
|
5575
|
+
}
|
|
5576
|
+
function getAILandingBounds(widget, canvas) {
|
|
5577
|
+
const bounds = seCssToBounds(widget.css, LUMIA_DEFAULT_SIZES.text, canvas);
|
|
5578
|
+
return { width: bounds.width, height: bounds.height };
|
|
5579
|
+
}
|
|
5580
|
+
function buildAIPromptForSEWidget(widget, canvas) {
|
|
5581
|
+
const variables = widget.variables ?? {};
|
|
5582
|
+
const listener = typeof widget.listener === "string" ? widget.listener : null;
|
|
5583
|
+
const listeners = widget.listeners && typeof widget.listeners === "object" && !Array.isArray(widget.listeners) ? Object.keys(widget.listeners) : null;
|
|
5584
|
+
const landing = getAILandingBounds(widget, canvas);
|
|
5585
|
+
return [
|
|
5586
|
+
"Recreate a StreamElements overlay widget as a Lumia Stream custom overlay (HTML + CSS + JS).",
|
|
5587
|
+
"",
|
|
5588
|
+
`StreamElements widget type: ${widget.type}`,
|
|
5589
|
+
listener ? `Primary event listener: ${listener}` : "",
|
|
5590
|
+
listeners ? `Subscribes to events: ${listeners.join(", ")}` : "",
|
|
5591
|
+
`Canvas: ${landing.width} \xD7 ${landing.height}`,
|
|
5592
|
+
"",
|
|
5593
|
+
"Widget configuration (JSON):",
|
|
5594
|
+
"```json",
|
|
5595
|
+
JSON.stringify(variables, null, 2).slice(0, 6e3),
|
|
5596
|
+
"```",
|
|
5597
|
+
"",
|
|
5598
|
+
"Constraints \u2014 your output must run inside a Lumia Custom Overlay sandboxed iframe:",
|
|
5599
|
+
'- Use `window.Overlay.on("alert", handler)` / `window.Overlay.on("chat", handler)` to receive Lumia events.',
|
|
5600
|
+
"- Lumia template variables use double-brace syntax: {{username}}, {{amount}}, {{message}}, {{currency}}.",
|
|
5601
|
+
"- The `window.DATA` object holds user-configurable values (mirrors your `configs`).",
|
|
5602
|
+
"- DO NOT depend on StreamElements globals (no SE_API, no jQuery).",
|
|
5603
|
+
"- Keep dependencies inline or via CDN <link>/<script> tags inside the HTML.",
|
|
5604
|
+
"",
|
|
5605
|
+
"Match the SE widget's visible behavior as closely as you can. Return the result via the `upsertOverlayTabs` function call with `html`, `css`, `js`, plus a `configs` array describing any tunable fields."
|
|
5606
|
+
].filter(Boolean).join("\n");
|
|
5607
|
+
}
|
|
2712
5608
|
export {
|
|
5609
|
+
FLAG_OFF_REASONS,
|
|
2713
5610
|
LSButton,
|
|
2714
5611
|
LSCheckbox,
|
|
2715
5612
|
LSCheckboxField,
|
|
@@ -2725,11 +5622,31 @@ export {
|
|
|
2725
5622
|
LSVariableInputField,
|
|
2726
5623
|
LSVariableInputProvider,
|
|
2727
5624
|
MEDIA_PREVIEW_USER_LEVEL_VALUES,
|
|
5625
|
+
MarketplacePicker,
|
|
5626
|
+
SEImportWizard,
|
|
5627
|
+
SE_IMPORT_FLAGS,
|
|
5628
|
+
SE_WIDGET_TO_MARKETPLACE_CANDIDATES,
|
|
5629
|
+
applyReviewAction,
|
|
5630
|
+
buildAIPromptForSEWidget,
|
|
5631
|
+
buildBootstrapUrl,
|
|
2728
5632
|
buildChatMessageContent,
|
|
2729
5633
|
codeMirrorlinterOptions,
|
|
5634
|
+
extractSEOverlayId,
|
|
5635
|
+
extractSEPreviewParts,
|
|
5636
|
+
fetchSEBootstrap,
|
|
5637
|
+
filenameFromURL,
|
|
5638
|
+
findSEAssetURLs,
|
|
5639
|
+
getAILandingBounds,
|
|
5640
|
+
getMarketplaceCandidates,
|
|
2730
5641
|
getMediaPreviewFromUrl,
|
|
2731
5642
|
getNormalizedUserLevels,
|
|
5643
|
+
hasMarketplaceCandidates,
|
|
5644
|
+
importSEBootstrap,
|
|
2732
5645
|
isMediaPreviewAllowedForUser,
|
|
5646
|
+
isSEBootstrap,
|
|
5647
|
+
isWidgetFlaggedOff,
|
|
5648
|
+
listTransplantableLayers,
|
|
5649
|
+
mirrorOneAsset,
|
|
2733
5650
|
normalizeHttpUrl,
|
|
2734
5651
|
normalizeMediaPreviewUserLevels,
|
|
2735
5652
|
parseMessageLinks,
|
|
@@ -2737,6 +5654,8 @@ export {
|
|
|
2737
5654
|
resolveMediaPreviewRoleSettings,
|
|
2738
5655
|
resolveMediaPreviewSetting,
|
|
2739
5656
|
resolvePlatformChatterProfileUrl,
|
|
5657
|
+
rewriteAssetURLs,
|
|
2740
5658
|
tokenizeChatMessage,
|
|
5659
|
+
transplantLayer,
|
|
2741
5660
|
variableCompletionOptions
|
|
2742
5661
|
};
|