@hashicorp/design-system-components
Version:
Helios Design System Components
124 lines (121 loc) • 8.01 kB
JavaScript
import Component from '@glimmer/component';
import { tracked } from '@glimmer/tracking';
import { schedule } from '@ember/runloop';
import { modifier } from 'ember-modifier';
import { concat, hash } from '@ember/helper';
import { guidFor } from '@ember/object/internals';
import { eq } from 'ember-truth-helpers';
import style from 'ember-style-modifier';
import { registerAriaDescriptionElement, unregisterAriaDescriptionElement, ariaDescribedBy } from '../../../../utils/hds-aria-described-by.js';
import HdsAlert from '../../alert/index.js';
import HdsFormError from '../error/index.js';
import HdsFormHelperText from '../helper-text/index.js';
import HdsFormKeyValueInputsDeleteRowButton from './delete-row-button.js';
import HdsFormKeyValueInputsField from './field.js';
import HdsFormKeyValueInputsGeneric from './generic.js';
import HdsFormLegend from '../legend/index.js';
import HdsYield from '../../yield/index.js';
import HdsFormKeyValueInputsAddRowButton from './add-row-button.js';
import { precompileTemplate } from '@ember/template-compilation';
import { setComponentTemplate } from '@ember/component';
import { c, g, i } from 'decorator-transforms/runtime';
/**
* Copyright IBM Corp. 2021, 2025
* SPDX-License-Identifier: MPL-2.0
*/
const KEY_VALUE_INPUTS_FIELD_SELECTOR = '.hds-form-key-value-inputs__field';
const KEY_VALUE_INPUTS_GENERIC_SELECTOR = '.hds-form-key-value-inputs__generic-container';
const KEY_VALUE_INPUTS_FIRST_ROW_SELECTOR = '.hds-form-key-value-inputs__row--first';
const KEY_VALUE_INPUTS_DELETE_ROW_CONTAINER_SELECTOR = '.hds-form-key-value-inputs__delete-row-button-container';
const HdsFormKeyValueInputs = c(class HdsFormKeyValueInputs extends Component {
_element;
static {
g(this.prototype, "_gridTemplateColumns", [tracked], function () {
return '';
});
}
#_gridTemplateColumns = (i(this, "_gridTemplateColumns"), void 0);
// this is not a specific DOM id, but a value that is used to "glue" together
// different fieldsset-related elements (legend, helper text, error) with the fieldset itself
get glueId() {
return guidFor(this);
}
_setUpColumn = () => {
// eslint-disable-next-line ember/no-runloop
schedule('afterRender', () => {
this._updateColumns();
});
};
_removeColumn = () => {
// eslint-disable-next-line ember/no-runloop
schedule('afterRender', () => {
this._updateColumns();
});
};
appendDescriptor = element => {
registerAriaDescriptionElement(this, element);
};
removeDescriptor = element => {
unregisterAriaDescriptionElement(this, element);
};
_setUpKeyValueInputs = modifier(element => {
this._element = element;
});
// Update the column array based on how they are ordered in the DOM
_updateColumns = () => {
const columns = this._element.querySelector(KEY_VALUE_INPUTS_FIRST_ROW_SELECTOR)?.querySelectorAll(`${KEY_VALUE_INPUTS_FIELD_SELECTOR}, ${KEY_VALUE_INPUTS_GENERIC_SELECTOR}, ${KEY_VALUE_INPUTS_DELETE_ROW_CONTAINER_SELECTOR}`);
let updatedGridTemplateColumns = '';
columns?.forEach((column, index) => {
const columnElement = column;
// FIELD
if (
// do substring to remove the leading dot from the class selector
column.classList.contains(KEY_VALUE_INPUTS_FIELD_SELECTOR.substring(1))) {
if (columnElement.dataset['width']) {
updatedGridTemplateColumns += `${columnElement.dataset['width']} `;
} else {
updatedGridTemplateColumns += '1fr ';
}
}
// GENERIC
if (
// do substring to remove the leading dot from the class selector
column.classList.contains(KEY_VALUE_INPUTS_GENERIC_SELECTOR.substring(1))) {
updatedGridTemplateColumns += 'auto ';
// Set grid-column so generic content appears in the correct column when grid-row is set; otherwise, browsers default it to the first column.
columnElement.style.setProperty('--hds-key-value-inputs-column-index', `${index + 1}`);
}
// DELETE BUTTON
if (column.classList.contains(KEY_VALUE_INPUTS_DELETE_ROW_CONTAINER_SELECTOR.substring(1))) {
// Set grid-column so generic content appears in the correct column when grid-row is set; otherwise, browsers default it to the first column.
columnElement.style.setProperty('--hds-key-value-inputs-column-index', `${index + 1}`);
}
});
// we always set aside the space for the delete button (it's always the last element)
// even when it's not rendered, to avoid layout shifts when moving to/from an empty state
updatedGridTemplateColumns += '2.25rem ';
this._gridTemplateColumns = updatedGridTemplateColumns;
};
static {
setComponentTemplate(precompileTemplate("<fieldset class=\"hds-form-key-value-inputs\" ...attributes {{style --hds-key-value-inputs-columns=this._gridTemplateColumns}} {{!-- need to set aria-labelledby because the legend is not a direct descendant of the fieldset --}} aria-labelledby=\"legend-{{this.glueId}}\" {{!-- @glint-expect-error --}} aria-describedby={{this.ariaDescribedBy}} tabindex=\"-1\" {{this._setUpKeyValueInputs}}>\n <div class=\"hds-form-key-value-inputs__header\">\n {{yield (hash Legend=(component HdsFormLegend contextualClass=\"hds-form-key-value-inputs__legend\" id=(concat \"legend-\" this.glueId) isOptional=@isOptional isRequired=@isRequired) HelperText=(component HdsFormHelperText contextualClass=\"hds-form-key-value-inputs__helper-text\" controlId=this.glueId onInsert=this.appendDescriptor) Generic=HdsYield) to=\"header\"}}\n </div>\n\n {{#if (eq @data.length 0)}}\n <div class=\"hds-form-key-value-inputs__row hds-form-key-value-inputs__row--first\">\n {{yield (hash Field=(component HdsFormKeyValueInputsField onInsert=this._setUpColumn onRemove=this._removeColumn rowIndex=0) Generic=(component HdsFormKeyValueInputsGeneric onInsert=this._setUpColumn onRemove=this._removeColumn) rowData=undefined rowIndex=0) to=\"row\"}}\n\n {{!-- leaving as a separate yield to keep the delete row button at the end of the row --}}\n {{yield (hash DeleteRowButton=(component HdsFormKeyValueInputsDeleteRowButton returnFocusTo=this._element onInsert=this._setUpColumn onRemove=this._removeColumn rowData=undefined rowIndex=0)) to=\"row\"}}\n </div>\n {{/if}}\n\n {{#each @data as |item index|}}\n <div class=\"hds-form-key-value-inputs__row\n {{if (eq index 0) \"hds-form-key-value-inputs__row--first\"}}\">\n {{yield (hash Field=(component HdsFormKeyValueInputsField onInsert=this._setUpColumn onRemove=this._removeColumn rowIndex=index) Generic=(component HdsFormKeyValueInputsGeneric onInsert=this._setUpColumn onRemove=this._removeColumn) rowData=item rowIndex=index) to=\"row\"}}\n\n {{!-- leaving as a separate yield to keep the delete row button at the end of the row --}}\n {{yield (hash DeleteRowButton=(component HdsFormKeyValueInputsDeleteRowButton onInsert=this._setUpColumn onRemove=this._removeColumn returnFocusTo=this._element rowData=item rowIndex=index) rowData=item rowIndex=index) to=\"row\"}}\n </div>\n {{/each}}\n\n <div class=\"hds-form-key-value-inputs__footer\">\n {{yield (hash Alert=(component HdsAlert color=\"neutral\" type=\"compact\") AddRowButton=HdsFormKeyValueInputsAddRowButton Error=(component HdsFormError contextualClass=\"hds-form-key-value-inputs__error\" controlId=this.glueId onInsert=this.appendDescriptor onRemove=this.removeDescriptor)) to=\"footer\"}}\n </div>\n</fieldset>", {
strictMode: true,
scope: () => ({
style,
hash,
HdsFormLegend,
concat,
HdsFormHelperText,
HdsYield,
eq,
HdsFormKeyValueInputsField,
HdsFormKeyValueInputsGeneric,
HdsFormKeyValueInputsDeleteRowButton,
HdsAlert,
HdsFormKeyValueInputsAddRowButton,
HdsFormError
})
}), this);
}
}, [ariaDescribedBy]);
export { HdsFormKeyValueInputs as default };
//# sourceMappingURL=index.js.map