Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <div class-rtabs {{yield extra-attributes}}>
- <div class-tab-window {{#if .direction === 'left'}}class-going-left{{else}}class-going-right{{/if}}>
- <div class-tabs>
- <div class="left-tabs">
- {{#each .tabs}}{{#unless .right}}{{>tab}}{{/unless}}{{/each}}
- </div>
- <div class="right-tabs">
- {{#each .tabs}}{{#if .right}}{{>tab}}{{/if}}{{/each}}
- </div>
- <div class="selection-indicator" style-left="{{.selectedLeft}}px" {{#if .selectedRight !== undefined}}style-right="{{.selectedRight}}px"{{/if}} />
- </div>
- </div>
- <div class-content-window
- {{#if .transition === 'fade'}}
- style-opacity="{{opacity}}"
- class-trans-fade
- {{elseif .transition === 'slide'}}
- class-trans-slide
- {{/if}}
- >
- <div class-contents style-left="{{.selectedContent * -100}}%">
- {{#each .tabs}}{{>tab-content}}{{/each}}
- </div>
- </div>
- </div>
- <template id="tab">
- <div
- class-tab
- {{#unless .button}}class-selected="~/selected === @index"{{/unless}}
- {{#if .disabled}}class-disabled
- {{elseif !.button}}on-click=['select', @index]{{/if}}
- as-registered="@index"
- {{#if .extraTab}}{{yield .extraTab}}{{/if}}
- >
- {{#if typeof .title === 'string'}}{{title}}{{elseif .title}}{{yield .title}}{{/if}}
- {{#if .closable && !.button}}<div class-close on-click=['close', @index]>×</div>{{/if}}
- </div>
- </template>
- <template id="tab-content">
- {{#if !.button}}
- <div
- class-tab
- class-selected="~/selectedContent === @index"
- {{#if .extra}}{{yield .extra}}{{/if}}
- >
- {{yield .template}}
- </div>
- {{else}}<div class-tab />
- {{/if}}
- </template>
- <script>
- import Ractive from 'ractive';
- let resizer;
- const instances = [];
- class Tabs extends Ractive {
- constructor(opts) {
- super(opts);
- }
- updateIndicator() {
- const node = this._tabs[this.get('selected')];
- if (node) {
- const start = this.get('selectedLeft');
- if (start === undefined) {
- this.set({
- selectedLeft: node.offsetLeft,
- selectedRight: node.offsetParent.clientWidth - (node.offsetLeft + node.offsetWidth)
- });
- } else {
- const max = node.offsetParent.clientWidth;
- const left = node.offsetLeft, width = node.clientWidth, right = max - left - width;
- this.set({
- direction: left < start ? 'left' : 'right',
- selectedLeft: left,
- selectedRight: right
- });
- }
- } else {
- this.set({
- selectedLeft: 0,
- selectedRight: this.find('.tabs').offsetWidth
- });
- }
- }
- }
- const tabAttrs = ['closable', 'disabled', 'title', 'right', 'button'];
- Ractive.extendWith(Tabs, {
- template: $TEMPLATE,
- cssId: 'tabs',
- noCssTransform: true,
- css: $CSS,
- attributes: ['transition'],
- data() {
- return {
- tabs: [],
- rightTabs: [],
- selected: 0,
- selectedContent: 0,
- opacity: 1
- }
- },
- on: {
- config() {
- const tpl = this.partials.content;
- if (tpl) {
- const tabs = tpl.filter(n => n.e === 'tab').map(t => {
- const tab = {
- template: { t: t.f }
- };
- const extra = [];
- const extraTab = [];
- t.m.forEach(a => {
- if (a.t === 13 && ~tabAttrs.indexOf(a.n)) tab[a.n] = a.f === 0 ? true : typeof a.f === 'string' ? a.f : { t: a.f };
- else if (a.t === 70) extraTab.push(a);
- else extra.push(a);
- });
- if (extra.length) tab.extra = { t: extra };
- if (extraTab.length) tab.extraTab = { t: extraTab };
- return tab;
- });
- tabs.unshift('tabs');
- this.push.apply(this, tabs);
- if (!resizer && typeof window !== undefined) {
- resizer = true;
- window.addEventListener('resize', () => {
- instances.forEach(i => i.updateIndicator());
- });
- }
- instances.push(this);
- }
- },
- select(ctx, idx) {
- const current = this.get('selected');
- const prs = [];
- const node = this.find('.contents');
- const trans = this.get('transition');
- if (current !== idx) {
- if (trans === 'fade') {
- this.set({
- opacity: 0,
- selected: idx
- });
- this.updateIndicator();
- setTimeout(() => {
- this.set({
- selectedContent: idx,
- opacity: 1
- });
- }, 300);
- } else if (trans === 'slide') {
- this.set('selected', idx);
- this.set('selectedContent', idx);
- this.updateIndicator();
- } else {
- this.set({
- selected: idx,
- selectedContent: idx
- });
- this.updateIndicator();
- }
- }
- },
- close(ctx, idx) {
- const tab = this.getContext(this._tabs[idx]);
- let ok = true;
- if (tab.element.events.find(e => e.events.find(e => e.name === 'close'))) {
- ok = tab.raise('close');
- }
- if (ok) this.splice('tabs', idx, 1);
- return false;
- },
- teardown() {
- instances.splice(instances.indexOf(this), 1);
- }
- },
- decorators: {
- registered(node, idx) {
- const me = this;
- if (!this._tabs) this._tabs = [];
- this._tabs[idx] = node;
- this.updateIndicator();
- return {
- teardown() {},
- invalidate() {
- me.updateIndicator();
- },
- update(idx) {
- me._tabs[idx] = node;
- setTimeout(() => me.updateIndicator());
- }
- };
- }
- }
- });
- export default Tabs;
- </script>
- <style>
- .rtabs {
- position: relative;
- }
- .rtabs > .tab-window {
- overflow-y: hidden;
- overflow-x: auto;
- box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14),
- 0 1px 5px 0 rgba(0, 0, 0, 0.12),
- 0 3px 1px -2px rgba(0, 0, 0, 0.2);
- }
- .rtabs > .tab-window .tabs {
- display: table;
- position: relative;
- min-width: 100%;
- overflow-x: auto;
- overflow-y: hidden;
- white-space: nowrap;
- }
- .rtabs > .tab-window .tab {
- display: inline-block;
- box-sizing: border-box;
- padding: 0.5em 1em;
- height: 2.5em;
- cursor: pointer;
- opacity: 0.7;
- transition: opacity 0.2s ease-in-out;
- user-select: none;
- }
- .rtabs > .tab-window .tab:hover {
- opacity: 1;
- }
- .rtabs > .tab-window .tab.selected {
- opacity: 1;
- }
- .rtabs > .tab-window .tab.disabled {
- opacity: 0.4;
- }
- .rtabs > .tab-window .right-tabs {
- text-align: right;
- display: table-cell;
- }
- .rtabs > .tab-window .left-tabs {
- text-align: left;
- display: table-cell;
- }
- .rtabs > .tab-window .tab > .close {
- display: inline-block;
- margin-right: -0.5em;
- font-weight: 700;
- }
- .rtabs > .tab-window .selection-indicator {
- position: absolute;
- bottom: 0;
- height: 2px;
- background-color: blue;
- }
- .rtabs > .tab-window.going-left .selection-indicator {
- transition: left 0.2s ease-in-out, right 0.2s ease-in-out 0.1s;
- }
- .rtabs > .tab-window.going-right .selection-indicator {
- transition: left 0.2s ease-in-out 0.1s, right 0.2s ease-in-out;
- }
- .rtabs > .content-window {
- width: 100%;
- overflow: hidden;
- }
- .rtabs > .content-window > .contents {
- list-style: none;
- padding: 0;
- margin: 0;
- position: relative;
- white-space: nowrap;
- left: 0;
- }
- .rtabs > .content-window.trans-slide > .contents {
- transition: left 0.45s ease-in-out;
- }
- .rtabs > .content-window.trans-fade {
- transition: opacity 0.3s ease;
- }
- .rtabs > .content-window > .contents > .tab {
- display: inline-block;
- width: 100%;
- vertical-align: top;
- white-space: initial;
- transition: opacity 0.1s ease-in-out;
- }
- </style>
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement