framework7
Version:
Full featured mobile HTML framework for building iOS & Android apps
172 lines • 6.43 kB
JavaScript
import $ from '../../shared/dom7.js';
import { bindMethods, getTranslate, nextFrame } from '../../shared/utils.js';
const Fab = {
morphOpen(fabEl, targetEl) {
const app = this;
const $fabEl = $(fabEl);
const $targetEl = $(targetEl);
if ($targetEl.length === 0) return;
$targetEl.transition(0).addClass('fab-morph-target-visible');
const target = {
width: $targetEl[0].offsetWidth,
height: $targetEl[0].offsetHeight,
offset: $targetEl.offset(),
borderRadius: $targetEl.css('border-radius'),
zIndex: $targetEl.css('z-index')
};
const fab = {
width: $fabEl[0].offsetWidth,
height: $fabEl[0].offsetHeight,
offset: $fabEl.offset(),
translateX: getTranslate($fabEl[0], 'x'),
translateY: getTranslate($fabEl[0], 'y')
};
$fabEl[0].f7FabMorphData = {
$targetEl,
target,
fab
};
const diffX = fab.offset.left + fab.width / 2 - (target.offset.left + target.width / 2) - fab.translateX;
const diffY = fab.offset.top + fab.height / 2 - (target.offset.top + target.height / 2) - fab.translateY;
const scaleX = target.width / fab.width;
const scaleY = target.height / fab.height;
let borderRadius = Math.ceil(parseInt(target.borderRadius, 10) / Math.max(scaleX, scaleY));
if (borderRadius > 0) borderRadius += 2;
$fabEl[0].f7FabMorphResizeHandler = function resizeHandler() {
$fabEl.transition(0).transform('');
$targetEl.transition(0);
target.width = $targetEl[0].offsetWidth;
target.height = $targetEl[0].offsetHeight;
target.offset = $targetEl.offset();
fab.offset = $fabEl.offset();
const diffXNew = fab.offset.left + fab.width / 2 - (target.offset.left + target.width / 2) - fab.translateX;
const diffYNew = fab.offset.top + fab.height / 2 - (target.offset.top + target.height / 2) - fab.translateY;
const scaleXNew = target.width / fab.width;
const scaleYNew = target.height / fab.height;
$fabEl.transform(`translate3d(${-diffXNew}px, ${-diffYNew}px, 0) scale(${scaleXNew}, ${scaleYNew})`);
};
$targetEl.css('opacity', 0).transform(`scale(${1 / scaleX}, ${1 / scaleY})`);
$fabEl.addClass('fab-opened').css('z-index', target.zIndex - 1).transform(`translate3d(${-diffX}px, ${-diffY}px, 0)`);
$fabEl.transitionEnd(() => {
$targetEl.transition('');
nextFrame(() => {
$targetEl.css('opacity', 1).transform('scale(1,1)');
$fabEl.transform(`translate3d(${-diffX}px, ${-diffY}px, 0) scale(${scaleX}, ${scaleY})`).css('border-radius', `${borderRadius}px`).css('box-shadow', 'none').css('opacity', '0');
});
app.on('resize', $fabEl[0].f7FabMorphResizeHandler);
if ($targetEl.parents('.page-content').length > 0) {
$targetEl.parents('.page-content').on('scroll', $fabEl[0].f7FabMorphResizeHandler);
}
});
},
morphClose(fabEl) {
const app = this;
const $fabEl = $(fabEl);
const morphData = $fabEl[0].f7FabMorphData;
if (!morphData) return;
const {
$targetEl,
target,
fab
} = morphData;
if ($targetEl.length === 0) return;
const diffX = fab.offset.left + fab.width / 2 - (target.offset.left + target.width / 2) - fab.translateX;
const diffY = fab.offset.top + fab.height / 2 - (target.offset.top + target.height / 2) - fab.translateY;
const scaleX = target.width / fab.width;
const scaleY = target.height / fab.height;
app.off('resize', $fabEl[0].f7FabMorphResizeHandler);
if ($targetEl.parents('.page-content').length > 0) {
$targetEl.parents('.page-content').off('scroll', $fabEl[0].f7FabMorphResizeHandler);
}
$targetEl.css('opacity', 0).transform(`scale(${1 / scaleX}, ${1 / scaleY})`);
$fabEl.transition('').css('box-shadow', '').css('border-radius', '').css('opacity', '1').transform(`translate3d(${-diffX}px, ${-diffY}px, 0)`);
$fabEl.transitionEnd(() => {
$fabEl.css('z-index', '').removeClass('fab-opened').transform('');
nextFrame(() => {
$fabEl.transitionEnd(() => {
$targetEl.removeClass('fab-morph-target-visible').css('opacity', '').transform('').transition('');
});
});
});
},
open(fabEl, targetEl) {
const app = this;
const $fabEl = $(fabEl).eq(0);
const $buttonsEl = $fabEl.find('.fab-buttons');
if (!$fabEl.length) return;
if ($fabEl.hasClass('fab-opened')) return;
if (!$buttonsEl.length && !$fabEl.hasClass('fab-morph')) return;
if (app.fab.openedEl) {
if (app.fab.openedEl === $fabEl[0]) return;
app.fab.close(app.fab.openedEl);
}
app.fab.openedEl = $fabEl[0];
if ($fabEl.hasClass('fab-morph')) {
app.fab.morphOpen($fabEl, targetEl || $fabEl.attr('data-morph-to'));
} else {
$fabEl.addClass('fab-opened');
}
$fabEl.siblings('.fab-backdrop').addClass('backdrop-in');
$fabEl.trigger('fab:open');
},
close(fabEl) {
if (fabEl === void 0) {
fabEl = '.fab-opened';
}
const app = this;
const $fabEl = $(fabEl).eq(0);
const $buttonsEl = $fabEl.find('.fab-buttons');
if (!$fabEl.length) return;
if (!$fabEl.hasClass('fab-opened')) return;
if (!$buttonsEl.length && !$fabEl.hasClass('fab-morph')) return;
app.fab.openedEl = null;
if ($fabEl.hasClass('fab-morph')) {
app.fab.morphClose($fabEl);
} else {
$fabEl.removeClass('fab-opened');
}
$fabEl.siblings('.fab-backdrop').removeClass('backdrop-in');
$fabEl.trigger('fab:close');
},
toggle(fabEl) {
const app = this;
const $fabEl = $(fabEl);
if (!$fabEl.hasClass('fab-opened')) app.fab.open(fabEl);else app.fab.close(fabEl);
}
};
export default {
name: 'fab',
create() {
const app = this;
bindMethods(app, {
fab: {
openedEl: null,
...Fab
}
});
},
clicks: {
'.fab > a': function open($clickedEl) {
const app = this;
app.fab.toggle($clickedEl.parents('.fab'));
},
'.fab-open': function open($clickedEl, data) {
if (data === void 0) {
data = {};
}
const app = this;
app.fab.open(data.fab);
},
'.fab-close': function close($clickedEl, data) {
if (data === void 0) {
data = {};
}
const app = this;
app.fab.close(data.fab);
},
'.fab-backdrop': function close() {
const app = this;
app.fab.close();
}
}
};