diff --git a/.gitignore b/.gitignore index c73b705..d4287d9 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,7 @@ coverage_html # Log files and directories logs/ + +# Node.js dependencies +node_modules/ +package-lock.json diff --git a/.stylelintrc.json b/.stylelintrc.json new file mode 100644 index 0000000..40db42c --- /dev/null +++ b/.stylelintrc.json @@ -0,0 +1,3 @@ +{ + "extends": "stylelint-config-standard" +} diff --git a/apps/autocomplete/static/autocomplete/css/autocomplete.css b/apps/autocomplete/static/autocomplete/css/autocomplete.css index 6bcc0bb..42e1708 100644 --- a/apps/autocomplete/static/autocomplete/css/autocomplete.css +++ b/apps/autocomplete/static/autocomplete/css/autocomplete.css @@ -1,7 +1,7 @@ -.phac_aspc_form_autocomplete { +.phac-aspc-form-autocomplete { display: block; width: 100%; - padding: calc(.375rem - 2px) 2.25rem calc(0.375rem - 2px) 0.75rem; + padding: calc(0.375rem - 2px) 2.25rem calc(0.375rem - 2px) 0.75rem; -moz-padding-start: calc(0.75rem - 3px); font-weight: 400; line-height: 1.5; @@ -9,26 +9,26 @@ background-color: #fff; background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e"); background-repeat: no-repeat; - background-position: right .75rem center; + background-position: right 0.75rem center; background-size: 16px 12px; border: 1px solid #ced4da; - border-radius: .375rem; - transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out; + border-radius: 0.375rem; + transition: border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; appearance: none; min-height: 38px; position: relative; } -.phac_aspc_form_autocomplete_focus_ring.disabled .phac_aspc_form_autocomplete { +.phac-aspc-form-autocomplete-focus-ring.disabled .phac-aspc-form-autocomplete { background-color: #e9ecef; background-image: none; } -.phac_aspc_form_autocomplete * { +.phac-aspc-form-autocomplete * { box-sizing: border-box; } -.phac_aspc_form_autocomplete ul.ac_container { +.phac-aspc-form-autocomplete ul.ac-container { position: relative; overflow: hidden; margin: 0; @@ -39,18 +39,45 @@ flex-wrap: wrap; } -.phac_aspc_form_autocomplete ul.ac_container li { - list-style: none; +.phac-aspc-form-autocomplete ul.ac-container li { + list-style: none; +} + +.phac-aspc-form-autocomplete .more-results { + border-top: 1px dashed #ccc; +} + +.phac-aspc-form-autocomplete .more-results span { + white-space: nowrap; + display: block; + font-size: 0.8em; + opacity: 0.8; + padding: 10px 30px 0; +} + +.phac-aspc-form-autocomplete ul.ac-container li.search-indicator svg { + max-width: 25px; + max-height: 25px; +} + +.phac-aspc-form-autocomplete ul.ac-container li.search-indicator svg .magnify { + fill: #000; + animation: search 1s infinite ease; } -.phac_aspc_form_autocomplete ul.ac_container li.chip { +.phac-aspc-form-autocomplete ul.ac-container li.search-indicator svg .doc { + fill: #444; + animation: flyby 1s infinite ease; +} + +.phac-aspc-form-autocomplete ul.ac-container li.chip { position: relative; margin: 3px 5px 3px 0; padding: 3px 20px 3px 5px; border: 1px solid #aaa; max-width: 100%; border-radius: 3px; - background-color: #eeeeee; + background-color: #eee; background-image: linear-gradient(#f4f4f4 20%, #f0f0f0 50%, #e8e8e8 52%, #eee 100%); background-size: 100% 19px; background-repeat: repeat-x; @@ -61,41 +88,41 @@ cursor: default; } -.phac_aspc_form_autocomplete_focus_ring.disabled .phac_aspc_form_autocomplete ul.ac_container li.chip { - padding: 3px 5px 3px 5px; +.phac-aspc-form-autocomplete-focus-ring.disabled .phac-aspc-form-autocomplete ul.ac-container li.chip { + padding: 3px 5px; } -.phac_aspc_form_autocomplete ul.ac_container li.chip span { - word-wrap: break-word; +.phac-aspc-form-autocomplete ul.ac-container li.chip span { + overflow-wrap: break-word; } -.phac_aspc_form_autocomplete ul.ac_container li.chip a { +.phac-aspc-form-autocomplete ul.ac-container li.chip a { position: absolute; top: 4px; right: 3px; display: block; width: 12px; height: 12px; - font-size: 1px; + font-size: 1px; } -.phac_aspc_form_autocomplete ul.ac_container li.chip a svg { +.phac-aspc-form-autocomplete ul.ac-container li.chip a svg { user-select: none; cursor: pointer; font-size: 12px; - margin: -2.5px 0px 0 0px; + margin: -2.5px 0 0; top: 0; width: 1em; height: 1em; - fill: currentColor; - color: rgba(0, 0, 0, 0.26); + fill: currentcolor; + color: rgb(0 0 0 / 26%); } -.phac_aspc_form_autocomplete ul.ac_container li.chip a svg:hover { - color: rgba(0, 0, 0, 0.4); +.phac-aspc-form-autocomplete ul.ac-container li.chip a svg:hover { + color: rgb(0 0 0 / 40%); } -.phac_aspc_form_autocomplete ul.ac_container li.input { +.phac-aspc-form-autocomplete ul.ac-container li.input { margin: 0; padding: 0; min-width: 10px; @@ -106,7 +133,7 @@ line-height: 14px; } -.phac_aspc_form_autocomplete ul.ac_container li input.textinput { +.phac-aspc-form-autocomplete ul.ac-container li input.textinput { margin: 1px 0; padding: 0; height: 25px; @@ -122,66 +149,43 @@ cursor: pointer; } -.phac_aspc_form_autocomplete .ac_required_input { +.phac-aspc-form-autocomplete .ac-required-input { opacity: 0; position: absolute; } -.phac_aspc_form_autocomplete ul.ac_container li.search-indicator svg{ - max-width:25px; - max-height:25px; -} -.phac_aspc_form_autocomplete ul.ac_container li.search-indicator svg .magnify { - fill:#000; - animation:search 1s infinite ease; -} -.phac_aspc_form_autocomplete ul.ac_container li.search-indicator svg .doc{ - fill:#444; - animation:flyby 1s infinite ease; -} - - @keyframes search { -0%{ - transform:translate(40px, 40px) scale(.6); -} -50%{ - transform:translate(20px, 20px) scale(.6); -} -100%{ - transform:translate(40px, 40px) scale(.6); -} + 0% { + transform: translate(40px, 40px) scale(0.6); + } + + 50% { + transform: translate(20px, 20px) scale(0.6); + } + + 100% { + transform: translate(40px, 40px) scale(0.6); + } } @keyframes flyby { -0%{ - transform:translate(-20px, 20px) scale(.2); - opacity:0 -} -50%{ - transform:translate(30px, 20px) scale(.5); - opacity:1 -} -100%{ - transform:translate(100px, 20px) scale(.2); - opacity:0 -} -} + 0% { + transform: translate(-20px, 20px) scale(0.2); + opacity: 0; + } -.phac_aspc_form_autocomplete .more-results { - border-top: 1px dashed #ccc; -} + 50% { + transform: translate(30px, 20px) scale(0.5); + opacity: 1; + } -.phac_aspc_form_autocomplete .more-results span { - white-space: nowrap; - display: block; - font-size: 0.8em; - opacity: 0.8; - padding: 10px 30px 0 30px; + 100% { + transform: translate(100px, 20px) scale(0.2); + opacity: 0; + } } - -.phac_aspc_form_autocomplete .results { +.phac-aspc-form-autocomplete .results { max-height: 240px; max-width: 100%; position: absolute; @@ -197,18 +201,18 @@ list-style: none; background-color: #fff; background-clip: padding-box; - border: 1px solid rgba(0, 0, 0, 0.175); + border: 1px solid rgb(0 0 0 / 17.5%); border-radius: 0.375rem; } -.phac_aspc_form_autocomplete .results.show { +.phac-aspc-form-autocomplete .results.show { display: block; } -.phac_aspc_form_autocomplete .results .item { +.phac-aspc-form-autocomplete .results .item { display: block; width: 100%; - padding: 2px 1rem 2px 1rem; + padding: 2px 1rem; clear: both; font-weight: 400; color: #212529; @@ -216,64 +220,65 @@ text-decoration: none; white-space: nowrap; background-color: transparent; - border: 0; + border: 0; } -.phac_aspc_form_autocomplete .results .item .highlight { +.phac-aspc-form-autocomplete .results .item .highlight { font-weight: 600; text-decoration: underline; } -.phac_aspc_form_autocomplete_focus_ring .live_info { - border: 0!important; - clip: rect(0 0 0 0)!important; - height: 1px!important; - margin: -1px!important; - overflow: hidden!important; - padding: 0!important; - position: absolute!important; - width: 1px!important; +.phac-aspc-form-autocomplete-focus-ring .live-info { + border: 0 !important; + clip-path: inset(50%) !important; + height: 1px !important; + margin: -1px !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + width: 1px !important; } -.phac_aspc_form_autocomplete_focus_ring.disabled { +.phac-aspc-form-autocomplete-focus-ring.disabled { cursor: inherit; } -.phac_aspc_form_autocomplete_focus_ring { +.phac-aspc-form-autocomplete-focus-ring { cursor: pointer; padding: 4px; } -.phac_aspc_form_autocomplete_focus_ring.active { +.phac-aspc-form-autocomplete-focus-ring.active { border: 2px solid #000; padding: 2px; } -.phac_aspc_form_autocomplete_focus_ring.active > div { + +.phac-aspc-form-autocomplete-focus-ring.active > div { color: #1e2125; background-color: #e9ecef; } -.phac_aspc_form_autocomplete .results .item.hasFocus, -.phac_aspc_form_autocomplete .results .item:hover { - color: #1e2125; - background-color: #e9ecef; +.phac-aspc-form-autocomplete .results .item.selected { + display: list-item; + color: #ccc; } -.phac_aspc_form_autocomplete .results .item.selected.hasFocus, -.phac_aspc_form_autocomplete .results .item.selected:hover { +.phac-aspc-form-autocomplete .results .item.has-focus, +.phac-aspc-form-autocomplete .results .item:hover { color: #1e2125; - background-color: #eca9a9; + background-color: #e9ecef; } -.phac_aspc_form_autocomplete .results .item.hasFocus { +.phac-aspc-form-autocomplete .results .item.has-focus { outline: 2px solid #000; } -.phac_aspc_form_autocomplete .results .item.selected { - display: list-item; - color: #ccc; +.phac-aspc-form-autocomplete .results .item.selected.has-focus, +.phac-aspc-form-autocomplete .results .item.selected:hover { + color: #1e2125; + background-color: #eca9a9; } -.phac_aspc_form_autocomplete li.input.ac-active { +.phac-aspc-form-autocomplete li.input.ac-active { min-width: 50px !important; } diff --git a/apps/autocomplete/static/autocomplete/js/autocomplete.js b/apps/autocomplete/static/autocomplete/js/autocomplete.js index 1750353..a60aa21 100644 --- a/apps/autocomplete/static/autocomplete/js/autocomplete.js +++ b/apps/autocomplete/static/autocomplete/js/autocomplete.js @@ -7,20 +7,20 @@ function phac_aspc_autocomplete_trigger_change(container_id) { } function phac_aspc_autocomplete_clear_focus(container, activate_ring) { - const hasFocus = container.querySelectorAll('.hasFocus'); - for (const el of hasFocus) { - el.classList.remove('hasFocus'); + const focusedElements = container.querySelectorAll('.has-focus'); + for (const el of focusedElements) { + el.classList.remove('has-focus'); } const el = container.querySelector('.textinput'); el.removeAttribute('aria-activedescendant'); if (activate_ring) { - container.closest('.phac_aspc_form_autocomplete_focus_ring') + container.closest('.phac-aspc-form-autocomplete-focus-ring') .classList.add('active'); container.querySelector('.textinput').focus(); } else { - container.closest('.phac_aspc_form_autocomplete_focus_ring') + container.closest('.phac-aspc-form-autocomplete-focus-ring') .classList.remove('active'); } } @@ -98,7 +98,7 @@ function phac_aspc_autocomplete_blur_handler(event, name, sync = false, item = f } function phac_aspc_autocomplete_item_click_handler(event) { - const container = event.target.closest('.phac_aspc_form_autocomplete'); + const container = event.target.closest('.phac-aspc-form-autocomplete'); const results = container.querySelector('.results'); const open = results && results.classList.contains('show'); if (open) { @@ -109,12 +109,12 @@ function phac_aspc_autocomplete_item_click_handler(event) { } function phac_aspc_autocomplete_focus_handler(event) { - const container = event.target.closest('.phac_aspc_form_autocomplete'); + const container = event.target.closest('.phac-aspc-form-autocomplete'); phac_aspc_autocomplete_clear_focus(container, true); phac_aspc_autocomplete_set_initial_value(container); setTimeout(() => { // Announce selected items to screen readers. (if any) - const info = container.querySelector('.live_info'); + const info = container.querySelector('.live-info'); info.innerHTML += ' '; }, 100); } @@ -135,7 +135,7 @@ function phac_aspc_autocomplete_set_initial_value(container, reset = false) { phac_aspc_autocomplete_closed = {}; function phac_aspc_autocomplete_click_handler(event) { if (event.target.classList.contains('item')) return true; - const container = event.target.closest('.phac_aspc_form_autocomplete'); + const container = event.target.closest('.phac-aspc-form-autocomplete'); const id = container.getAttribute('id'); const results = container.querySelector('.results'); const open = results && results.classList.contains('show'); @@ -160,7 +160,7 @@ function phac_aspc_autocomplete_keyup_handler(event) { const value = phac_aspc_autocomplete_initial_value; const elem = event.target; - const container = elem.closest('.phac_aspc_form_autocomplete'); + const container = elem.closest('.phac-aspc-form-autocomplete'); const id = container.getAttribute('id'); phac_aspc_autocomplete_set_initial_value(container); @@ -205,7 +205,7 @@ function phac_aspc_autocomplete_keydown_handler(event) { // TODO: bug with down if (!container) return null; const results = container.querySelector('.results'); - let element = container.querySelector('.hasFocus'); + let element = container.querySelector('.has-focus'); const must_skip = Boolean(element); const fallback = down ? results.querySelector('a:first-child') : results.querySelector('a:last-child'); @@ -230,11 +230,11 @@ function phac_aspc_autocomplete_keydown_handler(event) { phac_aspc_autocomplete_clear_focus(container); const el = container.querySelector('.textinput'); el.setAttribute('aria-activedescendant', element.getAttribute('id')); - element.classList.add('hasFocus'); + element.classList.add('has-focus'); element.scrollIntoView({ block: 'nearest' }) } const selectFocusedItem = (container) => { - const item = container.querySelector('.hasFocus'); + const item = container.querySelector('.has-focus'); if (item) { item.dispatchEvent(new Event('click')); } @@ -274,7 +274,7 @@ function phac_aspc_autocomplete_keydown_handler(event) { return Math.floor((r1.bottom - r1.top) / (r2.bottom - r2.top)); } - const container = event.target.closest('.phac_aspc_form_autocomplete'); + const container = event.target.closest('.phac-aspc-form-autocomplete'); const results = container.querySelector('.results'); const id = container.getAttribute('id'); @@ -414,7 +414,7 @@ class MultiAutocompleteHelper extends AbstractAutocompleteHelper { } getChips(){ - return this.getContainer().querySelectorAll(`#${this.getComponentId()}_ac_container li.chip`); + return this.getContainer().querySelectorAll(`#${this.getComponentId()}_ac-container li.chip`); } clear(){ diff --git a/apps/autocomplete/templates/autocomplete/ac_container.html b/apps/autocomplete/templates/autocomplete/ac-container.html similarity index 89% rename from apps/autocomplete/templates/autocomplete/ac_container.html rename to apps/autocomplete/templates/autocomplete/ac-container.html index a901989..a807057 100644 --- a/apps/autocomplete/templates/autocomplete/ac_container.html +++ b/apps/autocomplete/templates/autocomplete/ac-container.html @@ -2,8 +2,8 @@ This draws the list of selected items as chips as well as the text input box {% endcomment %}