<div id="large-input-46993-76096" class="large-input has-overlay-link">
    <label for="large-input-46993-76096-input" class="large-input__label">Suchbegriff</label>

    <input class="large-input__input" id="large-input-46993-76096-input" name="search" type="text" data-autocomplete="https://jsonplaceholder.typicode.com/posts?q=" autocomplete="off">
</div>
{% set id = id ??? html_id('large-input') -%}

<div {{ html_attributes({
  id: id ?? false,
  class: {
    'large-input': true,
    'large-input--frameless': frameless ?? false,
    'has-overlay-link': true,
  },
}, attrs ?? {}) }}>
  <label for="{{ 'input' | namespaceInputId(id) }}" class="large-input__label">
    {{- label -}}
  </label>

  <input {{ html_attributes({
    class: 'large-input__input',
    id: 'input' | namespaceInputId(id),
    name: name,
    type: type ??? 'text',
    required: required ?? false,
    value: value ?? null,
    'data-autocomplete': autocomplete ?? false,
    autocomplete: autocomplete|default ? 'off',
  }, inputAttrs ?? {}) }}>
</div>
{
  "name": "search",
  "label": "Suchbegriff",
  "autocomplete": "https://jsonplaceholder.typicode.com/posts?q="
}
  • Content:
    :root {
      --large-input-background-color: var(--color-white);
      --large-input-border-color: var(--color-midnight);
      --large-input-border-width: 2px;
      --large-input-color: var(--color-midnight);
      --large-input-font-size: 2.4rem;
      --large-input-height: 8.4rem;
      --large-input-label-color: var(--color-grey-dark);
      --large-input-label-font-size: 0.55em;
      --large-input-padding-block: 1.6rem;
      --large-input-padding-inline: 2.4rem;
      --large-input-cancel-button-size: 1.8rem;
      --large-input-highlight-color: var(--color-orange);
    }
    
    .large-input {
      background-color: var(--large-input-background-color);
      box-shadow: inset 0 0 0 var(--large-input-border-width) var(--large-input-border-color);
      color: var(--large-input-color);
      font-size: var(--large-input-font-size);
      position: relative;
      user-select: none;
    }
    
    .large-input--frameless {
      --large-input-border-width: 0;
    }
    
    .large-input__label {
      color: var(--large-input-label-color);
      display: block;
      font-size: var(--large-input-label-font-size);
      inset-block-start: var(--large-input-padding-block);
      inset-inline-start: var(--large-input-padding-inline);
      padding-inline: 0;
      position: absolute;
    }
    
    .large-input__input {
      --focus-outline-offset: 0;
      --selection-background-color: var(--large-input-color);
      --selection-foreground-color: var(--large-input-background-color);
    
      background-color: transparent;
      block-size: var(--large-input-height);
      display: block;
      font-size: inherit;
      font-weight: var(--font-weight-bold);
      inline-size: 100%;
      padding-block-end: var(--large-input-padding-block);
      padding-block-start: calc(var(--large-input-padding-block) + var(--large-input-label-font-size) + 1rem);
      padding-inline: var(--large-input-padding-inline);
    
      .large-input--frameless & {
        --focus-outline-offset: 3px;
      }
    
      &::-webkit-search-cancel-button {
        display: none;
      }
    }
    
    .large-input__autocomplete {
      animation: opacity var(--duration-default);
      background-color: var(--large-input-background-color);
      border: var(--large-input-border-width) solid var(--large-input-border-color);
      border-block-start: 0;
      display: grid;
      font-size: var(--large-input-font-size);
      gap: 2rem;
      padding-block-end: calc(var(--large-input-padding-block) * 2);
      padding-block-start: var(--large-input-padding-block);
      padding-inline: var(--large-input-padding-inline);
      transform: translateY(-1rem);
      z-index: z-index('dropdown');
    
      &[hidden] {
        display: none;
      }
    }
    
    .large-input__autocomplete-option {
      --large-input-highlight-opacity: 0;
    
      position: relative;
    
      &:is([aria-selected='true']) {
        --large-input-highlight-opacity: 1;
      }
    
      &::before {
        background-color: var(--large-input-highlight-color);
        border-block: 0.25em solid var(--large-input-highlight-color);
        border-inline: var(--large-input-padding-inline) solid var(--large-input-highlight-color);
        content: '';
        inset-block: -0.25em;
        inset-inline: calc(var(--large-input-padding-inline) * -1);
        opacity: var(--large-input-highlight-opacity);
        pointer-events: none;
        position: absolute;
        transition-duration: 0.2s;
        transition-property: opacity;
        z-index: -1;
      }
    }
    
    .large-input__autocomplete-option--empty {
      color: var(--color-grey-dark);
    }
    
  • URL: /components/raw/large-input/large-input.scss
  • Filesystem Path: src/components/1-atoms/large-input/large-input.scss
  • Size: 3.3 KB
  • Content:
    import autocomplete, { type AutocompleteItem } from 'autocompleter';
    
    type AutocompleteApiItem = {
      title: string;
    };
    
    document
      .querySelectorAll<HTMLInputElement>('input[data-autocomplete]')
      .forEach(($input) => {
        autocomplete<AutocompleteApiItem & AutocompleteItem>({
          className: 'large-input__autocomplete',
          disableAutoSelect: true,
          input: $input,
          minLength: 3,
          emptyMsg: 'Keine Ergebnisse gefunden',
          preventSubmit: 1,
          render(item) {
            const $item = document.createElement('div');
            $item.textContent = item.title;
    
            return $item;
          },
          async fetch(text, update) {
            // nosemgrep: nodejs_scan.javascript-ssrf-rule-node_ssrf
            const results = await fetch(`${$input.dataset.autocomplete}${text}`, {
              method: 'GET',
              credentials: 'include',
              headers: {
                Accept: 'application/json',
              },
            });
    
            const items: AutocompleteApiItem[] = await results.json();
            update(items.slice(0, 5));
          },
          onSelect(item) {
            $input.value = item.title;
          },
          customize(_, __, $container) {
            $container.classList.remove('autocomplete');
    
            $container.querySelectorAll('[role="option"]').forEach(($option) => {
              $option.classList.remove('selected');
              $option.classList.add('large-input__autocomplete-option');
            });
    
            $container.querySelectorAll('.empty').forEach(($empty) => {
              $empty.classList.remove('empty');
              $empty.classList.add('large-input__autocomplete-option');
              $empty.classList.add('large-input__autocomplete-option--empty');
            });
          },
        });
      });
    
  • URL: /components/raw/large-input/large-input.ts
  • Filesystem Path: src/components/1-atoms/large-input/large-input.ts
  • Size: 1.7 KB

No notes defined.