@taiga-ui/cdk
Version:
Base library for creating Angular components and applications using Taiga UI principles regarding of actual visual appearance
247 lines • 13.9 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.migrateComboBox = migrateComboBox;
const insert_todo_1 = require("../../../../utils/insert-todo");
const elements_1 = require("../../../../utils/templates/elements");
const template_resource_1 = require("../../../../utils/templates/template-resource");
const control_state_attrs_1 = require("../../../utils/templates/control-state-attrs");
const replace_tag_1 = require("../../../utils/templates/replace-tag");
const DOCS_LINK = 'https://taiga-ui.dev/components/combo-box';
const CONTROL_ATTR_NAMES = [
'formControlName',
'[formControl]',
'formControl',
'[(ngModel)]',
'[ngModel]',
'ngModel',
];
const CONTROL_ATTRS = new Set(CONTROL_ATTR_NAMES.map((name) => name.toLowerCase()));
const INPUT_ATTRS = new Set(['[strictMatcher]'.toLowerCase(), '[strict]']);
const REMOVE_ATTRS = new Set([
'[tuiTextfieldLabelOutside]'.toLowerCase(),
'tuiTextfieldLabelOutside'.toLowerCase(),
]);
function migrateComboBox({ resource, recorder, fileSystem, }) {
const template = (0, template_resource_1.getTemplateFromTemplateResource)(resource, fileSystem);
const templateOffset = (0, template_resource_1.getTemplateOffset)(resource);
const elements = (0, elements_1.findElementsByTagName)(template, 'tui-combo-box');
elements.forEach((element) => {
var _a, _b;
const sourceCodeLocation = element.sourceCodeLocation;
const controlAttrs = element.attrs.filter((attr) => CONTROL_ATTRS.has(attr.name.toLowerCase()));
const inputAttrs = element.attrs.filter((attr) => INPUT_ATTRS.has(attr.name.toLowerCase()));
const removeAttrs = element.attrs.filter((attr) => REMOVE_ATTRS.has(attr.name.toLowerCase()));
const controlStateAttrs = (0, control_state_attrs_1.getControlStateAttrs)(element);
const labelOutsideAttr = removeAttrs.find((attr) => REMOVE_ATTRS.has(attr.name.toLowerCase()));
const searchAttr = element.attrs.find((attr) => attr.name.toLowerCase() === '[search]');
const searchChangeAttr = element.attrs.find((attr) => attr.name.toLowerCase() === '(searchChange)'.toLowerCase());
const valueContentAttr = element.attrs.find((attr) => attr.name.toLowerCase() === '[valueContent]'.toLowerCase());
for (const attr of [...controlAttrs, ...inputAttrs, ...removeAttrs]) {
removeAttr(recorder, templateOffset, element, attr.name, template);
}
(0, control_state_attrs_1.removeControlStateAttrs)(recorder, templateOffset, element, template, controlStateAttrs);
if (searchAttr) {
removeAttr(recorder, templateOffset, element, searchAttr.name, template);
}
if (searchChangeAttr) {
removeAttr(recorder, templateOffset, element, searchChangeAttr.name, template);
}
const addAttributes = [];
if (valueContentAttr) {
removeAttr(recorder, templateOffset, element, '[valueContent]', template);
addAttributes.push('#textfieldRef', `[content]="textfieldRef.focused() ? '' : ${valueContentAttr.value}"`);
}
(0, replace_tag_1.replaceTag)(recorder, sourceCodeLocation, 'tui-combo-box', 'tui-textfield', template, templateOffset, addAttributes);
if (searchAttr || searchChangeAttr) {
const searchTodo = [
`<!-- ${insert_todo_1.TODO_MARK} tui-combo-box migration (see ${DOCS_LINK}):`,
' - [search] / (searchChange): use native (input) event on <input tuiComboBox>',
'-->\n',
].join('\n');
const insertAt = ((_a = sourceCodeLocation === null || sourceCodeLocation === void 0 ? void 0 : sourceCodeLocation.startOffset) !== null && _a !== void 0 ? _a : 0) + templateOffset;
recorder.insertLeft(insertAt, searchTodo);
}
const searchHandler = searchChangeAttr
? ` (input)="${searchChangeAttr.value.replaceAll('$event', '$event.target.value')}"`
: '';
const inputs = element.childNodes.filter((node) => node.nodeName === 'input');
const isBinding = (_b = labelOutsideAttr === null || labelOutsideAttr === void 0 ? void 0 : labelOutsideAttr.name.startsWith('[')) !== null && _b !== void 0 ? _b : false;
const isLabelOutsideTrue = (labelOutsideAttr === null || labelOutsideAttr === void 0 ? void 0 : labelOutsideAttr.value) === 'true' ||
(!!labelOutsideAttr && !isBinding && labelOutsideAttr.value === '');
const isLabelOutsideDynamic = !!labelOutsideAttr &&
!isLabelOutsideTrue &&
labelOutsideAttr.value !== 'false';
if (inputs.length) {
handleExistingInput({
inputs,
recorder,
templateOffset,
template,
controlAttrs,
inputAttrs,
controlStateAttrs,
searchHandler,
placeholder: isLabelOutsideTrue ? getPlaceholderText(element) : '',
});
if (!labelOutsideAttr || labelOutsideAttr.value === 'false') {
wrapTextInLabel(recorder, templateOffset, element);
}
else if (isLabelOutsideTrue) {
removeTextNode(recorder, templateOffset, element);
}
else if (isLabelOutsideDynamic) {
addLabelOutsideTodo(recorder, templateOffset, element, template);
}
}
else {
if (!labelOutsideAttr || labelOutsideAttr.value === 'false') {
wrapTextInLabel(recorder, templateOffset, element);
}
else if (isLabelOutsideDynamic) {
addLabelOutsideTodo(recorder, templateOffset, element, template);
}
handleGeneratedInput({
element,
recorder,
templateOffset,
controlAttrs,
inputAttrs,
controlStateAttrs,
searchHandler,
sourceCodeLocation,
isLabelOutsideTrue,
});
}
});
}
function handleExistingInput({ inputs, recorder, templateOffset, template, controlAttrs, inputAttrs, controlStateAttrs, searchHandler, placeholder, }) {
inputs.forEach((input) => {
var _a, _b, _c, _d, _e, _f;
const legacyAttr = input.attrs.find((attr) => /^tuitextfieldlegacy$/i.test(attr.name));
if (legacyAttr) {
const { startOffset = 0, endOffset = 0 } = (_c = (_b = (_a = input.sourceCodeLocation) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b[legacyAttr.name]) !== null && _c !== void 0 ? _c : {};
const lineStart = template.lastIndexOf('\n', startOffset) + 1;
const lineEnd = template.indexOf('\n', endOffset);
const lineText = lineEnd === -1 ? '' : template.slice(lineStart, lineEnd);
const attrText = template.slice(startOffset, endOffset);
if (lineText.trim() === attrText.trim() && lineEnd !== -1) {
recorder.remove(templateOffset + lineStart, lineEnd - lineStart + 1);
}
else {
recorder.remove(templateOffset + startOffset, endOffset - startOffset);
}
}
const insertOffset = ((_f = (_e = (_d = input.sourceCodeLocation) === null || _d === void 0 ? void 0 : _d.startTag) === null || _e === void 0 ? void 0 : _e.startOffset) !== null && _f !== void 0 ? _f : 0) + '<input'.length;
const formAttrs = formatControlAttrs(controlAttrs);
const inputAttrStr = formatInputAttrs(inputAttrs);
const placeholderAttr = placeholder ? ` placeholder="${placeholder}"` : '';
const controlStateStr = (0, control_state_attrs_1.stringifyControlStateAttrs)(controlStateAttrs);
recorder.insertRight(templateOffset + insertOffset, ` tuiComboBox${formAttrs}${inputAttrStr}${searchHandler}${placeholderAttr}${controlStateStr}`);
});
}
function handleGeneratedInput({ element, recorder, templateOffset, controlAttrs, inputAttrs, controlStateAttrs, searchHandler, sourceCodeLocation, isLabelOutsideTrue, }) {
var _a, _b, _c, _d, _e, _f, _g, _h;
const formAttrs = formatControlAttrs(controlAttrs);
const inputAttrStr = formatInputAttrs(inputAttrs);
const controlStateStr = (0, control_state_attrs_1.stringifyControlStateAttrs)(controlStateAttrs);
const labelNode = findTextNode(element);
if (isLabelOutsideTrue && labelNode) {
const labelText = labelNode.value.trim();
const textStart = (_b = (_a = labelNode.sourceCodeLocation) === null || _a === void 0 ? void 0 : _a.startOffset) !== null && _b !== void 0 ? _b : 0;
const textEnd = (_d = (_c = labelNode.sourceCodeLocation) === null || _c === void 0 ? void 0 : _c.endOffset) !== null && _d !== void 0 ? _d : 0;
recorder.remove(templateOffset + textStart, textEnd - textStart);
recorder.insertRight(templateOffset + textStart, `\n<input tuiComboBox${formAttrs}${inputAttrStr}${searchHandler} placeholder="${labelText}"${controlStateStr} />\n`);
return;
}
const insertOffset = labelNode
? ((_f = (_e = labelNode.sourceCodeLocation) === null || _e === void 0 ? void 0 : _e.endOffset) !== null && _f !== void 0 ? _f : 0)
: ((_h = (_g = sourceCodeLocation === null || sourceCodeLocation === void 0 ? void 0 : sourceCodeLocation.endTag) === null || _g === void 0 ? void 0 : _g.startOffset) !== null && _h !== void 0 ? _h : 0);
recorder.insertRight(templateOffset + insertOffset, `\n<input tuiComboBox${formAttrs}${inputAttrStr}${searchHandler}${controlStateStr} />\n`);
}
function findTextNode(element) {
return element.childNodes.find((node) => node.nodeName === '#text' && !!node.value.trim());
}
function getPlaceholderText(element) {
var _a, _b;
return (_b = (_a = findTextNode(element)) === null || _a === void 0 ? void 0 : _a.value.trim()) !== null && _b !== void 0 ? _b : '';
}
function removeTextNode(recorder, templateOffset, element) {
var _a, _b, _c, _d;
const labelNode = findTextNode(element);
if (!labelNode) {
return;
}
const textStart = (_b = (_a = labelNode.sourceCodeLocation) === null || _a === void 0 ? void 0 : _a.startOffset) !== null && _b !== void 0 ? _b : 0;
const textEnd = (_d = (_c = labelNode.sourceCodeLocation) === null || _c === void 0 ? void 0 : _c.endOffset) !== null && _d !== void 0 ? _d : 0;
recorder.remove(templateOffset + textStart, textEnd - textStart);
}
function addLabelOutsideTodo(recorder, templateOffset, element, template) {
var _a, _b;
const elementStart = (_b = (_a = element.sourceCodeLocation) === null || _a === void 0 ? void 0 : _a.startOffset) !== null && _b !== void 0 ? _b : 0;
const lineStart = template.lastIndexOf('\n', elementStart - 1) + 1;
const indent = template.slice(lineStart, elementStart);
recorder.insertRight(templateOffset + elementStart, `<!-- ${insert_todo_1.TODO_MARK} [tuiTextfieldLabelOutside] is dynamic and cannot be migrated automatically. Use <label tuiLabel> inside <tui-textfield> for floating label or input[placeholder] for outside label -->\n${indent}`);
}
function wrapTextInLabel(recorder, templateOffset, element) {
var _a, _b, _c, _d;
const labelNode = findTextNode(element);
if (!labelNode) {
return;
}
const labelTextStart = ((_b = (_a = labelNode.sourceCodeLocation) === null || _a === void 0 ? void 0 : _a.startOffset) !== null && _b !== void 0 ? _b : 0) + templateOffset;
const labelTextEnd = ((_d = (_c = labelNode.sourceCodeLocation) === null || _c === void 0 ? void 0 : _c.endOffset) !== null && _d !== void 0 ? _d : 0) + templateOffset;
recorder.insertRight(labelTextStart, '\n<label tuiLabel>');
recorder.insertRight(labelTextEnd, '</label>\n');
}
function removeAttr(recorder, templateOffset, element, name, template) {
var _a, _b;
const attrLocation = (_b = (_a = element.sourceCodeLocation) === null || _a === void 0 ? void 0 : _a.attrs) === null || _b === void 0 ? void 0 : _b[name.toLowerCase()];
if (!attrLocation) {
return;
}
const lineStart = template.lastIndexOf('\n', attrLocation.startOffset) + 1;
const lineEnd = template.indexOf('\n', attrLocation.endOffset);
const attrText = template.slice(attrLocation.startOffset, attrLocation.endOffset);
const lineText = lineEnd === -1 ? '' : template.slice(lineStart, lineEnd);
if (lineText.trim() === attrText.trim() && lineEnd !== -1) {
recorder.remove(templateOffset + lineStart, lineEnd - lineStart + 1);
return;
}
recorder.remove(templateOffset + attrLocation.startOffset - 1, attrLocation.endOffset - attrLocation.startOffset + 1);
}
function formatControlAttrs(attrs) {
return attrs
.map(({ name, value }) => ` ${normalizeAttrName(name)}="${value}"`)
.join('');
}
function formatInputAttrs(attrs) {
return attrs
.map(({ name, value }) => {
const attrName = name.toLowerCase() === '[strictMatcher]'.toLowerCase()
? '[matcher]'
: normalizeAttrName(name);
return ` ${attrName}="${value}"`;
})
.join('');
}
function normalizeAttrName(name) {
switch (name.toLowerCase()) {
case '[(ngModel)]'.toLowerCase():
return '[(ngModel)]';
case '[formControl]'.toLowerCase():
return '[formControl]';
case '[ngModel]'.toLowerCase():
return '[ngModel]';
case 'formControl'.toLowerCase():
return 'formControl';
case 'formControlName'.toLowerCase():
return 'formControlName';
case 'ngModel'.toLowerCase():
return 'ngModel';
case '[strict]':
return '[strict]';
default:
return name;
}
}
//# sourceMappingURL=migrate-combo-box.js.map