diff --git a/README.md b/README.md index c91f5e2..fbc2e03 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The following example demonstrates a basic usage of the `` component: ```javascript import React from 'react' import Group from "@interopio/groups-ui-react"; -import "@interopio/groups-ui-react/dist/styles/styles.css"; +import "@interopio/groups-ui-react/dist/styles/groups.css"; const App = () => { return diff --git a/assets/css/groups.css b/assets/css/groups.css index 583b565..5db947f 100644 --- a/assets/css/groups.css +++ b/assets/css/groups.css @@ -1,9 +1,10 @@ +@import "overlayscrollbars/styles/overlayscrollbars.css"; @import "vars.css"; * { box-sizing: border-box; transition-timing-function: cubic-bezier(0.45, 0, 0.15, 1); - transition-duration: 250ms; + transition-duration: 240ms; transition-property: background-color, color; } @@ -11,43 +12,42 @@ body { max-width: none; max-height: none; overflow: hidden; - background-color: var(--t42-background); color: var(--t42-body-color); + background-color: var(--t42-background); } input { - font-family: var(--t42-font-family); - font-size: var(--t42-font-size); + font-family: var(--io-font-family); } #t42-group-container { display: flex; flex-direction: column; - overflow: hidden; width: 100%; - height: 100%; max-width: none; + height: 100%; max-height: none; - background-color: transparent; border-width: 0; + overflow: hidden; + background-color: transparent; /* DONT TOUCH THIS */ } #t42-frames-container { + position: relative; display: flex; flex-grow: 1; - position: relative; height: 100%; background-color: transparent; } .t42-caption-bar { + position: relative; display: flex; flex-direction: column; flex-grow: 0; flex-shrink: 0; overflow: hidden; - position: relative; } .t42-internal-caption-bar { @@ -59,51 +59,56 @@ input { flex-grow: 1; } -.t42-caption-bar:after { - width: 100%; +.t42-caption-bar::after { + position: absolute; + z-index: 1; display: block; + width: 100%; background-color: var(--t42-caption-separator-color); content: ""; - position: absolute; - z-index: 1; } .t42-caption { - overflow: hidden; align-items: center; + overflow: hidden; + font-size: var(--io-font-size); + line-height: var(--t42-line-height); white-space: nowrap; text-align: left; user-select: none; - font-size: var(--g42-font-size); } .t42-caption-editor { display: inline-block; - color: var(--t42-caption-editor-color); - margin: var(--t42-caption-editor-margin); - border: var(--spacing-1) solid hsl(var(--g42-interactive-primary)); - border-radius: var(--border-radius-4); - outline: none; min-width: 150px; + height: var(--t42-caption-editor-height); + margin: var(--t42-caption-editor-margin); padding: 0 var(--spacing-2) 0 var(--spacing-2); - white-space: nowrap; + border: var(--t42-caption-editor-border); + border-radius: var(--base-radius-default); overflow-x: hidden; + color: var(--t42-caption-editor-color); + font-size: var(--io-font-size); + white-space: nowrap; + outline: 0; } .t42-caption-editor.t42-group-caption-bar-element, .t42-caption-editor.t42-frame-caption-bar-element { margin: var(--t42-title-margin); + outline: 0; } .t42-title { - color: var(--t42-title-color); margin: var(--t42-title-margin); + color: var(--t42-title-color); + line-height: var(--t42-line-height); } .t42-move-area { - align-items: center; display: flex; flex-grow: 1; + align-items: center; min-width: var(--t42-move-area-min-width); } @@ -112,13 +117,29 @@ input { flex-direction: row; } +.t42-html-buttons-container { + position: absolute; + top: var(--spacing-4); + right: var(--spacing-4); + display: flex; + background-color: var(--t42-html-buttons-bar-background); +} + +.t42-html-buttons-container ul:first-of-type { + padding-left: var(--spacing-4); +} + +.t42-html-buttons-bar-element { + background-color: var(--t42-html-buttons-bar-background); +} + .t42-buttons { display: flex; flex-shrink: 0; align-items: center; + margin: 0; + padding: 0; overflow: hidden; - margin: 0px; - padding: 0px; list-style-type: none; } @@ -133,28 +154,22 @@ input { } .t42-custom-button { - height: var(--t42-custom-button-size); - width: var(--t42-custom-button-size); - background-size: cover; position: relative; -} - -.t42-custom-button { - height: var(--t42-custom-button-size); width: var(--t42-custom-button-size); + height: var(--t42-custom-button-size); background-size: cover; - position: relative; } .t42-standard-button::before, .t42-tab-channel-selector-content::before, .t42-frame-channel-selector-content::before, .t42-tab-close-button-content::before { - align-items: center; display: flex; - font-family: "io-icons"; - font-size: var(--spacing-16); + align-items: center; justify-content: center; + font-size: var(--spacing-16); + font-family: "io-icons"; + transition-property: color; content: ""; } @@ -162,14 +177,13 @@ input { fill: var(--t42-standard-button-color); } - .t42-caption-bar-button-lock, .t42-caption-bar-button-unlock, .t42-caption-bar-button-feedback, .t42-caption-bar-button-sticky, .t42-caption-bar-button-extract { - margin: var(--spacing-2) var(--spacing-2) 0 0; - border-radius: var(--border-radius-4); + margin: var(--t42-tab-bar-button-margin); + border-radius: var(--t42-tab-bar-button-radius); } .t42-caption-bar-button-lock .t42-standard-button::before, @@ -178,7 +192,7 @@ input { font-size: var(--spacing-14); } -.t42-caption-bar-button:hover .t42-standard-button-close:before { +.t42-caption-bar-button:hover .t42-standard-button-close::before { color: var(--t42-caption-bar-button-close-hover-text); } @@ -199,8 +213,9 @@ input { } .t42-tab-close-button-content::before { - height: var(--t42-tab-bar-tab-close-button-size); width: var(--t42-tab-bar-tab-close-button-size); + height: var(--t42-tab-bar-tab-close-button-size); + font-size: var(--t42-tab-bar-tab-close-button-size); } .t42-standard-button-restore::before { @@ -223,24 +238,31 @@ input { content: "\e91c"; } +.t42-standard-button-clone::before { + content: "\e91f"; +} + +.t42-standard-button-overflow::before { + content: "\e91d"; +} + .t42-standard-button-sticky::before { - content: var(--sticky-icon-off); display: block; - height: var(--spacing-14); width: var(--spacing-14); + height: var(--spacing-14); line-height: var(--spacing-14); + content: var(--sticky-icon-off); } - .t42-caption-bar-button:hover .t42-standard-button-sticky::before { content: var(--sticky-icon-off-hover); } .t42-caption-bar-button.active .t42-standard-button-sticky::before { - content: var(--sticky-icon-on); - height: var(--spacing-16); width: var(--spacing-16); - line-height: var(--spacing-16); + height: var(--spacing-16); + line-height: var(--t42-line-height); + content: var(--sticky-icon-on); } .t42-caption-bar-button.active:hover .t42-standard-button-sticky::before { @@ -249,8 +271,8 @@ input { .t42-tab-channel-selector-content::before, .t42-frame-channel-selector-content::before { + font-size: var(--spacing-14); content: "\e902"; - font-size: var(--spacing-16); } .t42-group-caption-bar { @@ -261,6 +283,10 @@ input { background-color: var(--t42-group-caption-background); } +.t42-group-caption-bar-element:focus-visible { + outline: 0; +} + .t42-group-caption-bar::after { bottom: 0; height: var(--t42-group-caption-separator-size); @@ -272,21 +298,21 @@ input { } .t42-frame { + position: absolute; display: flex; flex-direction: column; flex-grow: 0; flex-shrink: 0; - position: absolute; - overflow: hidden; - background-color: transparent; - border-style: solid; border-color: var(--t42-frame-border-color); + border-style: solid; border-width: var(--t42-frame-border-size); + overflow: hidden; + background-color: transparent; } .t42-frame-html { /* Don't touch this! We don't have borders for 'html' mode frames */ - border-width: 0px; + border-width: 0; } .t42-focused-frame { @@ -308,15 +334,16 @@ input { .t42-frame-channel-selector { align-self: center; + justify-content: center; width: var(--t42-frame-channel-selector-size); height: var(--t42-frame-channel-selector-size); margin: var(--t42-frame-channel-selector-margin); - justify-content: center; + border-radius: var(--t42-frame-channel-selector-border-radius); } .t42-frame-channel-selector-content { - width: var(--t42-standard-button-size); - height: var(--t42-standard-button-size); + width: var(--t42-frame-channel-selector-size); + height: var(--t42-frame-channel-selector-size); } .t42-frame-channel-selector-content .t42-standard-button-image { @@ -330,8 +357,8 @@ input { .t42-frame-window-container { display: flex; - flex-grow: 1; flex-direction: column; + flex-grow: 1; } .t42-frame-window { @@ -348,40 +375,41 @@ input { .t42-frame-window-footer { display: flex; - flex-grow: 0; flex-direction: column; + flex-grow: 0; background-color: var(--t42-background); } .t42-tab-bar { + position: relative; display: flex; flex-direction: column; - position: relative; } .t42-tab-bar::after { - display: block; - content: ""; position: absolute; - z-index: 1; - background-color: var(--t42-caption-separator-color); bottom: 0; - height: var(--t42-tab-bar-separator-size); + z-index: 1; + display: block; width: 100%; + height: var(--t42-tab-bar-separator-size); + background-color: var(--t42-caption-separator-color); + content: ""; } .t42-tab-bar-header { + position: relative; display: flex; flex-direction: row; flex-grow: 0; flex-shrink: 0; - overflow: hidden; - position: relative; height: var(--t42-tab-bar-height); + overflow: hidden; } .t42-tab-bar-element { background-color: var(--t42-tab-bar-background); + transition-property: background-color; } .t42-tab-bar-button { @@ -389,11 +417,10 @@ input { height: var(--t42-tab-bar-button-size); } - .t42-caption-bar-button { position: relative; - background-color: var(--t42-caption-bar-button-background); color: var(--t42-standard-button-color); + background-color: var(--t42-caption-bar-button-background); } .t42-caption-bar-button:hover { @@ -407,22 +434,24 @@ input { .t42-caption-bar-button-maximize, .t42-caption-bar-button-minimize, .t42-caption-bar-button-restore, +.t42-caption-bar-button-clone, .t42-caption-bar-button-close { width: var(--t42-caption-bar-button-width); height: var(--t42-tab-bar-height); } -.t42-tabs { +.t42-tabs, +.t42-tabs-pinned { + position: relative; display: flex; flex-direction: row; flex-grow: 0; flex-shrink: 1; + align-items: center; + padding: var(--t42-tab-bar-padding); overflow: hidden; list-style-type: none; - position: relative; - padding: 0px; - margin: var(--t42-tab-bar-tabs-margin); - border-top-right-radius: var(--border-radius-4); + -webkit-app-region: drag; } .t42-react-tab { @@ -432,38 +461,42 @@ input { } .t42-tab { + position: relative; display: flex; flex-direction: row; flex-grow: 0; flex-shrink: 1; align-items: center; - position: relative; - padding: 0px var(--spacing-8); - margin-right: var(--spacing-2); width: 150px; min-width: var(--t42-tab-bar-tab-min-width); max-width: var(--t42-tab-bar-tab-width); - background-color: var(--t42-tab-bar-tab-background); - border-top-right-radius: var(--spacing-4); + height: var(--t42-tab-bar-tab-height); + margin: var(--t42-tab-bar-tab-margin); + padding: var(--t42-tab-bar-tab-padding); + border-radius: var(--tabs-radius); border-top-left-radius: var(--spacing-4); - transition-property: padding; - + border-top-right-radius: var(--spacing-4); + background-color: var(--t42-tab-bar-tab-background); container-type: size; - + container-name: normal-tabs; + -webkit-app-region: no-drag; + /* transition-property: all; + transition-duration: 260ms; + transition-timing-function: ease-in-out; */ } .t42-tab::before { - width: var(--t42-tab-bar-tab-separator-size); - height: var(--spacing-8); position: absolute; left: calc(var(--spacing-2) * -1); + z-index: 10; display: block; - transition: 0.3s; + width: var(--t42-tab-bar-tab-separator-size); + height: var(--t42-tab-bar-tab-separator-height); background-color: var(--t42-tab-bar-tab-separator-color); - content: ""; - z-index: 10; opacity: 1; + transition: 0.3s; transition-property: opacity; + content: ""; } .t42-tab:first-of-type::before { @@ -482,8 +515,8 @@ input { .t42-tab-channel-selector { justify-content: center; - width: var(--t42-tab-bar-tab-channels-size); - height: var(--t42-tab-bar-tab-channels-size); + width: var(--t42-tab-bar-tab-channels-width); + height: var(--t42-tab-bar-tab-channels-height); margin: var(--t42-tab-bar-tab-channels-margin); border-radius: var(--t42-tab-bar-tab-channels-border-radius); background-color: transparent; @@ -493,29 +526,34 @@ input { .t42-tab-caption { flex-grow: 1; color: var(--t42-tab-bar-tab-text); - -webkit-mask-image: linear-gradient(90deg, Hsl(var(--g42-bg-00)) 75%, transparent); + mask-image: linear-gradient(90deg, Hsl(var(--io-bg-00)) 75%, transparent); } .t42-tab-caption-editor { min-width: unset; - -webkit-mask-image: none; + mask-image: none; + height: var(--spacing-12); +} + +.t42-tab-caption-editor:focus-visible { + outline: 0; } .t42-tab-close-button { margin: var(--t42-tab-bar-tab-close-button-margin); - transition-property: margin; + transition-property: margin, background-color; } .t42-tab-close-button-content { display: flex; + align-items: center; + justify-content: center; width: calc(var(--t42-tab-bar-tab-close-button-size) + var(--t42-tab-bar-tab-close-button-padding) * 2); height: calc(var(--t42-tab-bar-tab-close-button-size) + var(--t42-tab-bar-tab-close-button-padding) * 2); border-radius: 50%; - background-color: transparent; - transition-property: background-color, fill; - justify-content: center; - align-items: center; - font-size: var(--spacing-14); + background-color: var(--t42-tab-bar-tab-close-button-background); + transition-duration: 80ms; + transition-property: background-color, fill, color; } .t42-tab-close-button-content svg { @@ -528,9 +566,8 @@ input { } .t42-tab-close-button-content:hover { + color: var(--t42-tab-bar-tab-text-hover); background-color: var(--t42-tab-bar-tab-close-button-bg-hover); - color: Hsl(var(--g42-label-primary)); - } .t42-tab-close-button-content:hover .t42-standard-button-image { @@ -542,20 +579,20 @@ input { } .t42-selected-tab::before, -.t42-selected-tab+.t42-tab::before { +.t42-selected-tab + .t42-tab::before { opacity: 0; } .t42-selected-tab:hover::before { - width: calc(100% - var(--t42-tab-bar-tab-separator-size)); - height: var(--t42-tab-bar-tab-selected-separator-size); position: absolute; - left: 0px; - bottom: 0px; + bottom: 0; + left: 0; + z-index: 10; display: block; + width: calc(100% - var(--t42-tab-bar-tab-separator-size)); + height: var(--t42-tab-bar-tab-selected-separator-size); background-color: var(--t42-tab-bar-tab-selected-separator-color); content: ""; - z-index: 10; } .t42-selected-tab-caption { @@ -568,15 +605,25 @@ input { } .t42-channel-selector-content-light::before { - color: hsl(var(--g42-white)); + color: hsl(var(--io-white)); transition-property: color; } .t42-channel-selector-content-dark::before { - color: hsl(var(--g42-black)); + color: hsl(var(--io-black)); transition-property: color; } +.t42-channel-selector-direction { + width: var(--t42-channel-selector-direction-width); + height: var(--t42-channel-selector-direction-height); + gap: var(--t42-channel-selector-direction-gap); +} + +.t42-channel-selector-direction .icon { + gap: var(--t42-channel-selector-direction-gap); +} + @keyframes approaching-edge-animation { from { background-color: var(--t42-approaching-edge-start-color); @@ -588,9 +635,9 @@ input { } .t42-approaching-edge { - display: block; position: absolute; z-index: 100; + display: block; background-color: var(--t42-approaching-edge-start-color); animation: approaching-edge-animation; animation-duration: var(--t42-approaching-edge-animation-duration); @@ -606,18 +653,118 @@ input { width: var(--t42-approaching-edge-size); } +.t42-sizing-border-group { + position: absolute; + z-index: 100; + display: flex; + flex-grow: 0; + flex-shrink: 0; + margin: 0; + padding: 0; + overflow: hidden; + list-style-type: none; + background-color: var(--t42-sizing-border-group-color); + pointer-events: none; +} + +.t42-vertical-sizing-border-group { + flex-direction: column; + cursor: ew-resize; +} + +.t42-horizontal-sizing-border-group { + flex-direction: row; + cursor: ns-resize; +} + +.t42-sizing-border-group:hover { + background-color: var(--t42-hover-sizing-border-group-color); +} + +.t42-active-sizing-border-group { + z-index: 200; + background-color: var(--t42-active-sizing-border-group-color); +} + +.t42-active-sizing-border-group:hover { + background-color: var(--t42-active-sizing-border-group-color); +} + +.t42-sizing-border { + flex-shrink: 0; + margin: 0; + padding: 0; + pointer-events: auto; +} + +.t42-frame-sizing-border { + flex-grow: 0; +} + +.t42-cross-sizing-border { + flex-grow: 1; + cursor: ne-resize; +} + +.t42-active-sizing-border { + background-color: transparent; +} + .t42-skip-focus { /* We used non-standard rule to have non-empty style */ -moz-user-focus: ignore; } -.loader.active { - animation: s3 1.5s infinite linear; +@keyframes clipMe { + 0%, + 100% { + clip: rect(0, 25vh, 2px, 0); + } + + 25% { + clip: rect(0, 2px, 25vh, 0); + } + + 50% { + clip: rect(calc(25vh - 2px), 25vh, 25vh, 0); + } + + 75% { + clip: rect(0, 25vh, 25vh, calc(25vh - 2px)); + } } .loader-wrapper { - background-color: var(--t42-background); + display: flex; + flex-direction: column; flex-grow: 1; + gap: 1rem; + align-items: center; + justify-content: center; + background: var(--t42-background); +} + +.loader-wrapper .loader { + width: 2rem; + height: 2rem; + border-radius: 50%; + background: + radial-gradient(farthest-side, #999d9e 94%, rgba(0, 0, 0, 0)) center top / 4px 4px no-repeat, + conic-gradient(rgba(0, 0, 0, 0) 15%, #999d9e); + -webkit-mask: radial-gradient(farthest-side, rgba(0, 0, 0, 0) calc(100% - 4px), #000000 0); +} + +.loader-wrapper .loader-text { + margin: 0 auto; + padding: 0 0.833rem; + overflow: hidden; + color: var(--io-secondary-primary); + text-align: center; + text-overflow: ellipsis; +} + +.loader.active { + animation: s3 1.5s infinite linear; } @keyframes s3 { @@ -646,27 +793,207 @@ input { .t42-tab-flashing .t42-tab-bar-element, .t42-tab-flashing .t42-tab-caption { + color: var(--t42-tab-bar-tab-flashing-color); background-color: transparent; - color: var(--white); } -@container (max-width: 50px) { +@container normal-tabs (max-width: 50px) { .t42-tab-channel-selector { - width: 0; - margin: 0; + --t42-tab-bar-tab-channels-height:0; + --t42-tab-bar-tab-channels-width: 0; + --t42-tab-bar-tab-channels-margin: 0; } - } -@container (max-width: 40px) { +@container normal-tabs (max-width: 40px) { .t42-tab-close-button { margin: auto; } } -@container (max-width: 30px) { +@container normal-tabs (max-width: 30px) { .t42-selected-tab-caption { flex-grow: 0; width: 0; } -} \ No newline at end of file +} + +.os-scrollbar-horizontal { + z-index: 1001; +} + +.t42-tabs-overflow .t42-tab { + min-width: var(--t42-tab-bar-tab-overflowable-min-width); +} + +.t42-tabs-overflow .t42-tabs { + overflow: auto; +} + +.t42-tabs-overflow.t42-tabs-fade-right { + -webkit-mask-image: linear-gradient( + -90deg, + rgba(0, 0, 0, 0) 0, + rgba(0, 0, 0, 0.3) calc(var(--t42-tab-bar-fade-size) / 100 * 30), + rgba(0, 0, 0, 0.8) calc(var(--t42-tab-bar-fade-size) / 100 * 80), + rgba(0, 0, 0, 1) var(--t42-tab-bar-fade-size) + ); +} + +.t42-tabs-overflow.t42-tabs-fade-left { + -webkit-mask-image: linear-gradient( + 90deg, + rgba(0, 0, 0, 0) 0, + rgba(0, 0, 0, 0.3) calc(var(--t42-tab-bar-fade-size) / 100 * 30), + rgba(0, 0, 0, 0.8) calc(var(--t42-tab-bar-fade-size) / 100 * 80), + rgba(0, 0, 0, 1) var(--t42-tab-bar-fade-size) + ); +} + +.t42-tabs-overflow.t42-tabs-fade-both { + -webkit-mask-image: linear-gradient( + 90deg, + rgba(0, 0, 0, 0) 0%, + rgba(0, 0, 0, 0.3) calc(var(--t42-tab-bar-fade-size) / 100 * 30), + rgba(0, 0, 0, 0.8) calc(var(--t42-tab-bar-fade-size) / 100 * 80), + rgba(0, 0, 0, 1) var(--t42-tab-bar-fade-size), + rgba(0, 0, 0, 1) calc(100% - var(--t42-tab-bar-fade-size)), + rgba(0, 0, 0, 0.8) calc(100% - (var(--t42-tab-bar-fade-size) / 100 * 80)), + rgba(0, 0, 0, 0.3) calc(100% - (var(--t42-tab-bar-fade-size) / 100 * 30)), + rgba(0, 0, 0, 0) 100% + ); +} + +.t42-page-popup { + position: absolute; + z-index: 999; + margin-top: var(--t42-wg-tab-over-top-offset); +} + +.t42-tab-overflow-popup, +.t42-tab-context-menu { + display: flex; + flex-direction: column; + min-width: var(--t42-wg-tab-over-min-width); + max-width: var(--t42-wg-tab-over-max-width); + max-height: var(--t42-wg-tab-over-max-height); + padding: var(--t42-wg-tab-over-padding); + border-radius: var(--t42-wg-tab-over-border-radius); + overflow: auto; + background-color: var(--t42-wg-tab-over-background); +} + +.t42-tab-overflow-popup li, +.t42-tab-context-menu li { + display: flex; + gap: var(--t42-wg-tab-over-item-gap); + align-items: center; + height: var(--t42-wg-tab-over-item-height); + padding: var(--t42-wg-tab-over-item-padding); + transition-duration: 80ms; + transition-property: background-color; +} + +.t42-tab-overflow-popup li span, +.t42-tab-context-menu li span { + flex-grow: 1; + overflow: hidden; + text-wrap: nowrap; + text-overflow: clip; +} + +.t42-tab-overflow-popup li:not(.title):hover, +.t42-tab-context-menu li:not(.title):hover { + color: var(--t42-wg-tab-over-item-color-hover); + background-color: var(--t42-wg-tab-over-item-background-hover); +} + +.t42-tab-overflow-popup hr { + height: var(--t42-wg-tab-over-separator-size); + margin: var(--t42-wg-tab-over-separator-space); + border: 0; + background-color: var(--t42-wg-tab-over-separator-color); +} + +.t42-tab-overflow-popup .title { + color: var(--t42-wg-tab-over-item-title-color); + font-size: var(--t42-wg-tab-over-item-title-size); + letter-spacing: var(--t42-wg-tab-over-item-title-spacing); +} + +.t42-tabs-pinned { + min-width: 0; + flex-shrink: 0; +} + +.t42-tabs-pinned .t42-tab { + --t42-tab-bar-tab-margin: var(--t42-wg-pin-tab-margin); + --t42-tab-bar-tab-height: var(--t42-wg-pin-tab-height); + border-radius: var(--t42-wg-pin-tab-border-radius); + width: var(--t42-wg-pin-tab-width); +} + +.t42-tabs-pinned .t42-tab-caption { + mask-image: none; +} + +.t42-tabs-pinned .t42-tab { + container-name: pinned; +} + +@container pinned (min-width:1px) { + .t42-tab-close-button { + background-color: transparent; + } +} + +.t42-tabs-pinned .t42-tab-fade, +.t42-tabs-overflow .t42-tab-fade { + overflow: hidden; + width: 0; + padding: 0; + min-width: 0; + margin: 0; +} + +.t42-multi-channel-selector-content { + width: var(--t42-tab-bar-tab-channels-width); + height: var(--t42-tab-bar-tab-channels-height); + border-radius: var(--t42-tab-bar-tab-channels-border-radius); +} + +.t42-multi-channel-selector-2 { + background-image: conic-gradient( + var(--t42-multi-channel-selector-2-color-1) 0deg, + var(--t42-multi-channel-selector-2-color-1) 180deg, + var(--t42-multi-channel-selector-2-color-2) 180deg, + var(--t42-multi-channel-selector-2-color-2) 0deg + ); + mask-image: var(--t42-multi-channel-selector-2-mask); +} + +.t42-multi-channel-selector-3 { + background-image: conic-gradient( + var(--t42-multi-channel-selector-3-color-1) 0deg, + var(--t42-multi-channel-selector-3-color-1) 120deg, + var(--t42-multi-channel-selector-3-color-2) 120deg, + var(--t42-multi-channel-selector-3-color-2) 240deg, + var(--t42-multi-channel-selector-3-color-3) 240deg, + var(--t42-multi-channel-selector-3-color-3) 0deg + ); + mask-image: var(--t42-multi-channel-selector-3-mask); +} + +.t42-multi-channel-selector-4 { + background-image: conic-gradient( + var(--t42-multi-channel-selector-4-color-1) 0deg, + var(--t42-multi-channel-selector-4-color-1) 90deg, + var(--t42-multi-channel-selector-4-color-2) 90deg, + var(--t42-multi-channel-selector-4-color-2) 180deg, + var(--t42-multi-channel-selector-4-color-3) 180deg, + var(--t42-multi-channel-selector-4-color-3) 270deg, + var(--t42-multi-channel-selector-4-color-4) 270deg, + var(--t42-multi-channel-selector-4-color-4) 0deg + ); + mask-image: var(--t42-multi-channel-selector-4-mask); +} diff --git a/assets/css/vars.css b/assets/css/vars.css index 05c16ef..c14e264 100644 --- a/assets/css/vars.css +++ b/assets/css/vars.css @@ -1,111 +1,186 @@ @import "@interopio/theme/dist/io.platform.css"; :root { - - --t42-body-color: hsl(var(--g42-label-secondary)); + --t42-body-color: var(--tabs-color-default); + --t42-line-height: var(--spacing-16); --t42-title-margin: 0 0 0 var(--spacing-8); - --t42-title-color: Hsl(var(--g42-label-primary)); + --t42-title-color: var(--tabs-color-active); --t42-caption-editor-margin: 0; - --t42-caption-editor-color: Hsl(var(--g42-label-primary)); + --t42-caption-editor-color: var(--tabs-color-active); + --t42-caption-editor-border: 0; + --t42-caption-editor-height: var(--spacing-16); --t42-move-area-min-width: 30px; --t42-standard-button-size: 10px; - --t42-standard-button-color: hsl(var(--g42-label-secondary)); - --t42-standard-button-hover-color: hsl(var(--g42-label-primary)); + --t42-standard-button-color: var(--tabs-color-default); + --t42-standard-button-hover-color: var(--tabs-color-active); --t42-custom-button-size: 20px; - --t42-group-caption-background: Hsl(var(--g42-bg-01)); + --t42-group-caption-background: var(--window-header-background); --t42-group-caption-height: 30px; --t42-group-caption-separator-size: 0; --t42-frame-border-size: 0; - --t42-frame-border-color: hsl(var(--g42-border-secondary)); - --t42-focused-frame-border-color: hsl(var(--g42-border-primary)); + --t42-frame-border-color: var(--base-surface-frame-border); + --t42-focused-frame-border-color: transparent; + + --t42-frame-channel-selector-border-radius: var(--base-radius-default); + --t42-frame-channel-selector-size: var(--spacing-16); + --t42-frame-channel-selector-margin: 0 0 0 4px; - --t42-frame-channel-selector-size: 18px; - --t42-frame-channel-selector-margin: 0px 0px 1px 4px; --t42-frame-caption-height: 30px; --t42-frame-caption-separator-size: 0; - --t42-frame-caption-background: Hsl(var(--g42-bg-01)); + --t42-frame-caption-background: var(--window-header-background); + + --t42-html-buttons-bar-background: var(--window-header-background); - --t42-tab-bar-height: 32px; + --t42-tab-bar-height: 32px; /* for 10.0 - 38px*/ --t42-tab-bar-button-size: 26px; + --t42-tab-bar-button-margin: var(--spacing-2) var(--spacing-2) 0 0; + --t42-tab-bar-button-radius: var(--spacing-4); /* for 10.0 - 50%; */ --t42-tab-bar-separator-size: 0; - --t42-tab-bar-background: Hsl(var(--g42-bg-01)); - --t42-tab-bar-selected-tab-text: hsl(var(--g42-label-primary)); - --t42-tab-bar-selected-tab-hover-text: hsl(var(--g42-label-primary)); - --t42-tab-bar-selected-tab-hover-background: Hsl(var(--g42-bg-02)); - - --t42-tab-bar-tabs-margin: var(--spacing-4) 0 0 0; - - --t42-tab-bar-tab-min-width: 40px; + --t42-tab-bar-padding: 0; /* for 10.0 - 0 0 0 var(--spacing-6); */ + --t42-tab-bar-background: var(--window-header-background); + --t42-tab-bar-selected-tab-text: var(--tabs-color-active); + --t42-tab-bar-selected-tab-hover-text: var(--tabs-color-hover); + --t42-tab-bar-selected-tab-background: var(--window-tabs-background-active); + --t42-tab-bar-selected-tab-hover-background: var(--window-tabs-background-active); + --t42-tab-bar-fade-size: 24px; + + --t42-tab-bar-tab-height: 28px; /* for 10.0 - var(--spacing-24); */ + --t42-tab-bar-tab-min-width: 48px; + --t42-tab-bar-tab-overflowable-min-width: 96px; --t42-tab-bar-tab-width: 150px; - --t42-tab-bar-tab-text: hsl(var(--g42-label-secondary)); - --t42-tab-bar-tab-text-hover: hsl(var(--g42-label-primary)); + --t42-tab-bar-tab-padding: 0 var(--spacing-8); + --t42-tab-bar-tab-margin: var(--spacing-4) var(--spacing-2) 0 0; /* for 10.0 - 0 var(--spacing-2) 0 0; */ + --t42-tab-bar-tab-text: var(--tabs-color-default); + --t42-tab-bar-tab-text-hover: var(--tabs-color-hover); --t42-tab-bar-tab-separator-size: 1px; - --t42-tab-bar-tab-separator-color: hsl(var(--g42-border-primary)); - --t42-tab-bar-tab-selected-separator-color: hsl(var(--g42-border-secondary)); + --t42-tab-bar-tab-separator-height: var(--spacing-8); /* for 10.0 - var(--spacing-12); */ + --t42-tab-bar-tab-separator-color: hsl(var(--io-border-primary)); /* for 10.0 - var(--base-border-separator); */ + --t42-tab-bar-tab-selected-separator-color: var(--window-tabs-background-active); /* bottom underline previous tab version */ --t42-tab-bar-tab-hover-separator-size: 3px; --t42-tab-bar-tab-selected-separator-size: 3px; - --t42-tab-bar-tab-background: Hsl(var(--g42-bg-01)); - --t42-tab-bar-tab-hover-background: Hsl(var(--g42-bg-02)); - --t42-tab-bar-tab-flashing-background: #DE7337b0; + --t42-tab-bar-tab-background: transparent; + --t42-tab-bar-tab-hover-background: transparent; /* non used */ + --t42-tab-bar-tab-flashing-color: var(--io-neutrals-0); + --t42-tab-bar-tab-flashing-background:var(--severity-high); /* color-mix(in srgb, var(--severity-high) 65%, transparent); */ - --t42-tab-bar-tab-channels-border-radius: var(--border-radius-4); - --t42-tab-bar-tab-channels-size: var(--spacing-16); + --t42-tab-bar-tab-channels-border-radius: var(--base-radius-default); + --t42-tab-bar-tab-channels-width: var(--spacing-16); + --t42-tab-bar-tab-channels-height: var(--spacing-16); --t42-tab-bar-tab-channels-margin: 0 var(--spacing-4) 0 0; --t42-tab-bar-tab-channels-content-size: 0; --t42-tab-bar-tab-channels-content-margin: 0; --t42-tab-bar-tab-caption-margin: 0; + --t42-channel-selector-direction-width: var(--spacing-24); + --t42-channel-selector-direction-height: var(--spacing-16); + --t42-channel-selector-direction-gap: var(--spacing-1); + --t42-tab-bar-tab-close-button-size: 6px; --t42-tab-bar-tab-close-button-padding: 3px; - --t42-tab-bar-tab-close-button-margin: 0 0 0 var(--spacing-12); + --t42-tab-bar-tab-close-button-margin: 0 0 0 var(--spacing-8); --t42-tab-bar-tab-close-button-size: 10px; --t42-tab-bar-tab-close-button-padding: 3px; - --t42-tab-bar-tab-close-button-bg-hover: Hsl(var(--g42-bg-03)); + --t42-tab-bar-tab-close-button-background: transparent; + --t42-tab-bar-tab-close-button-bg-hover: var(--icon-background-hover); --t42-approaching-edge-animation-duration: 0.5s; --t42-approaching-edge-size: 4px; - --t42-channels-fill-color: hsl(var(--g42-label-primary)); - ; + --t42-channels-fill-color: var(--tabs-color-active); - --t42-caption-separator-color: hsl(var(--g42-border-secondary)); - --t42-caption-text-hover-color: hsl(var(--g42-label-primary)); - --t42-caption-bar-button-width: 40px; + --t42-caption-separator-color: var(--tabs-border); + --t42-caption-text-hover-color: var(--tabs-color-hover); + --t42-caption-bar-button-width: 48px; --t42-caption-bar-button-background: transparent; - --t42-caption-bar-button-hover-background: hsl(var(--g42-bg-02)); - --t42-caption-bar-button-close-hover-background: hsl(355 86% 49%); - --t42-caption-bar-button-close-hover-text: hsl(var(--g42-white)); + --t42-caption-bar-button-hover-background:#37383a; /* for 10.0 var(--icon-background-hover); */ + --t42-caption-bar-button-close-hover-background: var(--io-red-700); + --t42-caption-bar-button-close-hover-text: var(--io-neutrals-0); --t42-caption-bar-button-correction: 6px; - --t42-approaching-edge-start-color: #4B92FB; - --t42-approaching-edge-end-color: hsl(var(--g42-highlight-Interactive)); + --t42-approaching-edge-start-color: #4b92fb; + --t42-approaching-edge-end-color:var(--io-blue-700); + + --t42-sizing-border-group-color: hsl(var(--io-bg-01)); + --t42-hover-sizing-border-group-color: hsl(var(--io-highlight-Interactive)); + --t42-active-sizing-border-group-color: hsl(var(--io-interactive-primary)); + + + --t42-wg-tab-over-max-height: 100vh; + --t42-wg-tab-over-max-width: 200px; + --t42-wg-tab-over-min-width: 200px; + --t42-wg-tab-over-top-offset: var(--spacing-4); + --t42-wg-tab-over-border-radius: var(--spacing-8); + --t42-wg-tab-over-padding: var(--spacing-4) 0; + --t42-wg-tab-over-item-background-hover: var(--list-item-background-hover); + --t42-wg-tab-over-item-color-hover: var(--text-states-active); + --t42-wg-tab-over-item-padding: 0 var(--spacing-8) 0 var(--spacing-16); + --t42-wg-tab-over-item-gap: var(--spacing-8); + --t42-wg-tab-over-item-height: var(--spacing-32); + --t42-wg-tab-over-item-title-color: var(--text-inactive-tertiary); + --t42-wg-tab-over-item-title-size: var(--spacing-10); + --t42-wg-tab-over-item-title-spacing: 0.36px; + --t42-wg-tab-over-separator-size: var(--spacing-1); + --t42-wg-tab-over-separator-color: var(--base-border-separator); + --t42-wg-tab-over-separator-space: var(--spacing-8) 0; + + --t42-wg-pin-tab-border-radius: var(--spacing-4); + --t42-wg-pin-tab-width: 120px; + --t42-wg-pin-tab-margin: var(--spacing-4); + --t42-wg-pin-tab-height: var(--spacing-24); + + --t42-multi-channel-selector-2-color-1: var(--channels-blue); + --t42-multi-channel-selector-2-color-2: var(--channels-red); + --t42-multi-channel-selector-2-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' viewBox='0 0 16 16'%3E%3Crect width='7.5' height='16'/%3E%3Crect x='8.5' width='7.5' height='16'/%3E%3C/svg%3E"); + --t42-multi-channel-selector-3-color-1: var(--channels-blue); + --t42-multi-channel-selector-3-color-2: var(--channels-red); + --t42-multi-channel-selector-3-color-3: var(--channels-orange); + --t42-multi-channel-selector-3-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' viewBox='0 0 16 16'%3E%3Crect fill='none' width='16' height='16' rx='4' ry='4'/%3E%3Cpath fill='%23000000' d='M16,11.6v-7.6c0-2.2-1.8-4-4-4h-3.5v7.3l7.5,4.3Z'/%3E%3Cpath fill='%23000000' d='M7.5,0h-3.5C1.8,0,0,1.8,0,4v7.9l7.5-4.3V0Z'/%3E%3Cpath fill='%23000000' d='M.1,12.9c.4,1.8,2,3.1,3.9,3.1h8c2,0,3.6-1.4,3.9-3.2l-7.7-4.5L.1,12.9Z'/%3E%3C/svg%3E"); + --t42-multi-channel-selector-4-color-1: var(--channels-blue); + --t42-multi-channel-selector-4-color-2: var(--channels-red); + --t42-multi-channel-selector-4-color-3: var(--channels-orange); + --t42-multi-channel-selector-4-color-4: var(--channels-magenta); + --t42-multi-channel-selector-4-mask:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' version='1.1' viewBox='0 0 16 16'%3E%3Crect width='7.5' height='7.5'/%3E%3Crect x='8.5' width='7.5' height='7.5'/%3E%3Crect x='8.5' y='8.5' width='7.5' height='7.5'/%3E%3Crect y='8.5' width='7.5' height='7.5'/%3E%3C/svg%3E"); + +} + +/* Scroll vars override */ +.os-theme-dark, +.os-theme-light { + --os-size: var(--spacing-4); + --os-padding-perpendicular: 0; + --os-padding-axis: var(--spacing-1); + --os-handle-bg: var(--base-scroll-background-hover); + --os-handle-bg-hover: var(--base-scroll-background-hover); + --os-handle-bg-active: var(--base-scroll-background-hover); } .dark { - --t42-background: #26282A; - --t42-tab-bar-selected-tab-background: hsl(var(--g42-bg-02)); + --t42-background: #28292b; /* for 10.0 - #3d3f43 */ + --t42-wg-tab-over-background: #26282a; /* for 10.0 - var(--base-panel-background); */ --sticky-icon-off: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 16'%3E%3Cpath fill='%23afafaf' d='M15.9,2L14,0.1c-0.2-0.2-0.5-0.1-0.6,0.2L13,2.6C13,2.8,13.2,3,13.4,3l2.3-0.4C16,2.6,16.1,2.3,15.9,2z M0.1,13.9L2,15.9c0.2,0.2,0.5,0.1,0.6-0.2L3,13.4C3,13.2,2.8,13,2.6,13l-2.3,0.4C0,13.4-0.1,13.7,0.1,13.9z M6.5,0h-5 C0.7,0,0,0.7,0,1.5v5C0,7.3,0.7,8,1.5,8h5C7.3,8,8,7.3,8,6.5v-5C8,0.7,7.3,0,6.5,0z M6.5,7h-5C1.2,7,1,6.8,1,6.5V2h6v4.5 C7,6.8,6.8,7,6.5,7z M14.5,8h-5C8.7,8,8,8.7,8,9.5v5C8,15.3,8.7,16,9.5,16h5c0.8,0,1.5-0.7,1.5-1.5v-5C16,8.7,15.3,8,14.5,8z M14.5,15h-5C9.2,15,9,14.8,9,14.5V10h6v4.5C15,14.8,14.8,15,14.5,15z'/%3E%3C/svg%3E%0A"); - --sticky-icon-off-hover:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 17'%3E%3Cpath fill='%234B92FB' d='M11.3,3.8L9.5,5.6c-0.2,0.2-0.2,0.5,0,0.7s0.5,0.2,0.7,0L12,4.5c0.2-0.2,0.2-0.5,0-0.7 C11.8,3.6,11.5,3.6,11.3,3.8z M5.6,9.5l-1.8,1.8c-0.2,0.2-0.2,0.5,0,0.7c0.2,0.2,0.5,0.2,0.7,0l1.8-1.8c0.2-0.2,0.2-0.5,0-0.7 S5.8,9.3,5.6,9.5z'/%3E%3Cpath fill='%23AFAFAF' d='M15.9,2L14,0.1c-0.2-0.2-0.5-0.1-0.6,0.2L13,2.6C13,2.8,13.2,3,13.4,3l2.3-0.4C16,2.6,16.1,2.3,15.9,2z M0.1,14 L2,15.9c0.2,0.2,0.5,0.1,0.6-0.2L3,13.4C3,13.2,2.8,13,2.6,13l-2.3,0.4C0,13.4-0.1,13.7,0.1,14z M6.5,0h-5C0.7,0,0,0.7,0,1.5v5 C0,7.3,0.7,8,1.5,8h5C7.3,8,8,7.3,8,6.5v-5C8,0.7,7.3,0,6.5,0z M6.5,7h-5C1.2,7,1,6.8,1,6.5V2h6v4.5C7,6.8,6.8,7,6.5,7z M14.5,8h-5 C8.7,8,8,8.7,8,9.5v5C8,15.3,8.7,16,9.5,16h5c0.8,0,1.5-0.7,1.5-1.5v-5C16,8.7,15.3,8,14.5,8z M14.5,15h-5C9.2,15,9,14.8,9,14.5V10 h6v4.5C15,14.8,14.8,15,14.5,15z'/%3E%3C/svg%3E%0A");; - --sticky-icon-on:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 16'%3E%3Cpath fill='%23AFB2B5' d='M6.5,4h-5C0.7,4,0,4.7,0,5.5v5C0,11.3,0.7,12,1.5,12h5C7.3,12,8,11.3,8,10.5v-5C8,4.7,7.3,4,6.5,4z M6.5,11h-5 C1.2,11,1,10.8,1,10.5V6h6v4.5C7,10.8,6.8,11,6.5,11z M14.5,4h-5C8.7,4,8,4.7,8,5.5v5C8,11.3,8.7,12,9.5,12h5c0.8,0,1.5-0.7,1.5-1.5 v-5C16,4.7,15.3,4,14.5,4z M14.5,11h-5C9.2,11,9,10.8,9,10.5V6h6v4.5C15,10.8,14.8,11,14.5,11z'/%3E%3Cpath fill='%23808389' d='M6.6,0l2.7,0c0.3,0,0.5,0.3,0.3,0.5L8.5,2.1v1.4C8.5,3.8,8.3,4,8,4C7.7,4,7.5,3.8,7.5,3.5V2.1L6.3,0.5 C6.2,0.3,6.3,0,6.6,0z M7.5,13.9v-1.4C7.5,12.2,7.7,12,8,12c0.3,0,0.5,0.2,0.5,0.5v1.4l1.2,1.6c0.2,0.2,0,0.5-0.3,0.5H6.6 c-0.3,0-0.5-0.3-0.3-0.5L7.5,13.9z M8,11c-0.3,0-0.5-0.2-0.5-0.5v-4C7.5,6.2,7.7,6,8,6c0.3,0,0.5,0.2,0.5,0.5v4 C8.5,10.8,8.3,11,8,11z'/%3E%3C/svg%3E"); - --sticky-icon-on-hover:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 16'%3E%3Cpath fill='%23AFB2B5' d='M6.5,4h-5C0.7,4,0,4.7,0,5.5v5C0,11.3,0.7,12,1.5,12h5C7.3,12,8,11.3,8,10.5v-5C8,4.7,7.3,4,6.5,4z M6.5,11h-5 C1.2,11,1,10.8,1,10.5V6h6v4.5C7,10.8,6.8,11,6.5,11z M14.5,4h-5C8.7,4,8,4.7,8,5.5v5C8,11.3,8.7,12,9.5,12h5c0.8,0,1.5-0.7,1.5-1.5 v-5C16,4.7,15.3,4,14.5,4z M14.5,11h-5C9.2,11,9,10.8,9,10.5V6h6v4.5C15,10.8,14.8,11,14.5,11z'/%3E%3Cpath fill='%234B92FB' d='M6.6,0l2.7,0c0.3,0,0.5,0.3,0.3,0.5L8.3,2.4c-0.1,0.2-0.4,0.2-0.6,0L6.3,0.5C6.2,0.3,6.3,0,6.6,0z M6.6,16h2.7 c0.3,0,0.5-0.3,0.3-0.5l-1.4-1.9c-0.1-0.2-0.4-0.2-0.6,0l-1.4,1.9C6.2,15.7,6.3,16,6.6,16z'/%3E%3Cpath fill='%234B92FB' d='M8.5,13.5v1C8.5,14.8,8.3,15,8,15c-0.3,0-0.5-0.2-0.5-0.5v-1v-1v-11C7.5,1.2,7.7,1,8,1c0.3,0,0.5,0.2,0.5,0.5 v11V13.5C8.5,13.5,8.5,13.5,8.5,13.5z'/%3E%3C/svg%3E"); + --sticky-icon-off-hover: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 17'%3E%3Cpath fill='%234B92FB' d='M11.3,3.8L9.5,5.6c-0.2,0.2-0.2,0.5,0,0.7s0.5,0.2,0.7,0L12,4.5c0.2-0.2,0.2-0.5,0-0.7 C11.8,3.6,11.5,3.6,11.3,3.8z M5.6,9.5l-1.8,1.8c-0.2,0.2-0.2,0.5,0,0.7c0.2,0.2,0.5,0.2,0.7,0l1.8-1.8c0.2-0.2,0.2-0.5,0-0.7 S5.8,9.3,5.6,9.5z'/%3E%3Cpath fill='%23AFAFAF' d='M15.9,2L14,0.1c-0.2-0.2-0.5-0.1-0.6,0.2L13,2.6C13,2.8,13.2,3,13.4,3l2.3-0.4C16,2.6,16.1,2.3,15.9,2z M0.1,14 L2,15.9c0.2,0.2,0.5,0.1,0.6-0.2L3,13.4C3,13.2,2.8,13,2.6,13l-2.3,0.4C0,13.4-0.1,13.7,0.1,14z M6.5,0h-5C0.7,0,0,0.7,0,1.5v5 C0,7.3,0.7,8,1.5,8h5C7.3,8,8,7.3,8,6.5v-5C8,0.7,7.3,0,6.5,0z M6.5,7h-5C1.2,7,1,6.8,1,6.5V2h6v4.5C7,6.8,6.8,7,6.5,7z M14.5,8h-5 C8.7,8,8,8.7,8,9.5v5C8,15.3,8.7,16,9.5,16h5c0.8,0,1.5-0.7,1.5-1.5v-5C16,8.7,15.3,8,14.5,8z M14.5,15h-5C9.2,15,9,14.8,9,14.5V10 h6v4.5C15,14.8,14.8,15,14.5,15z'/%3E%3C/svg%3E%0A"); + --sticky-icon-on: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 16'%3E%3Cpath fill='%23AFB2B5' d='M6.5,4h-5C0.7,4,0,4.7,0,5.5v5C0,11.3,0.7,12,1.5,12h5C7.3,12,8,11.3,8,10.5v-5C8,4.7,7.3,4,6.5,4z M6.5,11h-5 C1.2,11,1,10.8,1,10.5V6h6v4.5C7,10.8,6.8,11,6.5,11z M14.5,4h-5C8.7,4,8,4.7,8,5.5v5C8,11.3,8.7,12,9.5,12h5c0.8,0,1.5-0.7,1.5-1.5 v-5C16,4.7,15.3,4,14.5,4z M14.5,11h-5C9.2,11,9,10.8,9,10.5V6h6v4.5C15,10.8,14.8,11,14.5,11z'/%3E%3Cpath fill='%23808389' d='M6.6,0l2.7,0c0.3,0,0.5,0.3,0.3,0.5L8.5,2.1v1.4C8.5,3.8,8.3,4,8,4C7.7,4,7.5,3.8,7.5,3.5V2.1L6.3,0.5 C6.2,0.3,6.3,0,6.6,0z M7.5,13.9v-1.4C7.5,12.2,7.7,12,8,12c0.3,0,0.5,0.2,0.5,0.5v1.4l1.2,1.6c0.2,0.2,0,0.5-0.3,0.5H6.6 c-0.3,0-0.5-0.3-0.3-0.5L7.5,13.9z M8,11c-0.3,0-0.5-0.2-0.5-0.5v-4C7.5,6.2,7.7,6,8,6c0.3,0,0.5,0.2,0.5,0.5v4 C8.5,10.8,8.3,11,8,11z'/%3E%3C/svg%3E"); + --sticky-icon-on-hover: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 16'%3E%3Cpath fill='%23AFB2B5' d='M6.5,4h-5C0.7,4,0,4.7,0,5.5v5C0,11.3,0.7,12,1.5,12h5C7.3,12,8,11.3,8,10.5v-5C8,4.7,7.3,4,6.5,4z M6.5,11h-5 C1.2,11,1,10.8,1,10.5V6h6v4.5C7,10.8,6.8,11,6.5,11z M14.5,4h-5C8.7,4,8,4.7,8,5.5v5C8,11.3,8.7,12,9.5,12h5c0.8,0,1.5-0.7,1.5-1.5 v-5C16,4.7,15.3,4,14.5,4z M14.5,11h-5C9.2,11,9,10.8,9,10.5V6h6v4.5C15,10.8,14.8,11,14.5,11z'/%3E%3Cpath fill='%234B92FB' d='M6.6,0l2.7,0c0.3,0,0.5,0.3,0.3,0.5L8.3,2.4c-0.1,0.2-0.4,0.2-0.6,0L6.3,0.5C6.2,0.3,6.3,0,6.6,0z M6.6,16h2.7 c0.3,0,0.5-0.3,0.3-0.5l-1.4-1.9c-0.1-0.2-0.4-0.2-0.6,0l-1.4,1.9C6.2,15.7,6.3,16,6.6,16z'/%3E%3Cpath fill='%234B92FB' d='M8.5,13.5v1C8.5,14.8,8.3,15,8,15c-0.3,0-0.5-0.2-0.5-0.5v-1v-1v-11C7.5,1.2,7.7,1,8,1c0.3,0,0.5,0.2,0.5,0.5 v11V13.5C8.5,13.5,8.5,13.5,8.5,13.5z'/%3E%3C/svg%3E"); } .light { - --t42-background: #E8E9ED; - --t42-tab-bar-selected-tab-background: hsl(var(--g42-white)); + --t42-background: #e8e9ed; /* for 10.0 - #ffffff */ + /* for 10.0 - --t42-tab-bar-separator-size: 1px; */ + --t42-caption-bar-button-hover-background: #f0f1f4; /* remove for 10.0 */ + --t42-wg-tab-over-background: #e8e9ed; /* for 10.0 - var(--base-panel-background); */ + --t42-tab-bar-tab-close-button-bg-hover: var(--io-neutrals-150); --sticky-icon-off: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 16'%3E%3Cpath fill='%23626F81' d='M15.9,2L14,0.1c-0.2-0.2-0.5-0.1-0.6,0.2L13,2.6C13,2.8,13.2,3,13.4,3l2.3-0.4C16,2.6,16.1,2.3,15.9,2z M0.1,13.9L2,15.9c0.2,0.2,0.5,0.1,0.6-0.2L3,13.4C3,13.2,2.8,13,2.6,13l-2.3,0.4C0,13.4-0.1,13.7,0.1,13.9z M6.5,0h-5 C0.7,0,0,0.7,0,1.5v5C0,7.3,0.7,8,1.5,8h5C7.3,8,8,7.3,8,6.5v-5C8,0.7,7.3,0,6.5,0z M6.5,7h-5C1.2,7,1,6.8,1,6.5V2h6v4.5 C7,6.8,6.8,7,6.5,7z M14.5,8h-5C8.7,8,8,8.7,8,9.5v5C8,15.3,8.7,16,9.5,16h5c0.8,0,1.5-0.7,1.5-1.5v-5C16,8.7,15.3,8,14.5,8z M14.5,15h-5C9.2,15,9,14.8,9,14.5V10h6v4.5C15,14.8,14.8,15,14.5,15z'/%3E%3C/svg%3E%0A"); - --sticky-icon-off-hover:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 17'%3E%3Cpath fill='%231B6ADE' d='M11.3,3.8L9.5,5.6c-0.2,0.2-0.2,0.5,0,0.7s0.5,0.2,0.7,0L12,4.5c0.2-0.2,0.2-0.5,0-0.7 C11.8,3.6,11.5,3.6,11.3,3.8z M5.6,9.5l-1.8,1.8c-0.2,0.2-0.2,0.5,0,0.7c0.2,0.2,0.5,0.2,0.7,0l1.8-1.8c0.2-0.2,0.2-0.5,0-0.7 S5.8,9.3,5.6,9.5z'/%3E%3Cpath fill='%23626F81' d='M15.9,2L14,0.1c-0.2-0.2-0.5-0.1-0.6,0.2L13,2.6C13,2.8,13.2,3,13.4,3l2.3-0.4C16,2.6,16.1,2.3,15.9,2z M0.1,14 L2,15.9c0.2,0.2,0.5,0.1,0.6-0.2L3,13.4C3,13.2,2.8,13,2.6,13l-2.3,0.4C0,13.4-0.1,13.7,0.1,14z M6.5,0h-5C0.7,0,0,0.7,0,1.5v5 C0,7.3,0.7,8,1.5,8h5C7.3,8,8,7.3,8,6.5v-5C8,0.7,7.3,0,6.5,0z M6.5,7h-5C1.2,7,1,6.8,1,6.5V2h6v4.5C7,6.8,6.8,7,6.5,7z M14.5,8h-5 C8.7,8,8,8.7,8,9.5v5C8,15.3,8.7,16,9.5,16h5c0.8,0,1.5-0.7,1.5-1.5v-5C16,8.7,15.3,8,14.5,8z M14.5,15h-5C9.2,15,9,14.8,9,14.5V10 h6v4.5C15,14.8,14.8,15,14.5,15z'/%3E%3C/svg%3E%0A");; - --sticky-icon-on:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 16'%3E%3Cpath fill='%23626F81' d='M6.5,4h-5C0.7,4,0,4.7,0,5.5v5C0,11.3,0.7,12,1.5,12h5C7.3,12,8,11.3,8,10.5v-5C8,4.7,7.3,4,6.5,4z M6.5,11h-5 C1.2,11,1,10.8,1,10.5V6h6v4.5C7,10.8,6.8,11,6.5,11z M14.5,4h-5C8.7,4,8,4.7,8,5.5v5C8,11.3,8.7,12,9.5,12h5c0.8,0,1.5-0.7,1.5-1.5 v-5C16,4.7,15.3,4,14.5,4z M14.5,11h-5C9.2,11,9,10.8,9,10.5V6h6v4.5C15,10.8,14.8,11,14.5,11z'/%3E%3Cpath fill='%23A4B1C3' d='M6.6,0l2.7,0c0.3,0,0.5,0.3,0.3,0.5L8.5,2.1v1.4C8.5,3.8,8.3,4,8,4C7.7,4,7.5,3.8,7.5,3.5V2.1L6.3,0.5 C6.2,0.3,6.3,0,6.6,0z M7.5,13.9v-1.4C7.5,12.2,7.7,12,8,12c0.3,0,0.5,0.2,0.5,0.5v1.4l1.2,1.6c0.2,0.2,0,0.5-0.3,0.5H6.6 c-0.3,0-0.5-0.3-0.3-0.5L7.5,13.9z M8,11c-0.3,0-0.5-0.2-0.5-0.5v-4C7.5,6.2,7.7,6,8,6c0.3,0,0.5,0.2,0.5,0.5v4 C8.5,10.8,8.3,11,8,11z'/%3E%3C/svg%3E"); - --sticky-icon-on-hover:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 16'%3E%3Cpath fill='%23626F81' d='M6.5,4h-5C0.7,4,0,4.7,0,5.5v5C0,11.3,0.7,12,1.5,12h5C7.3,12,8,11.3,8,10.5v-5C8,4.7,7.3,4,6.5,4z M6.5,11h-5 C1.2,11,1,10.8,1,10.5V6h6v4.5C7,10.8,6.8,11,6.5,11z M14.5,4h-5C8.7,4,8,4.7,8,5.5v5C8,11.3,8.7,12,9.5,12h5c0.8,0,1.5-0.7,1.5-1.5 v-5C16,4.7,15.3,4,14.5,4z M14.5,11h-5C9.2,11,9,10.8,9,10.5V6h6v4.5C15,10.8,14.8,11,14.5,11z'/%3E%3Cpath fill='%234B92FB' d='M6.6,0l2.7,0c0.3,0,0.5,0.3,0.3,0.5L8.3,2.4c-0.1,0.2-0.4,0.2-0.6,0L6.3,0.5C6.2,0.3,6.3,0,6.6,0z M6.6,16h2.7 c0.3,0,0.5-0.3,0.3-0.5l-1.4-1.9c-0.1-0.2-0.4-0.2-0.6,0l-1.4,1.9C6.2,15.7,6.3,16,6.6,16z'/%3E%3Cpath fill='%234B92FB' d='M8.5,13.5v1C8.5,14.8,8.3,15,8,15c-0.3,0-0.5-0.2-0.5-0.5v-1v-1v-11C7.5,1.2,7.7,1,8,1c0.3,0,0.5,0.2,0.5,0.5 v11V13.5C8.5,13.5,8.5,13.5,8.5,13.5z'/%3E%3C/svg%3E"); - -} \ No newline at end of file + --sticky-icon-off-hover: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 17'%3E%3Cpath fill='%231B6ADE' d='M11.3,3.8L9.5,5.6c-0.2,0.2-0.2,0.5,0,0.7s0.5,0.2,0.7,0L12,4.5c0.2-0.2,0.2-0.5,0-0.7 C11.8,3.6,11.5,3.6,11.3,3.8z M5.6,9.5l-1.8,1.8c-0.2,0.2-0.2,0.5,0,0.7c0.2,0.2,0.5,0.2,0.7,0l1.8-1.8c0.2-0.2,0.2-0.5,0-0.7 S5.8,9.3,5.6,9.5z'/%3E%3Cpath fill='%23626F81' d='M15.9,2L14,0.1c-0.2-0.2-0.5-0.1-0.6,0.2L13,2.6C13,2.8,13.2,3,13.4,3l2.3-0.4C16,2.6,16.1,2.3,15.9,2z M0.1,14 L2,15.9c0.2,0.2,0.5,0.1,0.6-0.2L3,13.4C3,13.2,2.8,13,2.6,13l-2.3,0.4C0,13.4-0.1,13.7,0.1,14z M6.5,0h-5C0.7,0,0,0.7,0,1.5v5 C0,7.3,0.7,8,1.5,8h5C7.3,8,8,7.3,8,6.5v-5C8,0.7,7.3,0,6.5,0z M6.5,7h-5C1.2,7,1,6.8,1,6.5V2h6v4.5C7,6.8,6.8,7,6.5,7z M14.5,8h-5 C8.7,8,8,8.7,8,9.5v5C8,15.3,8.7,16,9.5,16h5c0.8,0,1.5-0.7,1.5-1.5v-5C16,8.7,15.3,8,14.5,8z M14.5,15h-5C9.2,15,9,14.8,9,14.5V10 h6v4.5C15,14.8,14.8,15,14.5,15z'/%3E%3C/svg%3E%0A"); + --sticky-icon-on: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 16'%3E%3Cpath fill='%23626F81' d='M6.5,4h-5C0.7,4,0,4.7,0,5.5v5C0,11.3,0.7,12,1.5,12h5C7.3,12,8,11.3,8,10.5v-5C8,4.7,7.3,4,6.5,4z M6.5,11h-5 C1.2,11,1,10.8,1,10.5V6h6v4.5C7,10.8,6.8,11,6.5,11z M14.5,4h-5C8.7,4,8,4.7,8,5.5v5C8,11.3,8.7,12,9.5,12h5c0.8,0,1.5-0.7,1.5-1.5 v-5C16,4.7,15.3,4,14.5,4z M14.5,11h-5C9.2,11,9,10.8,9,10.5V6h6v4.5C15,10.8,14.8,11,14.5,11z'/%3E%3Cpath fill='%23A4B1C3' d='M6.6,0l2.7,0c0.3,0,0.5,0.3,0.3,0.5L8.5,2.1v1.4C8.5,3.8,8.3,4,8,4C7.7,4,7.5,3.8,7.5,3.5V2.1L6.3,0.5 C6.2,0.3,6.3,0,6.6,0z M7.5,13.9v-1.4C7.5,12.2,7.7,12,8,12c0.3,0,0.5,0.2,0.5,0.5v1.4l1.2,1.6c0.2,0.2,0,0.5-0.3,0.5H6.6 c-0.3,0-0.5-0.3-0.3-0.5L7.5,13.9z M8,11c-0.3,0-0.5-0.2-0.5-0.5v-4C7.5,6.2,7.7,6,8,6c0.3,0,0.5,0.2,0.5,0.5v4 C8.5,10.8,8.3,11,8,11z'/%3E%3C/svg%3E"); + --sticky-icon-on-hover: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' viewBox='0 0 16 16'%3E%3Cpath fill='%23626F81' d='M6.5,4h-5C0.7,4,0,4.7,0,5.5v5C0,11.3,0.7,12,1.5,12h5C7.3,12,8,11.3,8,10.5v-5C8,4.7,7.3,4,6.5,4z M6.5,11h-5 C1.2,11,1,10.8,1,10.5V6h6v4.5C7,10.8,6.8,11,6.5,11z M14.5,4h-5C8.7,4,8,4.7,8,5.5v5C8,11.3,8.7,12,9.5,12h5c0.8,0,1.5-0.7,1.5-1.5 v-5C16,4.7,15.3,4,14.5,4z M14.5,11h-5C9.2,11,9,10.8,9,10.5V6h6v4.5C15,10.8,14.8,11,14.5,11z'/%3E%3Cpath fill='%234B92FB' d='M6.6,0l2.7,0c0.3,0,0.5,0.3,0.3,0.5L8.3,2.4c-0.1,0.2-0.4,0.2-0.6,0L6.3,0.5C6.2,0.3,6.3,0,6.6,0z M6.6,16h2.7 c0.3,0,0.5-0.3,0.3-0.5l-1.4-1.9c-0.1-0.2-0.4-0.2-0.6,0l-1.4,1.9C6.2,15.7,6.3,16,6.6,16z'/%3E%3Cpath fill='%234B92FB' d='M8.5,13.5v1C8.5,14.8,8.3,15,8,15c-0.3,0-0.5-0.2-0.5-0.5v-1v-1v-11C7.5,1.2,7.7,1,8,1c0.3,0,0.5,0.2,0.5,0.5 v11V13.5C8.5,13.5,8.5,13.5,8.5,13.5z'/%3E%3C/svg%3E"); +} diff --git a/changelog.md b/changelog.md index 6512385..f2e18f0 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,37 @@ +2.6.0 +chore: official 9.7 support +feat: overflow tabs dynamic width +2.5.0 +chore: official 9.6 support +feat: multi channels support +2.4.1 +feat: directional channels improvement +2.4.0 +chore: official 9.5 support +2.3.1 +feat: pinned tabs support +2.3.0 +chore: official 9.4 support +2.2.2 +fix: fixed the internal CSS import for the overflow tabs +2.2.1 +feat: added support for overflowing tabs +2.2.0 +chore: official 9.3 support +chore: updated the css file name in the readme +feat: added support for defining the drag area with CSS +2.1.0 +chore: official 9.2 support +2.0.6 +fix: flat channels selector fix +2.0.4 +fix: typo in loading animation class name +2.0.3 +chore: release process issue +2.0.2 +fix: started using the default loading animation component +2.0.1 +feat: customizable html buttons 2.0.0 feat: rebranding 1.4.0 diff --git a/package-lock.json b/package-lock.json index addbbde..a7eb9c8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,17 +1,18 @@ { "name": "@interopio/groups-ui-react", - "version": "1.4.0", + "version": "2.5.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@interopio/groups-ui-react", - "version": "1.4.0", + "version": "2.5.0", "license": "MIT", "dependencies": { - "@interopio/theme": "^1.0.4", + "@interopio/theme": "^2.1.32", "callback-registry": "^2.7.2", "color2k": "^2.0.0", + "overlayscrollbars": "^2.8.3", "use-sync-external-store": "^1.2.0" }, "devDependencies": { @@ -2548,9 +2549,9 @@ } }, "node_modules/@interopio/theme": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@interopio/theme/-/theme-1.0.4.tgz", - "integrity": "sha512-8tqY9P6IJALnIHQ5PI8EYs/8Y3zTpNZ+uQbjY4lRbEjmhyUUf8P1D9N1C7zN/KefEvBsKtSv9vqpqcZjALyQhg==" + "version": "2.1.32", + "resolved": "https://registry.npmjs.org/@interopio/theme/-/theme-2.1.32.tgz", + "integrity": "sha512-r2jh6B2d8vGEcVKzU4eJMnQxnue8/4eb9MZYo98+3R1r7/iY1Z1Qk1lSm19KzG+BfM0o9DVUEAjwS+2YUTea9w==" }, "node_modules/@interopio/workspaces-api": { "version": "3.0.2", @@ -14890,6 +14891,11 @@ "node": ">=0.10.0" } }, + "node_modules/overlayscrollbars": { + "version": "2.8.3", + "resolved": "https://codeartifact-interopio-npm.interop.io/overlayscrollbars/-/overlayscrollbars-2.8.3.tgz", + "integrity": "sha512-7JHA1oWm3Gru3RF5wwaeBdgk4keGtc56HMWEQRQi/RdLdY3pZTUDlSfUk1jyv1yQN12otr828n52rT6VNzYO4w==" + }, "node_modules/p-limit": { "version": "1.3.0", "dev": true, @@ -22091,9 +22097,9 @@ } }, "@interopio/theme": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@interopio/theme/-/theme-1.0.4.tgz", - "integrity": "sha512-8tqY9P6IJALnIHQ5PI8EYs/8Y3zTpNZ+uQbjY4lRbEjmhyUUf8P1D9N1C7zN/KefEvBsKtSv9vqpqcZjALyQhg==" + "version": "2.1.32", + "resolved": "https://registry.npmjs.org/@interopio/theme/-/theme-2.1.32.tgz", + "integrity": "sha512-r2jh6B2d8vGEcVKzU4eJMnQxnue8/4eb9MZYo98+3R1r7/iY1Z1Qk1lSm19KzG+BfM0o9DVUEAjwS+2YUTea9w==" }, "@interopio/workspaces-api": { "version": "3.0.2", @@ -30037,6 +30043,11 @@ "version": "1.0.2", "dev": true }, + "overlayscrollbars": { + "version": "2.8.3", + "resolved": "https://codeartifact-interopio-npm.interop.io/overlayscrollbars/-/overlayscrollbars-2.8.3.tgz", + "integrity": "sha512-7JHA1oWm3Gru3RF5wwaeBdgk4keGtc56HMWEQRQi/RdLdY3pZTUDlSfUk1jyv1yQN12otr828n52rT6VNzYO4w==" + }, "p-limit": { "version": "1.3.0", "dev": true, diff --git a/package.json b/package.json index 12a1b53..7be207c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@interopio/groups-ui-react", - "version": "2.0.0", + "version": "2.6.0", "description": "React library for building a Web Group App for io.Connect Desktop.", "author": { "name": "interop.io", @@ -27,15 +27,17 @@ "bundle:css": "node ./scripts/bundlecss.js", "prepublishOnly": "npm run build", "preversion": "npm run build", - "version": "npm run build" + "version": "npm run build", + "clean": "rimraf ./node_modules/react && rimraf ./node_modules/react-dom && rimraf ./node_modules/@interopio/react-hooks" }, "publishConfig": { "access": "public" }, "dependencies": { - "@interopio/theme": "^1.0.4", + "@interopio/theme": "^2.1.32", "callback-registry": "^2.7.2", "color2k": "^2.0.0", + "overlayscrollbars": "^2.8.3", "use-sync-external-store": "^1.2.0" }, "peerDependencies": { diff --git a/src/GroupElementCreationWrapper.tsx b/src/GroupElementCreationWrapper.tsx index 0b45aec..d32b262 100644 --- a/src/GroupElementCreationWrapper.tsx +++ b/src/GroupElementCreationWrapper.tsx @@ -7,10 +7,12 @@ import { Bounds, ElementCreationWrapperState, TargetType } from "./types/interna import { CustomButtonProps } from "./types/defaultComponents"; import webGroupsManager from "./webGroupsManager"; import webGroupsStore from "./webGroupsStore"; +import FrameLoadingAnimation from "./defaultComponents/loadingAnimation/FrameLoadingAnimation"; -const GroupElementCreationWrapper: React.FC = ({ components }) => { +const GroupElementCreationWrapper: React.FC = ({ components, styles }) => { const state = useSyncExternalStore(webGroupsStore.subscribe, webGroupsStore.getSnapshot); + const LoadingAnimation = components?.frame?.LoadingAnimation ?? FrameLoadingAnimation; const renderGroupCaptionBar = () => { const GroupCaptionBarCustomElement = components?.group?.CaptionBar; @@ -22,28 +24,28 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { const minimize = { onClick: () => { - webGroupsManager.minimizeGroup(options.targetId); + webGroupsManager.onMinimizeButtonClick(TargetType.Group, options.targetId); }, ...options.minimize } const restore = { onClick: () => { - webGroupsManager.restoreGroup(options.targetId); + webGroupsManager.onRestoreButtonClick(TargetType.Group, options.targetId); }, ...options.restore } const maximize = { onClick: () => { - webGroupsManager.maximizeGroup(options.targetId); + webGroupsManager.onMaximizeButtonClick(TargetType.Group, options.targetId); }, ...options.maximize } const close = { onClick: () => { - webGroupsManager.closeGroup(options.targetId); + webGroupsManager.onCloseButtonClick(TargetType.Group, options.targetId); }, ...options.close } @@ -102,70 +104,77 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { const feedback = { onClick: () => { - webGroupsManager.feedbackFrame(options.targetId); + webGroupsManager.onFeedbackButtonClick(TargetType.Frame, options.targetId); }, ...options.feedback }; + const clone = { + onClick: () => { + webGroupsManager.onCloneButtonClick(TargetType.Frame, options.targetId); + }, + ...options.clone + }; + const sticky = { onClick: () => { - webGroupsManager.stickyFrame(options.targetId); + webGroupsManager.onStickyButtonClick(TargetType.Frame, options.targetId); }, ...options.sticky }; const extract = { onClick: () => { - webGroupsManager.extractFrame(options.targetId); + webGroupsManager.onExtractButtonClick(TargetType.Frame, options.targetId); }, ...options.extract }; const lock = { onClick: () => { - webGroupsManager.lockFrame(options.targetId); + webGroupsManager.onLockButtonClick(TargetType.Frame, options.targetId); }, ...options.lock }; const unlock = { onClick: () => { - webGroupsManager.unlockFrame(options.targetId); + webGroupsManager.onUnlockButtonClick(TargetType.Frame, options.targetId); }, ...options.unlock }; const minimize = { onClick: () => { - webGroupsManager.minimizeFrame(options.targetId); + webGroupsManager.onMinimizeButtonClick(TargetType.Frame, options.targetId); }, ...options.minimize } const restore = { onClick: () => { - webGroupsManager.restoreFrame(options.targetId); + webGroupsManager.onRestoreButtonClick(TargetType.Frame, options.targetId); }, ...options.restore } const maximize = { onClick: () => { - webGroupsManager.maximizeFrame(options.targetId); + webGroupsManager.onMaximizeButtonClick(TargetType.Frame, options.targetId); }, ...options.maximize } const close = { onClick: () => { - webGroupsManager.closeFrame(options.targetId); + webGroupsManager.onCloseButtonClick(TargetType.Frame, options.targetId); }, ...options.close } let customButtonsProps = new Array(); if (options.customButtons) { - customButtonsProps = options.customButtons.map((cButton) => { + customButtonsProps = options.customButtons.map((cButton) => { return { onClick: () => { webGroupsManager.clickCustomButton(options.targetId, cButton.buttonId); @@ -173,7 +182,9 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { visible: true, imageData: cButton.imageData, tooltip: cButton.tooltip, - buttonId: cButton.buttonId}}); + buttonId: cButton.buttonId + } + }); } const showSelector = (bounds: Bounds) => { @@ -184,7 +195,11 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { showSelector, visible: options.channelSelectorVisible, selectedChannel: options.selectedChannel, - selectedChannelColor: options.selectedChannelColor + selectedChannelColor: options.selectedChannelColor, + channelRestrictions: options.channelRestrictions, + channelLabel: options.channelLabel, + channelsMode: options.channelsMode ?? "single", + selectedChannels : options.selectedChannels } const captionEditor = { @@ -208,6 +223,7 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { return = ({ components }) => { } const renderFrameLoadingAnimations = () => { - const LoadingAnimationCustomElement = components?.frame?.LoadingAnimation; + const LoadingAnimationCustomElement = LoadingAnimation; return Object.values(state.frameLoadingAnimations).map((wla) => { if (!LoadingAnimationCustomElement || !wla.parentElement) { return; @@ -332,7 +348,6 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { const { parentElement, ...options } = te; - const onCloseClick = () => { webGroupsManager.closeTab(options.targetId); } @@ -345,7 +360,11 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { showSelector, visible: options.channelSelectorVisible, selectedChannel: options.selectedChannel, - selectedChannelColor: options.selectedChannelColor ?? options.selectedChannel // TODO remove the null check when the variable has been added + selectedChannelColor: options.selectedChannelColor ?? options.selectedChannel, // TODO remove the null check when the variable has been added + channelRestrictions: options.channelRestrictions, + channelLabel: options.channelLabel, + channelsMode: options.channelsMode ?? "single", + selectedChannels: options.selectedChannels }; const captionEditor = { @@ -366,6 +385,14 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { const notifyCaptionBoundsChanged = (bounds: Bounds) => webGroupsManager.onCaptionTextBoundsChanged(TargetType.Tab, options.targetId, bounds); + const addContainerClass = (className: string) => { + webGroupsManager.addTabContainerClass(options.targetId, className); + } + + const removeContainerClass = (className: string) => { + webGroupsManager.removeTabContainerClass(options.targetId, className); + } + return = ({ components }) => { windowId={options.targetId} captionEditor={captionEditor} notifyCaptionBoundsChanged={notifyCaptionBoundsChanged} + addContainerClass={addContainerClass} + removeContainerClass={removeContainerClass} /> }); @@ -400,72 +429,86 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { } const { parentElement, ...options } = te; + const overflow = { + onClick: () => { + webGroupsManager.onOverflowButtonClick(TargetType.TabBar, options.targetId); + }, + ...options.overflow + }; + const feedback = { onClick: () => { - webGroupsManager.feedbackTabBar(options.targetId); + webGroupsManager.onFeedbackButtonClick(TargetType.TabBar, options.targetId); }, ...options.feedback }; + const clone = { + onClick: () => { + webGroupsManager.onCloneButtonClick(TargetType.TabBar, options.targetId); + }, + ...options.clone + }; + const sticky = { onClick: () => { - webGroupsManager.stickyTabBar(options.targetId); + webGroupsManager.onStickyButtonClick(TargetType.TabBar, options.targetId); }, ...options.sticky }; const extract = { onClick: () => { - webGroupsManager.extractTabBar(options.targetId); + webGroupsManager.onExtractButtonClick(TargetType.TabBar, options.targetId); }, ...options.extract }; const lock = { onClick: () => { - webGroupsManager.lockTabBar(options.targetId); + webGroupsManager.onLockButtonClick(TargetType.TabBar, options.targetId); }, ...options.lock } const unlock = { onClick: () => { - webGroupsManager.unlockTabBar(options.targetId); + webGroupsManager.onUnlockButtonClick(TargetType.TabBar, options.targetId); }, ...options.unlock } const minimize = { onClick: () => { - webGroupsManager.minimizeTabBar(options.targetId); + webGroupsManager.onMinimizeButtonClick(TargetType.TabBar, options.targetId); }, ...options.minimize } const restore = { onClick: () => { - webGroupsManager.restoreTabBar(options.targetId); + webGroupsManager.onRestoreButtonClick(TargetType.TabBar, options.targetId); }, ...options.restore } const maximize = { onClick: () => { - webGroupsManager.maximizeTabBar(options.targetId); + webGroupsManager.onMaximizeButtonClick(TargetType.TabBar, options.targetId); }, ...options.maximize } const close = { onClick: () => { - webGroupsManager.closeTabBar(options.targetId); + webGroupsManager.onCloseButtonClick(TargetType.TabBar, options.targetId); }, ...options.close } let customButtonsProps = new Array(); if (options.customButtons) { - customButtonsProps = options.customButtons.map((cButton) => { + customButtonsProps = options.customButtons.map((cButton) => { return { onClick: () => { webGroupsManager.clickCustomButton(options.targetId, cButton.buttonId); @@ -473,11 +516,15 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { visible: true, imageData: cButton.imageData, tooltip: cButton.tooltip, - buttonId: cButton.buttonId}}); + buttonId: cButton.buttonId + } + }); } - + return = ({ components }) => { }); } + const renderTabOverflowPopups = () => { + const TabOverflowCustomElement = components?.tabs?.OverflowPopup; + + return Object.values(state.tabOverflowPopups).map((top) => { + if (!TabOverflowCustomElement || !top.parentElement) { + return; + } + const { parentElement, ...options } = top; + + const select = (windowId: string) => { + webGroupsManager.selectTab(windowId); + }; + + const close = (windowId: string) => { + webGroupsManager.closeTab(windowId); + } + + return + }); + } + const renderBelowTabs = () => { const BelowTabsCustomElement = components?.tabs?.Below; @@ -505,6 +577,125 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { }); } + const renderHtmlButtons = () => { + const HtmlButtonsCustomElement = components?.html?.Buttons; + + return Object.values(state.htmlButtons).map((te) => { + if (!HtmlButtonsCustomElement || !te.parentElement) { + return; + } + const { parentElement, ...options } = te; + + const overflow = { + onClick: () => { + webGroupsManager.onOverflowButtonClick(TargetType.HtmlButtons, options.targetId); + }, + ...options.overflow + }; + + const feedback = { + onClick: () => { + webGroupsManager.onFeedbackButtonClick(TargetType.HtmlButtons, options.targetId); + }, + ...options.feedback + }; + + const clone = { + onClick: () => { + webGroupsManager.onCloneButtonClick(TargetType.HtmlButtons, options.targetId); + }, + ...options.clone + }; + + const sticky = { + onClick: () => { + webGroupsManager.onStickyButtonClick(TargetType.HtmlButtons, options.targetId); + }, + ...options.sticky + }; + + const extract = { + onClick: () => { + webGroupsManager.onExtractButtonClick(TargetType.HtmlButtons, options.targetId); + }, + ...options.extract + }; + + const lock = { + onClick: () => { + webGroupsManager.onLockButtonClick(TargetType.HtmlButtons, options.targetId); + }, + ...options.lock + } + + const unlock = { + onClick: () => { + webGroupsManager.onUnlockButtonClick(TargetType.HtmlButtons, options.targetId); + }, + ...options.unlock + } + + const minimize = { + onClick: () => { + webGroupsManager.onMinimizeButtonClick(TargetType.HtmlButtons, options.targetId); + }, + ...options.minimize + } + + const restore = { + onClick: () => { + webGroupsManager.onRestoreButtonClick(TargetType.HtmlButtons, options.targetId); + }, + ...options.restore + } + + const maximize = { + onClick: () => { + webGroupsManager.onMaximizeButtonClick(TargetType.HtmlButtons, options.targetId); + }, + ...options.maximize + } + + const close = { + onClick: () => { + webGroupsManager.onCloseButtonClick(TargetType.HtmlButtons, options.targetId); + }, + ...options.close + } + + let customButtonsProps = new Array(); + if (options.customButtons) { + customButtonsProps = options.customButtons.map((cButton) => { + return { + onClick: () => { + webGroupsManager.clickCustomButton(options.targetId, cButton.buttonId); + }, + visible: true, + imageData: cButton.imageData, + tooltip: cButton.tooltip, + buttonId: cButton.buttonId + } + }); + } + + return + }); + } + return <> {renderGroupCaptionBar()} {renderGroupOverlay()} @@ -519,7 +710,9 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { {renderTabElements()} {renderAfterTabsZones()} {renderTabHeaderButtons()} + {renderTabOverflowPopups()} {renderBelowTabs()} + {renderHtmlButtons()} = ({ components }) => { onCreateFrameWindowOverlayRequested={components?.frame?.Overlay ? webGroupsStore.onCreateFrameWindowOverlayRequested : undefined} onCreateAboveWindowRequested={components?.frame?.AboveWindow ? webGroupsStore.onCreateAboveWindowRequested : undefined} onCreateWindowContentOverlayRequested={components?.frame?.WindowContentOverlay ? webGroupsStore.onCreateWindowContentOverlayRequested : undefined} - onCreateFrameLoadingAnimationRequested={components?.frame?.LoadingAnimation ? webGroupsStore.onCreateFrameLoadingAnimationRequested : undefined} + onCreateFrameLoadingAnimationRequested={LoadingAnimation ? webGroupsStore.onCreateFrameLoadingAnimationRequested : undefined} onCreateBelowWindowRequested={components?.frame?.BelowWindow ? webGroupsStore.onCreateBelowWindowRequested : undefined} onCreateAboveTabsRequested={components?.tabs?.Above ? webGroupsStore.onCreateAboveTabsComponentRequested : undefined} onCreateBeforeTabsComponentRequested={components?.tabs?.Before ? webGroupsStore.onCreateBeforeTabsComponentRequested : undefined} @@ -535,6 +728,8 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { onCreateAfterTabsComponentRequested={components?.tabs?.After ? webGroupsStore.onCreateAfterTabsComponentRequested : undefined} onCreateTabHeaderButtonsRequested={components?.tabs?.Buttons ? webGroupsStore.onCreateTabHeaderButtonsRequested : undefined} onCreateBelowTabsRequested={components?.tabs?.Below ? webGroupsStore.onCreateBelowTabsComponentRequested : undefined} + onCreateHtmlButtonsRequested={components?.html?.Buttons ? webGroupsStore.onCreateHtmlButtonsRequested : undefined} + onCreateTabOverflowPopupRequested={components?.tabs?.OverflowPopup ? webGroupsStore.onCreateTabOverflowPopupRequested : undefined} onUpdateGroupCaptionBarRequested={components?.group?.CaptionBar ? webGroupsStore.onUpdateGroupCaptionBarRequested : undefined} onUpdateFrameWindowOverlayRequested={components?.group?.Overlay ? webGroupsStore.onUpdateFrameWindowOverlayRequested : undefined} onUpdateFrameCaptionBarRequested={components?.flat?.CaptionBar ? webGroupsStore.onUpdateFrameCaptionBarRequested : undefined} @@ -558,13 +753,16 @@ const GroupElementCreationWrapper: React.FC = ({ components }) => { onRemoveAfterTabsComponentRequested={webGroupsStore.onRemoveAfterTabsComponentRequested} onRemoveTabHeaderButtonsRequested={webGroupsStore.onRemoveTabHeaderButtonsRequested} onRemoveBelowTabsRequested={webGroupsStore.onRemoveBelowTabsRequested} + onRemoveHtmlButtonsRequested={webGroupsStore.onRemoveHtmlButtonsRequested} + onRemoveTabOverflowPopupRequested={webGroupsStore.onRemoveTabOverflowPopupRequested} onShowCaptionEditorRequested={webGroupsStore.onShowCaptionEditorRequested} onCommitCaptionEditingRequested={webGroupsStore.onCommitCaptionEditingRequested} onHideCaptionEditorRequested={webGroupsStore.onHideCaptionEditorRequested} onShowLoadingAnimationRequested={webGroupsStore.onShowLoadingAnimationRequested} onHideLoadingAnimationRequested={webGroupsStore.onHideLoadingAnimationRequested} + styles={styles} /> } -export default GroupElementCreationWrapper; \ No newline at end of file +export default GroupElementCreationWrapper; diff --git a/src/GroupWrapper.tsx b/src/GroupWrapper.tsx index b1e3537..41f36eb 100644 --- a/src/GroupWrapper.tsx +++ b/src/GroupWrapper.tsx @@ -37,7 +37,13 @@ class GroupWrapper extends React.Component { createTabBarButtonsContainerElement: this.props.onCreateTabHeaderButtonsRequested, createBelowTabs: this.props.onCreateBelowTabsRequested, updateBelowTabs: this.props.onUpdateBelowTabsRequested, + + createHtmlButtonsContainerElement: this.props.onCreateHtmlButtonsRequested, + destroyHtmlButtonsContainerElement: this.props.onRemoveHtmlButtonsRequested, + createTabOverflowPopup:this.props.onCreateTabOverflowPopupRequested, + destroyTabOverflowPopup: this.props.onRemoveTabOverflowPopupRequested, + updateFrame: this.props.onUpdateFrameRequested, updateStandardButton: this.props.onUpdateStandardButtonRequested, updateCustomButtons: this.props.onUpdateCustomButtonsRequested, @@ -61,6 +67,23 @@ class GroupWrapper extends React.Component { }; webGroupsManager.init(undefined, componentFactory); + webGroupsManager.updateTabHeaderStyles(this.props.styles?.tabs?.header ?? {}); + webGroupsManager.updateTabMoveAreaStyles(this.props.styles?.tabs?.moveArea ?? {}); + webGroupsManager.updateFrameStyles(this.props.styles?.frame?.element ?? {}); + } + + componentDidUpdate(prevProps: Readonly, prevState: Readonly<{}>, snapshot?: any): void { + if (this.props.styles?.tabs?.header !== prevProps.styles?.tabs?.header) { + webGroupsManager.updateTabHeaderStyles(this.props.styles?.tabs?.header ?? {}); + } + + if (this.props.styles?.tabs?.moveArea !== prevProps.styles?.tabs?.moveArea) { + webGroupsManager.updateTabMoveAreaStyles(this.props.styles?.tabs?.moveArea ?? {}); + } + + if (this.props.styles?.frame?.element !== prevProps.styles?.frame?.element) { + webGroupsManager.updateFrameStyles(this.props.styles?.frame?.element ?? {}); + } } componentWillUnmount() { diff --git a/src/defaultComponents/buttons/CloneButton.tsx b/src/defaultComponents/buttons/CloneButton.tsx new file mode 100644 index 0000000..a07eba7 --- /dev/null +++ b/src/defaultComponents/buttons/CloneButton.tsx @@ -0,0 +1,11 @@ +import React from "react"; +import { CloneButtonProps } from "../../types/defaultComponents"; +import BaseButton from "./BaseButton"; + +const CloneButton: React.FC = ({ onClick, tooltip }) => { + return +} + +export default CloneButton; \ No newline at end of file diff --git a/src/defaultComponents/buttons/OverflowButton.tsx b/src/defaultComponents/buttons/OverflowButton.tsx new file mode 100644 index 0000000..efaf6f5 --- /dev/null +++ b/src/defaultComponents/buttons/OverflowButton.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import { OverflowButtonProps } from "../../types/defaultComponents"; +import BaseButton from "./BaseButton"; + +const OverflowButton: React.FC = ({ onClick, tooltip }) => { + return e.stopPropagation(), + onPointerDown: (e) => e.stopPropagation(), + className: "t42-button t42-caption-bar-button t42-tab-bar-button t42-caption-bar-button-overflow", title: tooltip, onClick + }} /> +} + +export default OverflowButton; \ No newline at end of file diff --git a/src/defaultComponents/channelSelector/BaseChannelSelector.tsx b/src/defaultComponents/channelSelector/BaseChannelSelector.tsx index eee6e8a..0406031 100644 --- a/src/defaultComponents/channelSelector/BaseChannelSelector.tsx +++ b/src/defaultComponents/channelSelector/BaseChannelSelector.tsx @@ -2,7 +2,7 @@ import React, { useEffect, useRef } from "react"; import { BaseChannelSelectorProps } from "../../types/defaultComponents"; import { IsBlackReadable } from "./utils"; -const BaseChannelSelector: React.FC = ({ outsideClass, contentClass, showSelector, selectedChannel, selectedChannelColor }) => { +const BaseChannelSelector: React.FC = ({ outsideClass, contentClass, showSelector, selectedChannel, selectedChannelColor, direction, channelLabel }) => { const ref = useRef(null); const wrappedOnClick = () => { if (!ref.current) { @@ -18,9 +18,14 @@ const BaseChannelSelector: React.FC = ({ outsideClass, } useEffect(() => { - ref.current?.addEventListener("mousedown", (e) => { + const handler = (e: MouseEvent) => { e.stopPropagation(); - }); + }; + const current = ref.current; + current?.addEventListener("mousedown", handler); + return ()=> { + current?.removeEventListener("mousedown", handler); + } }, [ref]); let className = contentClass; @@ -36,9 +41,13 @@ const BaseChannelSelector: React.FC = ({ outsideClass, return
-
-
+ {channelLabel ? +
+ {channelLabel} + {direction && } +
:
+
}
}; -export default BaseChannelSelector; \ No newline at end of file +export default BaseChannelSelector; diff --git a/src/defaultComponents/channelSelector/FlatChannelSelector.tsx b/src/defaultComponents/channelSelector/FlatChannelSelector.tsx index 153fa2f..26d802d 100644 --- a/src/defaultComponents/channelSelector/FlatChannelSelector.tsx +++ b/src/defaultComponents/channelSelector/FlatChannelSelector.tsx @@ -1,13 +1,16 @@ import React from "react"; import { FlatChannelSelectorProps } from "../../types/defaultComponents"; import BaseChannelSelector from "./BaseChannelSelector"; +import { getChannelDirection } from "./utils"; -const FlatChannelSelector: React.FC = ({ showSelector, selectedChannel, selectedChannelColor }) => { - return = ({ showSelector, selectedChannel, selectedChannelColor, channelRestrictions, channelLabel }) => { + return }; diff --git a/src/defaultComponents/channelSelector/TabChannelSelector.tsx b/src/defaultComponents/channelSelector/TabChannelSelector.tsx index 92a51b1..c5c89e1 100644 --- a/src/defaultComponents/channelSelector/TabChannelSelector.tsx +++ b/src/defaultComponents/channelSelector/TabChannelSelector.tsx @@ -1,13 +1,16 @@ import React from "react"; import { TabChannelSelectorProps } from "../../types/defaultComponents"; import BaseChannelSelector from "./BaseChannelSelector"; +import { getChannelDirection } from "./utils"; -const TabChannelSelector: React.FC = ({ showSelector, selectedChannel, selectedChannelColor }) => { - return = ({ showSelector, selectedChannel, selectedChannelColor, channelRestrictions, channelLabel }) => { + return }; diff --git a/src/defaultComponents/channelSelector/multi/BaseMultiChannelSelector.tsx b/src/defaultComponents/channelSelector/multi/BaseMultiChannelSelector.tsx new file mode 100644 index 0000000..d79cfe8 --- /dev/null +++ b/src/defaultComponents/channelSelector/multi/BaseMultiChannelSelector.tsx @@ -0,0 +1,68 @@ +import React, { useEffect, useRef, useState } from "react"; +import { BaseMultiChannelSelectorProps } from "../../../types/defaultComponents"; +import BaseChannelSelector from "../BaseChannelSelector"; +import { getChannelDirection } from "../utils"; + +const BaseMultiChannelSelector: React.FC = ({ outsideClass, contentClass, showSelector, selectedChannels, channelLabel, channelRestrictions }) => { + const ref = useRef(null); + const len = selectedChannels.length; + const showBaseChannelSelector = len < 2; + const wrappedOnClick = () => { + if (!ref.current) { + return; + } + + const bounds = ref.current.getBoundingClientRect(); + showSelector({ + left: bounds.left, + top: bounds.top, + width: bounds.width, + height: bounds.height, + }); + } + + useEffect(() => { + if (showBaseChannelSelector) { + return; + } + + const handler = (e: MouseEvent) => { + e.stopPropagation(); + }; + const current = ref.current; + ref.current?.addEventListener("mousedown", handler); + return () => { + current?.removeEventListener("mousedown", handler); + } + }, [ref, showBaseChannelSelector]); + + if (showBaseChannelSelector) { + return ; + } + + const colors = selectedChannels.map((channel) => channel.color) ?? []; + const title = colors.join(", "); + const lenMax4 = Math.min(len, 4); + const cssClass = `t42-multi-channel-selector-content t42-multi-channel-selector-${lenMax4}`; + let style: any = {}; + colors.forEach((color: string, index: number) => { + const colorVarName = `--t42-multi-channel-selector-${lenMax4}-color-${index + 1}`; + style[colorVarName] = color; + }); + + return ( +
+
+
+
+ ); +}; + +export default BaseMultiChannelSelector; diff --git a/src/defaultComponents/channelSelector/multi/FlatMultiChannelSelector.tsx b/src/defaultComponents/channelSelector/multi/FlatMultiChannelSelector.tsx new file mode 100644 index 0000000..d7c29fd --- /dev/null +++ b/src/defaultComponents/channelSelector/multi/FlatMultiChannelSelector.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import { FlatMultiChannelSelectorProps } from "../../../types/defaultComponents"; +import BaseMultiChannelSelector from "./BaseMultiChannelSelector"; + +const FlatMultiChannelSelector: React.FC = ({ showSelector, selectedChannels, channelRestrictions, channelLabel }) => { + return +}; + +export default FlatMultiChannelSelector; diff --git a/src/defaultComponents/channelSelector/multi/TabMultiChannelSelector.tsx b/src/defaultComponents/channelSelector/multi/TabMultiChannelSelector.tsx new file mode 100644 index 0000000..64a156d --- /dev/null +++ b/src/defaultComponents/channelSelector/multi/TabMultiChannelSelector.tsx @@ -0,0 +1,15 @@ +import React from "react"; +import { TabMultiChannelSelectorProps } from "../../../types/defaultComponents"; +import BaseMultiChannelSelector from "./BaseMultiChannelSelector"; + +const TabMultiChannelSelector: React.FC = ({ showSelector, selectedChannels, channelRestrictions, channelLabel }) => { + return +}; + +export default TabMultiChannelSelector; diff --git a/src/defaultComponents/channelSelector/utils.ts b/src/defaultComponents/channelSelector/utils.ts index e7e8a6d..9818753 100644 --- a/src/defaultComponents/channelSelector/utils.ts +++ b/src/defaultComponents/channelSelector/utils.ts @@ -23,4 +23,24 @@ export function IsBlackReadable(color: string) { console.error(`Error while checking readable color for '${color}'`, error); } return false; -} \ No newline at end of file +} + +export function getChannelDirection(channelRestrictions: { read: boolean, write: boolean }): string { + if (!channelRestrictions) { + return ""; + } + if (typeof channelRestrictions.read === "boolean" && typeof channelRestrictions.write === "boolean") { + if (channelRestrictions.read && channelRestrictions.write) { + return ""; + } + if (channelRestrictions.read) { + return "subscribe"; + } + if (channelRestrictions.write) { + return "publish" + } + return ""; + } else { + return ""; + } +}; \ No newline at end of file diff --git a/src/defaultComponents/flatCaptionBar/FlatButtons.tsx b/src/defaultComponents/flatCaptionBar/FlatButtons.tsx index f5c0bb5..e2aa385 100644 --- a/src/defaultComponents/flatCaptionBar/FlatButtons.tsx +++ b/src/defaultComponents/flatCaptionBar/FlatButtons.tsx @@ -3,6 +3,7 @@ import { FlatButtonsProps } from "../../types/defaultComponents"; import CloseButton from "../buttons/CloseButton"; import ExtractButton from "../buttons/ExtractButton"; import FeedbackButton from "../buttons/FeedbackButton"; +import CloneButton from "../buttons/CloneButton"; import StickyButton from "../buttons/StickyButton"; import LockButton from "../buttons/LockButtons"; import MaximizeButton from "../buttons/MaximizeButton"; @@ -11,7 +12,7 @@ import RestoreButton from "../buttons/RestoreButton"; import UnlockButton from "../buttons/UnlockButton"; import CustomButton from "../buttons/CustomButton"; -const FlatButtons: React.FC = ({ extract, minimize, maximize, restore, close, lock, unlock, feedback, sticky, customButtons }) => { +const FlatButtons: React.FC = ({ extract, minimize, maximize, restore, close, lock, unlock, feedback, clone, sticky, customButtons }) => { return
    { @@ -22,6 +23,7 @@ const FlatButtons: React.FC = ({ extract, minimize, maximize,
    {feedback?.visible && } + {clone?.visible && } {sticky?.visible && } {extract?.visible && } {lock?.visible && } diff --git a/src/defaultComponents/flatCaptionBar/FlatCaptionBar.tsx b/src/defaultComponents/flatCaptionBar/FlatCaptionBar.tsx index ba21ec1..c3f331a 100644 --- a/src/defaultComponents/flatCaptionBar/FlatCaptionBar.tsx +++ b/src/defaultComponents/flatCaptionBar/FlatCaptionBar.tsx @@ -5,14 +5,22 @@ import FlatButtons from "./FlatButtons"; import FlatCaption from "./FlatCaption"; import FlatCaptionEditor from "./FlatCaptionEditor"; import FlatMoveArea from "./FlatMoveArea"; +import FlatMultiChannelSelector from "../channelSelector/multi/FlatMultiChannelSelector"; const FlatCaptionBar: React.FC = ({ moveAreaId, caption, channels, captionEditor, notifyCaptionBoundsChanged, ...rest }) => { return (
    - {channels?.visible && } + selectedChannelColor={channels?.selectedChannelColor} + channelRestrictions={channels?.channelRestrictions} + channelLabel={channels?.channelLabel} />} + {channels?.visible && channels.channelsMode === "multi" && } {captionEditor.show ? : } @@ -20,4 +28,4 @@ const FlatCaptionBar: React.FC = ({ moveAreaId, caption, ch
    ); }; -export default FlatCaptionBar; \ No newline at end of file +export default FlatCaptionBar; diff --git a/src/defaultComponents/htmlButtonsBar/buttons.tsx b/src/defaultComponents/htmlButtonsBar/buttons.tsx new file mode 100644 index 0000000..da11e1a --- /dev/null +++ b/src/defaultComponents/htmlButtonsBar/buttons.tsx @@ -0,0 +1,40 @@ +import React from "react"; +import { HtmlButtonsProps } from "../../types/api"; +import CloseButton from "../buttons/CloseButton"; +import ExtractButton from "../buttons/ExtractButton"; +import FeedbackButton from "../buttons/FeedbackButton"; +import CloneButton from "../buttons/CloneButton"; +import LockButton from "../buttons/LockButtons"; +import MaximizeButton from "../buttons/MaximizeButton"; +import MinimizeButton from "../buttons/MinimizeButton"; +import RestoreButton from "../buttons/RestoreButton"; +import StickyButton from "../buttons/StickyButton"; +import UnlockButton from "../buttons/UnlockButton"; +import CustomButton from "../buttons/CustomButton"; + +const HtmlButtons: React.FC = ({ extract, minimize, maximize, restore, close, lock, unlock, feedback, clone, sticky, customButtons }) => { + return
    +
      + { + customButtons.map(customButton => { + return customButton.visible && + }) + } +
    +
      + {feedback?.visible && } + {clone?.visible && } + {sticky?.visible && } + {extract?.visible && } + {lock?.visible && } + {unlock?.visible && } + {minimize?.visible && } + {restore?.visible && } + {maximize?.visible && } + {close?.visible && } +
    +
    +}; + + +export default HtmlButtons; \ No newline at end of file diff --git a/src/defaultComponents/loadingAnimation/FrameLoadingAnimation.tsx b/src/defaultComponents/loadingAnimation/FrameLoadingAnimation.tsx index a367286..9dd3344 100644 --- a/src/defaultComponents/loadingAnimation/FrameLoadingAnimation.tsx +++ b/src/defaultComponents/loadingAnimation/FrameLoadingAnimation.tsx @@ -5,7 +5,7 @@ const FrameLoadingAnimation: React.FC = ({show}) => return ( show ? ( -
    +
    Loading...
    diff --git a/src/defaultComponents/popups/TabOverflowPopup.tsx b/src/defaultComponents/popups/TabOverflowPopup.tsx new file mode 100644 index 0000000..7b836ed --- /dev/null +++ b/src/defaultComponents/popups/TabOverflowPopup.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import { TabOverflowPopupProps } from '../../types/api'; +import { OverflowedTabInfo } from '../../types/internal'; + +const TabOverflowPopup: React.FC = ({ + hiddenTabsToTheLeft, + hiddenTabsToTheRight, + close, + select +}) => { + const createSection = (tabs: OverflowedTabInfo[], title: string) => { + return ( +
      +
    • {title}
    • + {tabs.map((tab) => ( +
    • handleTabClick(tab.windowId)}> + {tab.title} +
      { + e.stopPropagation(); + handleTabClose(tab.windowId) + }}>
      +
    • + ))} +
    + ); + }; + + const handleTabClick = (windowId: string) => { + select(windowId); + }; + + const handleTabClose = (windowId: string) => { + close(windowId); + }; + + return ( +
    + {hiddenTabsToTheLeft.length > 0 && createSection(hiddenTabsToTheLeft, "Open left")} + {hiddenTabsToTheLeft.length > 0 && hiddenTabsToTheRight.length > 0 &&
    } + {hiddenTabsToTheRight.length > 0 && createSection(hiddenTabsToTheRight, "Open right")} +
    + ); +}; + +export default TabOverflowPopup; \ No newline at end of file diff --git a/src/defaultComponents/tabs/Tab.tsx b/src/defaultComponents/tabs/Tab.tsx index a52084d..4274329 100644 --- a/src/defaultComponents/tabs/Tab.tsx +++ b/src/defaultComponents/tabs/Tab.tsx @@ -1,18 +1,20 @@ import React from "react"; import { TabElementProps } from "../../types/api"; import TabChannelSelector from "../channelSelector/TabChannelSelector"; +import TabMultiChannelSelector from "../channelSelector/multi/TabMultiChannelSelector"; import TabCaption from "./TabCaption"; import TabCaptionEditor from "./TabCaptionEditor"; import TabCloseButton from "./TabCloseButton"; -const Tab: React.FC = ({ caption, selected, close, channels, captionEditor, notifyCaptionBoundsChanged, windowId }) => { +const Tab: React.FC = ({ caption, selected, close, channels, captionEditor, notifyCaptionBoundsChanged, windowId, pinned }) => { return
    - {channels.visible && } + {channels.visible && channels.channelsMode !== "multi" && } + {channels.visible && channels.channelsMode === "multi" && } {captionEditor.show ? : } - + {pinned ? <> : }
    }; -export default Tab; \ No newline at end of file +export default Tab; diff --git a/src/defaultComponents/tabs/TabHeaderButtons.tsx b/src/defaultComponents/tabs/TabHeaderButtons.tsx index 99fa4ac..e4c5787 100644 --- a/src/defaultComponents/tabs/TabHeaderButtons.tsx +++ b/src/defaultComponents/tabs/TabHeaderButtons.tsx @@ -3,6 +3,7 @@ import { TabHeaderButtonsProps } from "../../types/api"; import CloseButton from "../buttons/CloseButton"; import ExtractButton from "../buttons/ExtractButton"; import FeedbackButton from "../buttons/FeedbackButton"; +import CloneButton from "../buttons/CloneButton"; import LockButton from "../buttons/LockButtons"; import MaximizeButton from "../buttons/MaximizeButton"; import MinimizeButton from "../buttons/MinimizeButton"; @@ -10,8 +11,9 @@ import RestoreButton from "../buttons/RestoreButton"; import StickyButton from "../buttons/StickyButton"; import UnlockButton from "../buttons/UnlockButton"; import CustomButton from "../buttons/CustomButton"; +import OverflowButton from "../buttons/OverflowButton"; -const TabHeaderButtons: React.FC = ({ extract, minimize, maximize, restore, close, lock, unlock, feedback, sticky, customButtons }) => { +const TabHeaderButtons: React.FC = ({ overflow, extract, minimize, maximize, restore, close, lock, unlock, feedback, clone, sticky, customButtons }) => { return
      { @@ -21,7 +23,9 @@ const TabHeaderButtons: React.FC = ({ extract, minimize, }
      + {overflow?.visible && } {feedback?.visible && } + {clone?.visible && } {sticky?.visible && } {extract?.visible && } {lock?.visible && } diff --git a/src/index.tsx b/src/index.tsx index 33da5de..d482108 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,178 +1,196 @@ -import CloseButton from "./defaultComponents/buttons/CloseButton"; -import FlatCaptionBar from "./defaultComponents/flatCaptionBar/FlatCaptionBar"; -import GroupCaptionBar from "./defaultComponents/groupCaptionBar/GroupCaptionBar"; -import MaximizeButton from "./defaultComponents/buttons/MaximizeButton"; -import MinimizeButton from "./defaultComponents/buttons/MinimizeButton"; -import Tab from "./defaultComponents/tabs/Tab"; -import TabHeaderButtons from "./defaultComponents/tabs/TabHeaderButtons"; -import TabCaption from "./defaultComponents/tabs/TabCaption"; -import TabCloseButton from "./defaultComponents/tabs/TabCloseButton"; -import GroupElementCreationWrapper from "./GroupElementCreationWrapper"; -import webGroupsManager from "./webGroupsManager"; -import GroupMoveArea from "./defaultComponents/groupCaptionBar/GroupMoveArea"; -import GroupButtons from "./defaultComponents/groupCaptionBar/GroupButtons"; -import FlatMoveArea from "./defaultComponents/flatCaptionBar/FlatMoveArea"; -import FlatButtons from "./defaultComponents/flatCaptionBar/FlatButtons"; -import FlatCaption from "./defaultComponents/flatCaptionBar/FlatCaption"; -import GroupCaption from "./defaultComponents/groupCaptionBar/GroupCaption"; -import FlatChannelSelector from "./defaultComponents/channelSelector/FlatChannelSelector"; -import TabChannelSelector from "./defaultComponents/channelSelector/TabChannelSelector"; -import RestoreButton from "./defaultComponents/buttons/RestoreButton"; -import LockButton from "./defaultComponents/buttons/LockButtons"; -import UnlockButton from "./defaultComponents/buttons/UnlockButton"; -import ExtractButton from "./defaultComponents/buttons/ExtractButton"; -import FeedbackButton from "./defaultComponents/buttons/FeedbackButton"; -import StickyButton from "./defaultComponents/buttons/StickyButton"; -import useIOConnectWindow from "./useIOConnectWindow"; -import CustomButton from "./defaultComponents/buttons/CustomButton"; -import { waitForWindow } from "./utils"; -import useGroupComponentVisibility from "./useGroupComponentVisibility"; -import { - CloseButtonProps, - ExtractButtonProps, - StickyButtonProps, - FeedbackButtonProps, - FlatButtonsProps, - FlatCaptionEditorProps, - FlatCaptionProps, - FlatChannelSelectorProps, - FlatMoveAreaProps, - GroupButtonsProps, - GroupCaptionEditorProps, - GroupMoveAreaProps, - LockButtonProps, - MaximizeButtonProps, - MinimizeButtonProps, - RestoreButtonProps, - TabCaptionEditorProps, - TabCaptionProps, - TabChannelSelectorProps, - TabCloseButtonProps, - UnlockButtonProps, - UseCaptionEditorOptions, - UseEditableCaptionOptions -} from "./types/defaultComponents"; -import { - AboveTabsProps, - AboveWindowProps, - AfterTabsProps, - BeforeTabsProps, - BelowTabsProps, - BelowWindowProps, - FlatCaptionBarProps, - FrameLoadingAnimationProps, - FrameWindowOverlayProps, - GroupCaptionBarProps, - GroupComponentVisibilityState, - GroupOverlayProps, - GroupProps, - MoveAreaProps, - TabElementProps, - TabHeaderButtonsProps, - WindowContentOverlayProps, -} from "./types/api"; -import GroupCaptionEditor from "./defaultComponents/groupCaptionBar/GroupCaptionEditor"; -import FlatCaptionEditor from "./defaultComponents/flatCaptionBar/FlatCaptionEditor"; -import TabCaptionEditor from "./defaultComponents/tabs/TabCaptionEditor"; -import { TargetType } from "./types/internal"; -import useCommitTabCaptionEditingRequested from "./defaultComponents/tabs/useCommitTabCaptionEditingRequested"; -import useCommitGroupCaptionEditingRequested from "./defaultComponents/groupCaptionBar/useCommitGroupCaptionEditingRequested"; -import useCommitFlatCaptionEditingRequested from "./defaultComponents/flatCaptionBar/useCommitFlatCaptionEditingRequested"; -import useEditableCaption from "./defaultComponents/captionEditor/useEditableCaption"; -import useCaptionEditor from "./defaultComponents/captionEditor/useCaptionEditor"; -import FrameLoadingAnimation from "./defaultComponents/loadingAnimation/FrameLoadingAnimation"; - - - -export { - GroupCaptionBar, - GroupMoveArea, - GroupButtons, - GroupCaptionEditor, - Tab, - TabChannelSelector, - TabCaption, - TabCloseButton, - TabCaptionEditor, - FeedbackButton, - StickyButton, - ExtractButton, - LockButton, - UnlockButton, - MinimizeButton, - RestoreButton, - MaximizeButton, - CustomButton, - CloseButton, - FlatCaptionBar, - FlatChannelSelector, - FlatCaption, - FlatMoveArea, - FlatButtons, - FlatCaptionEditor, - TabHeaderButtons, - FrameLoadingAnimation, - GroupComponentVisibilityState, - useIOConnectWindow, - useGroupComponentVisibility, - waitForWindow, - useEditableCaption, - useCaptionEditor, - useCommitGroupCaptionEditingRequested, - useCommitFlatCaptionEditingRequested, - useCommitTabCaptionEditingRequested, -} - -export const getGroupId: () => string = () => webGroupsManager?.getGroupId(); -export const requestPageFocus: () => void = () => webGroupsManager?.requestPageFocus(); -export const requestFrameFocus: (frameId: string) => void = (frameId) => webGroupsManager?.requestFrameFocus(frameId); -export const requestGroupFocus: () => void = () => webGroupsManager?.requestGroupFocus(); - -export const onCommitGroupCaptionEditingRequested = (targetId: string, cb: () => void) => webGroupsManager.onCommitCaptionEditingRequested(TargetType.Group, targetId, cb); -export const onCommitFlatCaptionEditingRequested = (targetId: string, cb: () => void) => webGroupsManager.onCommitCaptionEditingRequested(TargetType.Frame, targetId, cb); -export const onCommitTabCaptionEditingRequested = (targetId: string, cb: () => void) => webGroupsManager.onCommitCaptionEditingRequested(TargetType.Tab, targetId, cb); - -export { - MoveAreaProps, - GroupProps, - GroupCaption, - GroupCaptionBarProps, - GroupMoveAreaProps, - GroupOverlayProps, - GroupButtonsProps, - GroupCaptionEditorProps, - TabElementProps, - TabChannelSelectorProps, - TabCaptionProps, - TabCloseButtonProps, - TabHeaderButtonsProps, - TabCaptionEditorProps, - FlatCaptionBarProps, - FlatCaptionProps, - FrameWindowOverlayProps, - FlatMoveAreaProps, - FlatChannelSelectorProps, - FlatButtonsProps, - FlatCaptionEditorProps, - StickyButtonProps, - FeedbackButtonProps, - ExtractButtonProps, - LockButtonProps, - UnlockButtonProps, - MinimizeButtonProps, - MaximizeButtonProps, - RestoreButtonProps, - CloseButtonProps, - FrameLoadingAnimationProps, - UseCaptionEditorOptions, - UseEditableCaptionOptions, - AboveWindowProps, - BelowWindowProps, - AboveTabsProps, - BelowTabsProps, - BeforeTabsProps, - AfterTabsProps, - WindowContentOverlayProps -} - -export default GroupElementCreationWrapper; +import CloseButton from "./defaultComponents/buttons/CloseButton"; +import FlatCaptionBar from "./defaultComponents/flatCaptionBar/FlatCaptionBar"; +import GroupCaptionBar from "./defaultComponents/groupCaptionBar/GroupCaptionBar"; +import MaximizeButton from "./defaultComponents/buttons/MaximizeButton"; +import MinimizeButton from "./defaultComponents/buttons/MinimizeButton"; +import Tab from "./defaultComponents/tabs/Tab"; +import TabHeaderButtons from "./defaultComponents/tabs/TabHeaderButtons"; +import TabCaption from "./defaultComponents/tabs/TabCaption"; +import TabCloseButton from "./defaultComponents/tabs/TabCloseButton"; +import GroupElementCreationWrapper from "./GroupElementCreationWrapper"; +import webGroupsManager from "./webGroupsManager"; +import GroupMoveArea from "./defaultComponents/groupCaptionBar/GroupMoveArea"; +import GroupButtons from "./defaultComponents/groupCaptionBar/GroupButtons"; +import FlatMoveArea from "./defaultComponents/flatCaptionBar/FlatMoveArea"; +import FlatButtons from "./defaultComponents/flatCaptionBar/FlatButtons"; +import FlatCaption from "./defaultComponents/flatCaptionBar/FlatCaption"; +import GroupCaption from "./defaultComponents/groupCaptionBar/GroupCaption"; +import FlatChannelSelector from "./defaultComponents/channelSelector/FlatChannelSelector"; +import TabChannelSelector from "./defaultComponents/channelSelector/TabChannelSelector"; +import RestoreButton from "./defaultComponents/buttons/RestoreButton"; +import LockButton from "./defaultComponents/buttons/LockButtons"; +import UnlockButton from "./defaultComponents/buttons/UnlockButton"; +import ExtractButton from "./defaultComponents/buttons/ExtractButton"; +import FeedbackButton from "./defaultComponents/buttons/FeedbackButton"; +import CloneButton from "./defaultComponents/buttons/CloneButton"; +import StickyButton from "./defaultComponents/buttons/StickyButton"; +import OverflowButton from "./defaultComponents/buttons/OverflowButton"; +import useIOConnectWindow from "./useIOConnectWindow"; +import CustomButton from "./defaultComponents/buttons/CustomButton"; +import { waitForWindow } from "./utils"; +import useGroupComponentVisibility from "./useGroupComponentVisibility"; +import { + CloseButtonProps, + ExtractButtonProps, + StickyButtonProps, + FeedbackButtonProps, + FlatButtonsProps, + FlatCaptionEditorProps, + FlatCaptionProps, + FlatChannelSelectorProps, + FlatMoveAreaProps, + GroupButtonsProps, + GroupCaptionEditorProps, + GroupMoveAreaProps, + LockButtonProps, + MaximizeButtonProps, + MinimizeButtonProps, + RestoreButtonProps, + TabCaptionEditorProps, + TabCaptionProps, + TabChannelSelectorProps, + TabCloseButtonProps, + UnlockButtonProps, + UseCaptionEditorOptions, + UseEditableCaptionOptions, + OverflowButtonProps +} from "./types/defaultComponents"; +import { + AboveTabsProps, + AboveWindowProps, + AfterTabsProps, + BeforeTabsProps, + BelowTabsProps, + BelowWindowProps, + FlatCaptionBarProps, + FrameLoadingAnimationProps, + FrameWindowOverlayProps, + GroupCaptionBarProps, + GroupComponentVisibilityState, + GroupOverlayProps, + GroupProps, + HtmlButtonsProps, + MoveAreaProps, + OpenTabOverflowPopupOptions, + TabElementProps, + TabHeaderButtonsProps, + TabOverflowPopupProps, + WindowContentOverlayProps, +} from "./types/api"; +import GroupCaptionEditor from "./defaultComponents/groupCaptionBar/GroupCaptionEditor"; +import FlatCaptionEditor from "./defaultComponents/flatCaptionBar/FlatCaptionEditor"; +import TabCaptionEditor from "./defaultComponents/tabs/TabCaptionEditor"; +import { Location, TargetType } from "./types/internal"; +import useCommitTabCaptionEditingRequested from "./defaultComponents/tabs/useCommitTabCaptionEditingRequested"; +import useCommitGroupCaptionEditingRequested from "./defaultComponents/groupCaptionBar/useCommitGroupCaptionEditingRequested"; +import useCommitFlatCaptionEditingRequested from "./defaultComponents/flatCaptionBar/useCommitFlatCaptionEditingRequested"; +import useEditableCaption from "./defaultComponents/captionEditor/useEditableCaption"; +import useCaptionEditor from "./defaultComponents/captionEditor/useCaptionEditor"; +import FrameLoadingAnimation from "./defaultComponents/loadingAnimation/FrameLoadingAnimation"; +import HtmlButtons from "./defaultComponents/htmlButtonsBar/buttons"; +import TabOverflowPopup from "./defaultComponents/popups/TabOverflowPopup"; +import TabMultiChannelSelector from "./defaultComponents/channelSelector/multi/TabMultiChannelSelector"; +import FlatMultiChannelSelector from "./defaultComponents/channelSelector/multi/FlatMultiChannelSelector"; + +export { + GroupCaptionBar, + GroupMoveArea, + GroupButtons, + GroupCaptionEditor, + Tab, + TabChannelSelector, + TabCaption, + TabCloseButton, + TabCaptionEditor, + FeedbackButton, + CloneButton, + StickyButton, + ExtractButton, + LockButton, + UnlockButton, + MinimizeButton, + RestoreButton, + MaximizeButton, + CustomButton, + CloseButton, + FlatCaptionBar, + FlatChannelSelector, + FlatCaption, + FlatMoveArea, + FlatButtons, + FlatCaptionEditor, + TabHeaderButtons, + FrameLoadingAnimation, + HtmlButtons, + TabOverflowPopup, + OverflowButton, + GroupComponentVisibilityState, + TabMultiChannelSelector, + FlatMultiChannelSelector, + useIOConnectWindow, + useGroupComponentVisibility, + waitForWindow, + useEditableCaption, + useCaptionEditor, + useCommitGroupCaptionEditingRequested, + useCommitFlatCaptionEditingRequested, + useCommitTabCaptionEditingRequested, +} + +export const getGroupId: () => string = () => webGroupsManager?.getGroupId(); +export const requestPageFocus: () => void = () => webGroupsManager?.requestPageFocus(); +export const requestFrameFocus: (frameId: string) => void = (frameId) => webGroupsManager?.requestFrameFocus(frameId); +export const requestGroupFocus: () => void = () => webGroupsManager?.requestGroupFocus(); +export const openTabOverflowPopup: (options: OpenTabOverflowPopupOptions) => void = ({ frameId, location }: OpenTabOverflowPopupOptions) => webGroupsManager.openTabOverflowPopup(frameId, location); + +export const onCommitGroupCaptionEditingRequested = (targetId: string, cb: () => void) => webGroupsManager.onCommitCaptionEditingRequested(TargetType.Group, targetId, cb); +export const onCommitFlatCaptionEditingRequested = (targetId: string, cb: () => void) => webGroupsManager.onCommitCaptionEditingRequested(TargetType.Frame, targetId, cb); +export const onCommitTabCaptionEditingRequested = (targetId: string, cb: () => void) => webGroupsManager.onCommitCaptionEditingRequested(TargetType.Tab, targetId, cb); + +export { + MoveAreaProps, + GroupProps, + GroupCaption, + GroupCaptionBarProps, + GroupMoveAreaProps, + GroupOverlayProps, + GroupButtonsProps, + GroupCaptionEditorProps, + TabElementProps, + TabChannelSelectorProps, + TabCaptionProps, + TabCloseButtonProps, + TabHeaderButtonsProps, + TabCaptionEditorProps, + HtmlButtonsProps, + FlatCaptionBarProps, + FlatCaptionProps, + FrameWindowOverlayProps, + FlatMoveAreaProps, + FlatChannelSelectorProps, + FlatButtonsProps, + FlatCaptionEditorProps, + OverflowButtonProps, + StickyButtonProps, + FeedbackButtonProps, + ExtractButtonProps, + LockButtonProps, + UnlockButtonProps, + MinimizeButtonProps, + MaximizeButtonProps, + RestoreButtonProps, + CloseButtonProps, + FrameLoadingAnimationProps, + UseCaptionEditorOptions, + UseEditableCaptionOptions, + AboveWindowProps, + BelowWindowProps, + AboveTabsProps, + BelowTabsProps, + BeforeTabsProps, + AfterTabsProps, + WindowContentOverlayProps, + TabOverflowPopupProps, +} + +export default GroupElementCreationWrapper; diff --git a/src/types/api.ts b/src/types/api.ts index ecc565d..1c85938 100644 --- a/src/types/api.ts +++ b/src/types/api.ts @@ -1,5 +1,5 @@ import React from "react"; -import { Bounds, ButtonProps, ToggleButtonProps } from "./internal"; +import { Bounds, ButtonProps, Location, OverflowedTabInfo, StylesOptions, ToggleButtonProps } from "./internal"; import { CustomButtonProps } from "./defaultComponents"; export interface ChannelProps { @@ -7,6 +7,13 @@ export interface ChannelProps { selectedChannel: string; showSelector: (bounds: Bounds) => void; selectedChannelColor: string; + channelsMode: "single" | "multi"; + selectedChannels: { name: string, color: string }[]; + channelRestrictions: { + read: boolean, + write: boolean + }; + channelLabel: string; } export interface FrameWindowOverlayProps { @@ -50,6 +57,14 @@ export interface BelowTabsProps { selectedWindow: string; } +export interface TabOverflowPopupProps { + frameId: string; + select: (windowId: string) => void; + close: (windowId: string) => void; + hiddenTabsToTheLeft: OverflowedTabInfo[]; + hiddenTabsToTheRight: OverflowedTabInfo[]; +} + export interface CaptionEditorProps { show: boolean; text?: string; @@ -83,6 +98,7 @@ export interface FlatCaptionBarProps { moveAreaId: string; caption: string; feedback?: ButtonProps; + clone?: ButtonProps; sticky?: ToggleButtonProps; extract?: ButtonProps; lock?: ButtonProps; @@ -104,19 +120,26 @@ export interface TabElementProps { caption: string; selected: boolean; flashing: boolean; + pinned: boolean; close: () => void; channels: ChannelProps; notifyCaptionBoundsChanged: (bounds: Bounds) => void; captionEditor: CaptionEditorProps; + addContainerClass: (className: string) => void; + removeContainerClass: (className: string) => void; } export interface AfterTabsProps { frameId: string; selectedWindow: string; + hiddenTabsToTheLeft?: OverflowedTabInfo[]; + hiddenTabsToTheRight?: OverflowedTabInfo[]; } -export interface TabHeaderButtonsProps { +interface FrameButtonsProps { + overflow?: ButtonProps; feedback?: ButtonProps; + clone?: ButtonProps; sticky?: ToggleButtonProps; extract?: ButtonProps; lock?: ButtonProps; @@ -130,6 +153,14 @@ export interface TabHeaderButtonsProps { selectedWindow: string; } +export interface TabHeaderButtonsProps extends FrameButtonsProps { + hiddenTabsToTheLeft: OverflowedTabInfo[]; + hiddenTabsToTheRight: OverflowedTabInfo[]; +} + +export interface HtmlButtonsProps extends FrameButtonsProps { +} + export interface GroupProps { components?: { group?: { @@ -153,6 +184,19 @@ export interface GroupProps { After?: React.ComponentType; Buttons?: React.ComponentType; Below?: React.ComponentType; + OverflowPopup?: React.ComponentType; + }; + html?: { + Buttons?: React.ComponentType; + } + }, + styles?: { + tabs?: { + header?: StylesOptions; + moveArea?: StylesOptions; + }, + frame?: { + element?: StylesOptions; } } } @@ -163,4 +207,9 @@ export interface MoveAreaProps { export interface GroupComponentVisibilityState { groupCaptionBarVisible?: boolean; -} \ No newline at end of file +} + +export interface OpenTabOverflowPopupOptions { + frameId: string; + location: Location; +} diff --git a/src/types/defaultComponents.ts b/src/types/defaultComponents.ts index e1df10e..ac62fe3 100644 --- a/src/types/defaultComponents.ts +++ b/src/types/defaultComponents.ts @@ -26,6 +26,10 @@ export interface StickyButtonProps extends ToggleButtonProps { export interface FeedbackButtonProps extends ButtonProps { } +export interface CloneButtonProps extends ButtonProps { +} + + export interface ExtractButtonProps extends ButtonProps { } @@ -38,6 +42,9 @@ export interface UnlockButtonProps extends ButtonProps { export interface MinimizeButtonProps extends ButtonProps { } +export interface OverflowButtonProps extends ButtonProps { +} + export interface MaximizeButtonProps extends ButtonProps { } @@ -48,8 +55,8 @@ export interface CloseButtonProps extends ButtonProps { } export interface CustomButtonProps extends ButtonProps { - imageData: string; - buttonId: string; + imageData: string; + buttonId: string; } export interface BaseButtonProps { @@ -63,18 +70,62 @@ export interface BaseChannelSelectorProps { contentClass: string; selectedChannel: string; selectedChannelColor: string; + direction: string; + channelLabel: string; +} + +export interface BaseMultiChannelSelectorProps { + showSelector: (bounds: Bounds) => void; + outsideClass: string; + contentClass: string; + selectedChannels: { name: string; color: string }[]; + channelRestrictions: { + read: boolean, + write: boolean + }; + channelLabel: string; } export interface FlatChannelSelectorProps { showSelector: (bounds: Bounds) => void; selectedChannel: string; selectedChannelColor: string; + channelRestrictions: { + read: boolean, + write: boolean + }; + channelLabel: string; +} + +export interface FlatMultiChannelSelectorProps { + showSelector: (bounds: Bounds) => void; + selectedChannels: { name: string; color: string }[]; + channelRestrictions: { + read: boolean, + write: boolean + }; + channelLabel: string; } export interface TabChannelSelectorProps { showSelector: (bounds: Bounds) => void; selectedChannel: string; selectedChannelColor: string; + channelRestrictions: { + read: boolean, + write: boolean + }; + channelLabel: string; +} + +export interface TabMultiChannelSelectorProps { + showSelector: (bounds: Bounds) => void; + selectedChannels: { name: string; color: string }[]; + channelRestrictions: { + read: boolean, + write: boolean + }; + channelLabel: string; } export interface FlatCaptionEditorProps { @@ -93,6 +144,7 @@ export interface FlatMoveAreaProps { export interface FlatButtonsProps { feedback?: ButtonProps; + clone?: ButtonProps; sticky?: ToggleButtonProps; extract?: ButtonProps; lock?: ButtonProps; @@ -154,4 +206,4 @@ export interface UseCaptionEditorOptions { export interface UseEditableCaptionOptions { notifyBoundsChanged?: (bounds: Bounds) => void; -} \ No newline at end of file +} diff --git a/src/types/internal.ts b/src/types/internal.ts index f24d94a..8a15e69 100644 --- a/src/types/internal.ts +++ b/src/types/internal.ts @@ -1,5 +1,8 @@ import React from "react"; +type NonMethodKeys = ({ [P in keyof T]: T[P] extends Function ? never : P })[keyof T]; +type NonMethods = Pick>; + export interface PortalProps { parentElement: HTMLElement; children?: React.ReactNode; @@ -11,7 +14,7 @@ export interface ButtonProps { visible: boolean; } -export interface ToggleButtonProps extends ButtonProps{ +export interface ToggleButtonProps extends ButtonProps { isPressed: boolean; } @@ -44,7 +47,9 @@ export interface GroupWrapperProps { onCreateAfterTabsComponentRequested?: (options: CreateFrameElementRequestOptions) => void; onUpdateAfterTabsComponentRequested?: (options: CreateFrameElementRequestOptions) => void; - onCreateTabHeaderButtonsRequested?: (options: CreateTabHeaderButtonsOptions) => void; + onCreateTabHeaderButtonsRequested?: (options: CreateButtonsOptions) => void; + + onCreateTabOverflowPopupRequested?: (options: CreateTabOverflowPopupRequestOptions) => void; onCreateBelowTabsRequested?: (options: CreateFrameElementRequestOptions) => void; onUpdateBelowTabsRequested?: (options: CreateFrameElementRequestOptions) => void; @@ -53,6 +58,9 @@ export interface GroupWrapperProps { onUpdateStandardButtonRequested?: (options: UpdateStandardButtonRequestOptions) => void; onUpdateCustomButtonsRequested?: (options: UpdateCustomButtonsRequestOptions) => void; + onCreateHtmlButtonsRequested?: (options: CreateButtonsOptions) => void; + onRemoveHtmlButtonsRequested?: (options: RemoveRequestOptions) => void; + onRemoveFrameCaptionBarRequested?: (options: RemoveRequestOptions) => void; onRemoveFrameWindowOverlayRequested?: (options: RemoveRequestOptions) => void; onRemoveAboveWindowRequested?: (options: RemoveRequestOptions) => void; @@ -64,14 +72,24 @@ export interface GroupWrapperProps { onRemoveTabRequested?: (options: RemoveRequestOptions) => void; onRemoveAfterTabsComponentRequested?: (options: RemoveRequestOptions) => void; onRemoveTabHeaderButtonsRequested?: (options: RemoveRequestOptions) => void; + onRemoveTabOverflowPopupRequested?: (options: RemoveRequestOptions) => void; onRemoveBelowTabsRequested?: (options: RemoveRequestOptions) => void; onShowCaptionEditorRequested?: (targetType: TargetType, targetId: string, text: string) => void; onCommitCaptionEditingRequested?: (targetType: TargetType, targetId: string) => void; onHideCaptionEditorRequested?: (targetType: TargetType, targetId: string) => void; - onShowLoadingAnimationRequested?: (targetType: TargetType ,targetId: string) => void; - onHideLoadingAnimationRequested?: (targetType: TargetType ,targetId: string) => void; + onShowLoadingAnimationRequested?: (targetType: TargetType, targetId: string) => void; + onHideLoadingAnimationRequested?: (targetType: TargetType, targetId: string) => void; + styles?: { + tabs?: { + header?: StylesOptions; + moveArea?: StylesOptions; + }, + frame?: { + element?: StylesOptions; + } + }; } export interface CreateGroupCaptionBarRequestOptions extends CreateElementRequestOptions { @@ -112,60 +130,30 @@ export interface UpdateFrameCaptionBarRequestOptions extends BaseElementOptions } -export interface CreateFrameCaptionBarRequestOptions extends CreateFrameElementRequestOptions { +export interface CreateFrameCaptionBarRequestOptions extends CreateButtonsOptions { caption: string; moveAreaId: string; channelSelectorVisible: boolean; selectedChannel: string; selectedChannelColor: string; - feedback: { - tooltip: string; - visible: boolean; - }; - sticky: { - tooltip: string; - visible: boolean; - isPressed: boolean; - }; - extract: { - tooltip: string; - visible: boolean; - }; - lock: { - tooltip: string; - visible: boolean; - }; - unlock: { - tooltip: string; - visible: boolean; - }; - minimize: { - tooltip: string; - visible: boolean; - }; - restore: { - tooltip: string; - visible: boolean; - }; - maximize: { - tooltip: string; - visible: boolean; - }; - close: { - tooltip: string; - visible: boolean; - }; captionEditor: { show: boolean; text?: string; }; - customButtons: UpdateCustomButtonOptions[] + channelsMode: "single" | "multi"; + selectedChannels: { name: string; color: string }[]; + channelRestrictions: { + read: boolean, + write: boolean + }; + channelLabel: string; } export interface CreateTabRequestOptions extends CreateElementRequestOptions { caption: string; selected: boolean; flashing: boolean; + pinned: boolean; channelSelectorVisible: boolean; selectedChannel: string; selectedChannelColor: string; @@ -173,6 +161,13 @@ export interface CreateTabRequestOptions extends CreateElementRequestOptions { show: boolean; text?: string; }; + channelsMode: "single" | "multi"; + selectedChannels: { name: string; color: string }[]; + channelRestrictions: { + read: boolean, + write: boolean + }; + channelLabel: string; } export interface UpdateStandardButtonRequestOptions extends CreateElementRequestOptions { @@ -192,11 +187,19 @@ export interface UpdateCustomButtonOptions { imageData: string; } -export interface CreateTabHeaderButtonsOptions extends CreateFrameElementRequestOptions { +export interface CreateButtonsOptions extends CreateFrameElementRequestOptions { + overflow: { + tooltip: string; + visible: boolean; + }, feedback: { tooltip: string; visible: boolean; }; + clone: { + tooltip: string; + visible: boolean; + }; sticky: { tooltip: string; visible: boolean; @@ -230,7 +233,9 @@ export interface CreateTabHeaderButtonsOptions extends CreateFrameElementRequest tooltip: string; visible: boolean; }; - customButtons: UpdateCustomButtonOptions[] + customButtons: UpdateCustomButtonOptions[], + hiddenTabsToTheLeft: OverflowedTabInfo[]; + hiddenTabsToTheRight: OverflowedTabInfo[]; } export interface RemoveRequestOptions { @@ -251,21 +256,37 @@ export interface CreateFrameElementRequestOptions extends CreateElementRequestOp selectedWindow: string; } +export interface OverflowedTabInfo { + title: string; + windowId: string; +} + +export interface CreateTabOverflowPopupRequestOptions extends CreateElementRequestOptions { + hiddenTabsToTheLeft: OverflowedTabInfo[]; + hiddenTabsToTheRight: OverflowedTabInfo[]; +} + export interface CreateFrameLoadingAnimationRequestOptions extends CreateFrameElementRequestOptions { show: boolean; } -export type UpdateFrameRequestOptions = CreateFrameElementRequestOptions; +export interface UpdateFrameRequestOptions extends CreateFrameElementRequestOptions { + hiddenTabsToTheLeft: OverflowedTabInfo[]; + hiddenTabsToTheRight: OverflowedTabInfo[]; +} export enum TargetType { Group = "group", Frame = "frame", TabBar = "tabBar", - Tab = "tab" + Tab = "tab", + HtmlButtons = "html" } export enum StandardButtons { + Overflow = "overflow", Feedback = "feedback", + Clone = "clone", Sticky = "sticky", Extract = "extract", Lock = "lock", @@ -289,8 +310,10 @@ export interface ElementCreationWrapperState { beforeTabsZones: { [targetId: string]: CreateFrameElementRequestOptions }; tabElements: { [targetId: string]: CreateTabRequestOptions }; afterTabsZones: { [targetId: string]: CreateFrameElementRequestOptions }; - tabHeaderButtons: { [targetId: string]: CreateTabHeaderButtonsOptions }; + tabHeaderButtons: { [targetId: string]: CreateButtonsOptions }; + tabOverflowPopups: { [targetId: string]: CreateTabOverflowPopupRequestOptions }; belowTabsZones: { [targetId: string]: CreateFrameElementRequestOptions }; + htmlButtons: { [targetId: string]: CreateButtonsOptions }; } export interface ExternalLibraryFactory { @@ -308,6 +331,16 @@ export interface ExternalLibraryFactory { onCaptionEditorVisibleChanged(targetType: TargetType, targetId: string, visible: boolean): void; onCaptionEditorBoundsChanged(targetType: TargetType, targetId: string, bounds: Bounds): void; commitCaptionEditing(targetType: TargetType, targetId: string, text: string): void; + + updateTabHeaderStyles(styles: StylesOptions): void; + updateTabMoveAreaStyles(styles: StylesOptions): void; + updateFrameStyles(styles: StylesOptions): void; + + selectTab(windowId: string): void; + openTabOverflowPopup(frameId: string, location: Location): void + + addTabContainerClass(windowId: string, className: string): void; + removeTabContainerClass(windowId: string, className: string): void; } export interface WebGroupsManager { @@ -326,7 +359,15 @@ export interface Size { height: number; } -export interface Bounds extends Size { +export interface Location { left: number; top: number; } + +export interface StylesOptions { + css?: Partial>; + classes?: string[] +} + +export interface Bounds extends Size, Location { +} diff --git a/src/webGroupsManager.ts b/src/webGroupsManager.ts index 44f750b..6822e41 100644 --- a/src/webGroupsManager.ts +++ b/src/webGroupsManager.ts @@ -1,4 +1,4 @@ -import { Bounds, StandardButtons, TargetType, WebGroupsManager } from "./types/internal"; +import { Bounds, Location, StandardButtons, StylesOptions, TargetType, WebGroupsManager } from "./types/internal"; import callbackRegistry from "callback-registry"; declare const window: Window & { webGroupsManager: WebGroupsManager }; @@ -55,92 +55,48 @@ class WebGroupsManagerDecorator { return window.webGroupsManager.externalLibraryFactory.focusGroup(); } - public closeFrame(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Frame, targetId, StandardButtons.Close); + public onCloseButtonClick(targetType: TargetType, targetId: string): void { + window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(targetType, targetId, StandardButtons.Close); } - public restoreFrame(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Frame, targetId, StandardButtons.Restore); + public onRestoreButtonClick(targetType: TargetType, targetId: string): void { + window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(targetType, targetId, StandardButtons.Restore); } - public maximizeFrame(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Frame, targetId, StandardButtons.Maximize); + public onMaximizeButtonClick(targetType: TargetType, targetId: string): void { + window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(targetType, targetId, StandardButtons.Maximize); } - public minimizeFrame(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Frame, targetId, StandardButtons.Minimize); + public onMinimizeButtonClick(targetType: TargetType, targetId: string): void { + window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(targetType, targetId, StandardButtons.Minimize); } - public lockFrame(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Frame, targetId, StandardButtons.Lock); + public onLockButtonClick(targetType: TargetType, targetId: string): void { + window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(targetType, targetId, StandardButtons.Lock); } - public unlockFrame(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Frame, targetId, StandardButtons.Unlock); + public onUnlockButtonClick(targetType: TargetType, targetId: string): void { + window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(targetType, targetId, StandardButtons.Unlock); } - public feedbackFrame(targetId: string):void{ - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Frame, targetId, StandardButtons.Feedback); + public onOverflowButtonClick(targetType: TargetType, targetId: string): void { + window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(targetType, targetId, StandardButtons.Overflow); } - public stickyFrame(targetId: string):void{ - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Frame, targetId, StandardButtons.Sticky); + public onFeedbackButtonClick(targetType: TargetType, targetId: string): void { + window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(targetType, targetId, StandardButtons.Feedback); } - public extractFrame(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Frame, targetId, StandardButtons.Extract); + public onCloneButtonClick(targetType: TargetType, targetId: string): void { + window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(targetType, targetId, StandardButtons.Clone); } - public closeTabBar(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.TabBar, targetId, StandardButtons.Close); + public onStickyButtonClick(targetType: TargetType, targetId: string): void { + window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(targetType, targetId, StandardButtons.Sticky); } - public restoreTabBar(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.TabBar, targetId, StandardButtons.Restore); - } - - public maximizeTabBar(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.TabBar, targetId, StandardButtons.Maximize); - } - - public minimizeTabBar(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.TabBar, targetId, StandardButtons.Minimize); - } - - public lockTabBar(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.TabBar, targetId, StandardButtons.Lock); - } - - public unlockTabBar(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.TabBar, targetId, StandardButtons.Unlock); - } - - public feedbackTabBar(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.TabBar, targetId, StandardButtons.Feedback); - } - - public stickyTabBar(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.TabBar, targetId, StandardButtons.Sticky); - } - - public extractTabBar(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.TabBar, targetId, StandardButtons.Extract); - } - - public closeGroup(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Group, targetId, StandardButtons.Close); - } - - public restoreGroup(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Group, targetId, StandardButtons.Restore); - } - - public maximizeGroup(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Group, targetId, StandardButtons.Maximize); - } - - public minimizeGroup(targetId: string): void { - window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(TargetType.Group, targetId, StandardButtons.Minimize); + public onExtractButtonClick(targetType: TargetType, targetId: string): void { + window.webGroupsManager.externalLibraryFactory.onStandardButtonClick(targetType, targetId, StandardButtons.Extract); } public closeTab(targetId: string): void { @@ -202,6 +158,45 @@ class WebGroupsManagerDecorator { public requestCommitCaptionEditing(targetType: TargetType, targetId: string) { this.registry.execute(`${targetType}-${targetId}`); } + + public updateTabHeaderStyles(styles: StylesOptions) { + window.webGroupsManager.externalLibraryFactory.updateTabHeaderStyles(styles); + } + + public updateTabMoveAreaStyles(styles: StylesOptions) { + window.webGroupsManager.externalLibraryFactory.updateTabMoveAreaStyles(styles); + } + + public updateFrameStyles(styles: StylesOptions) { + window.webGroupsManager.externalLibraryFactory.updateFrameStyles(styles); + } + public selectTab(windowId: string): void { + window.webGroupsManager.externalLibraryFactory.selectTab(windowId); + } + + public addTabContainerClass(windowId: string, className: string): void { + if (typeof window.webGroupsManager.externalLibraryFactory.addTabContainerClass !== "function") { + console.warn("The method addTabContainerClass is not supported by the current version of the library"); + return; + } + window.webGroupsManager.externalLibraryFactory.addTabContainerClass(windowId, className); + } + + public removeTabContainerClass(windowId: string, className: string): void { + if (typeof window.webGroupsManager.externalLibraryFactory.removeTabContainerClass !== "function") { + console.warn("The method removeTabContainerClass is not supported by the current version of the library"); + return; + } + window.webGroupsManager.externalLibraryFactory.removeTabContainerClass(windowId, className); + } + + public openTabOverflowPopup(frameId: string, location: Location): void { + if (typeof window.webGroupsManager.externalLibraryFactory.openTabOverflowPopup !== "function") { + console.warn("The method openTabOverflowPopup is not supported by the current version of the library"); + return; + } + window.webGroupsManager.externalLibraryFactory.openTabOverflowPopup(frameId, location); + } } export default new WebGroupsManagerDecorator(); \ No newline at end of file diff --git a/src/webGroupsStore.ts b/src/webGroupsStore.ts index afc8376..1c2ec1a 100644 --- a/src/webGroupsStore.ts +++ b/src/webGroupsStore.ts @@ -3,7 +3,7 @@ import { CreateFrameCaptionBarRequestOptions, CreateFrameElementRequestOptions, CreateGroupCaptionBarRequestOptions, - CreateTabHeaderButtonsOptions, + CreateButtonsOptions, CreateTabRequestOptions, ElementCreationWrapperState, RemoveRequestOptions, @@ -13,7 +13,9 @@ import { UpdateStandardButtonRequestOptions, UpdateFrameRequestOptions, CreateFrameLoadingAnimationRequestOptions, - UpdateCustomButtonsRequestOptions + UpdateCustomButtonsRequestOptions, + CreateTabOverflowPopupRequestOptions, + OverflowedTabInfo } from "./types/internal"; import webGroupsManager from "./webGroupsManager"; @@ -33,8 +35,10 @@ class WebGroupsStore { tabElements: {}, // dict windowId to create tab elements options afterTabsZones: {}, // dict frameId to after tabs zones options tabHeaderButtons: {}, // dict frameId to crate tab header buttons options + tabOverflowPopups: {}, // dict frameId to create tab overflow popup options, belowTabsZones: {}, // dict frameId to create options frameLoadingAnimations: {}, // dict frameId to create options + htmlButtons: {}, // dict frameId to crate html buttons options } public subscribe = (cb: () => void) => { @@ -229,7 +233,7 @@ class WebGroupsStore { }); } - public onCreateTabHeaderButtonsRequested = (options: CreateTabHeaderButtonsOptions) => { + public onCreateTabHeaderButtonsRequested = (options: CreateButtonsOptions) => { if (options === this.state.tabHeaderButtons[options.targetId] || !options) { return; } @@ -259,6 +263,52 @@ class WebGroupsStore { }); } + public onCreateHtmlButtonsRequested = (options: CreateButtonsOptions) => { + if (options === this.state.htmlButtons[options.targetId] || !options) { + return; + } + this.setState(s => { + return { + ...s, + htmlButtons: { + ...s.htmlButtons, + [options.targetId]: options + } + } + }); + } + + public onCreateTabOverflowPopupRequested = (options: CreateTabOverflowPopupRequestOptions) => { + if (options === this.state.tabOverflowPopups[options.targetId] || !options) { + return; + } + + this.setState(s => { + return { + ...s, + tabOverflowPopups: { + ...s.tabOverflowPopups, + [options.targetId]: options + } + } + }); + } + + public onUpdateHtmlButtonsRequested = (options: CreateButtonsOptions) => { + if (options === this.state.htmlButtons[options.targetId] || !options) { + return; + } + this.setState(s => { + return { + ...s, + htmlButtons: { + ...s.htmlButtons, + [options.targetId]: { ...s.htmlButtons[options.targetId], ...options } + } + } + }); + } + public onUpdateGroupCaptionBarRequested = (options: UpdateGroupCaptionBarRequestOptions) => { if (options === this.state.groupCaptionBar) { return; @@ -362,7 +412,7 @@ class WebGroupsStore { }); } - public onUpdateTabHeaderButtonsRequested = (options: CreateTabHeaderButtonsOptions) => { + public onUpdateTabHeaderButtonsRequested = (options: CreateButtonsOptions) => { if (options === this.state.tabHeaderButtons[options.targetId] || !options) { return; } @@ -401,10 +451,23 @@ class WebGroupsStore { return; } - if (s[stateProp]![targetId] && s[stateProp]![targetId]?.selectedWindow !== selectedWindow) { + if (newState[stateProp]![targetId] && newState[stateProp]![targetId]?.selectedWindow !== selectedWindow) { newState[stateProp] = { - ...s[stateProp], - [targetId]: { ...s[stateProp]![targetId], selectedWindow: selectedWindow } + ...newState[stateProp], + [targetId]: { ...newState[stateProp]![targetId], selectedWindow } + } + } + }; + + const updateHiddenTabs = (stateProp: T, targetId: string, hiddenTabsToTheLeft: OverflowedTabInfo[], hiddenTabsToTheRight: OverflowedTabInfo[]) => { + const oldHiddenToTheLeft = newState[stateProp]![targetId]?.hiddenTabsToTheLeft; + const oldHiddenToTheRight = newState[stateProp]![targetId]?.hiddenTabsToTheRight; + newState[stateProp] = { + ...newState[stateProp], + [targetId]: { + ...newState[stateProp]![targetId], + hiddenTabsToTheLeft: hiddenTabsToTheLeft || oldHiddenToTheLeft, + hiddenTabsToTheRight: hiddenTabsToTheRight || oldHiddenToTheRight } } }; @@ -421,64 +484,85 @@ class WebGroupsStore { updateSelectionWindow("belowTabsZones", options.targetId, options.selectedWindow); updateSelectionWindow("frameLoadingAnimations", options.targetId, options.selectedWindow); + updateHiddenTabs("afterTabsZones", options.targetId, options.hiddenTabsToTheLeft, options.hiddenTabsToTheRight); + updateHiddenTabs("tabHeaderButtons", options.targetId, options.hiddenTabsToTheLeft, options.hiddenTabsToTheRight); + return newState; }); } public onUpdateStandardButton = (options: UpdateStandardButtonRequestOptions) => { - const isCaptionBar = options.targetType === TargetType.Group; //this.state.groupCaptionBar?.targetId === options.targetId; - const isFrame = options.targetType === TargetType.Frame; - const isTabHeaderButtons = options.targetType === TargetType.TabBar; - - if (isCaptionBar) { - const currentState = this.state.groupCaptionBar || { targetId: options.targetId } as CreateGroupCaptionBarRequestOptions; - const newOptions = { - ...currentState, - [options.buttonId]: { - ...options - } - }; - this.onUpdateGroupCaptionBarRequested(newOptions as UpdateGroupCaptionBarRequestOptions); - } else if (isFrame && options.targetType === TargetType.Frame) { - const currentState = this.state.frameCaptionBars[options.targetId] || { targetId: options.targetId } as CreateTabHeaderButtonsOptions; - const newOptions = { - ...currentState, - [options.buttonId]: { - ...options - } - }; - this.onUpdateFrameCaptionBarRequested(newOptions); - } else if (isTabHeaderButtons && options.targetType === TargetType.TabBar) { - const currentState = this.state.tabHeaderButtons[options.targetId] || { targetId: options.targetId } as CreateTabHeaderButtonsOptions; - const newOptions = { - ...currentState, - [options.buttonId]: { - ...options - } - }; - - this.onUpdateTabHeaderButtonsRequested(newOptions); + const targetState = { targetId: options.targetId }; + switch (options.targetType) { + case TargetType.Group: + const currentGroupState = this.state.groupCaptionBar || targetState as CreateGroupCaptionBarRequestOptions; + const newGroupOptions = { + ...currentGroupState, + [options.buttonId]: { + ...options + } + }; + this.onUpdateGroupCaptionBarRequested(newGroupOptions); + break; + case TargetType.Frame: + const currentFrameState = this.state.frameCaptionBars[options.targetId] || targetState as CreateFrameCaptionBarRequestOptions; + const newFrameOptions = { + ...currentFrameState, + [options.buttonId]: { + ...options + } + }; + this.onUpdateFrameCaptionBarRequested(newFrameOptions); + break; + case TargetType.TabBar: + const currentTabButtonsState = this.state.tabHeaderButtons[options.targetId] || targetState as CreateButtonsOptions; + const newTabButtonsOptions = { + ...currentTabButtonsState, + [options.buttonId]: { + ...options + } + }; + this.onUpdateTabHeaderButtonsRequested(newTabButtonsOptions); + break; + case TargetType.HtmlButtons: + const currentHtmlButtonsState = this.state.htmlButtons[options.targetId] || targetState as CreateButtonsOptions; + const newHtmlButtonsOptions = { + ...currentHtmlButtonsState, + [options.buttonId]: { + ...options + } + }; + this.onUpdateHtmlButtonsRequested(newHtmlButtonsOptions); + break; } } public onUpdateCustomButtons = (options: UpdateCustomButtonsRequestOptions) => { - const isFrame = options.targetType === TargetType.Frame; - const isTabHeaderButtons = options.targetType === TargetType.TabBar; - - if (isFrame && options.targetType === TargetType.Frame) { - const currentState = this.state.frameCaptionBars[options.targetId] || { targetId: options.targetId } as CreateTabHeaderButtonsOptions; - const newOptions = { - ...currentState, - ...options - }; - this.onUpdateFrameCaptionBarRequested(newOptions); - } else if (isTabHeaderButtons && options.targetType === TargetType.TabBar) { - const currentState = this.state.tabHeaderButtons.customButtons || { customButtons: options.customButtons } as CreateTabHeaderButtonsOptions; - const newOptions = { - ...currentState, - ...options - }; - this.onUpdateTabHeaderButtonsRequested(newOptions); + switch (options.targetType) { + case TargetType.Frame: + const currentFrameState = this.state.frameCaptionBars[options.targetId] || { targetId: options.targetId } as CreateButtonsOptions; + const newFrameOptions = { + ...currentFrameState, + ...options + }; + this.onUpdateFrameCaptionBarRequested(newFrameOptions); + break; + case TargetType.TabBar: + const currentTabBarState = this.state.tabHeaderButtons.customButtons || { customButtons: options.customButtons } as CreateButtonsOptions; + const newTabBarOptions = { + ...currentTabBarState, + ...options + }; + this.onUpdateTabHeaderButtonsRequested(newTabBarOptions); + break; + case TargetType.HtmlButtons: + const currentHtmlButtonsState = this.state.htmlButtons.customButtons || { customButtons: options.customButtons } as CreateButtonsOptions; + const newHtmlButtonsOptions = { + ...currentHtmlButtonsState, + ...options + }; + this.onUpdateHtmlButtonsRequested(newHtmlButtonsOptions); + break; } } @@ -709,6 +793,44 @@ class WebGroupsStore { }); } + public onRemoveHtmlButtonsRequested = (options: RemoveRequestOptions) => { + if (!this.state.htmlButtons[options.targetId]) { + return; + } + this.setState(s => { + const newHtmlObj = Object.keys(s.htmlButtons).reduce((acc, targetId) => { + if (targetId != options.targetId) { + acc[targetId] = s.htmlButtons[targetId]; + } + return acc; + }, {}); + + return { + ...s, + htmlButtons: newHtmlObj + } + }); + } + + public onRemoveTabOverflowPopupRequested = (options: RemoveRequestOptions) => { + if (!this.state.tabOverflowPopups[options.targetId]) { + return; + } + this.setState(s => { + const newTabOverflowPopupsObj = Object.keys(s.tabOverflowPopups).reduce((acc, targetId) => { + if (targetId != options.targetId) { + acc[targetId] = s.tabOverflowPopups[targetId]; + } + return acc; + }, {}); + + return { + ...s, + tabOverflowPopups: newTabOverflowPopupsObj + } + }); + } + public onShowCaptionEditorRequested = (targetType: TargetType, targetId: string, text: string) => { if (targetType === TargetType.Group) { this.onShowGroupCaptionEditorRequested(targetId, text); @@ -733,15 +855,15 @@ class WebGroupsStore { } } - public onShowLoadingAnimationRequested = (targetType: TargetType,targetId: string) => { - if (targetType === TargetType.Frame) { + public onShowLoadingAnimationRequested = (targetType: TargetType, targetId: string) => { + if (targetType === TargetType.Frame) { this.onShowLoadingAnimation(targetId); - } else { + } else { console.warn(`Loading animation for elements other than Frame are not supported`); - } + } } - public onHideLoadingAnimationRequested = (targetType: TargetType,targetId: string) => { + public onHideLoadingAnimationRequested = (targetType: TargetType, targetId: string) => { if (targetType === TargetType.Frame) { this.onHideLoadingAnimation(targetId); } else {