@newlogic-digital/ui 3.2.0 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/.eslintrc +13 -0
  2. package/.stylelintrc +18 -0
  3. package/README.md +1 -5
  4. package/package.json +16 -8
  5. package/public/sw.js +30 -0
  6. package/src/data/main.json +5 -0
  7. package/src/emails/email.prod.html +6 -0
  8. package/src/emails/email.twig.html +6 -0
  9. package/src/emails/{email.css → styles/email.css} +1 -1
  10. package/src/emails/templates/Content.twig +16 -0
  11. package/src/emails/templates/Header.twig +14 -0
  12. package/src/emails/templates/Layout.twig +23 -0
  13. package/src/emails/templates.prod/.gitkeep +0 -0
  14. package/src/scripts/Layout/Main.js +3 -3
  15. package/src/scripts/Libraries/Dialog.js +8 -1
  16. package/src/scripts/Libraries/Drawer.js +16 -14
  17. package/src/scripts/Libraries/Form.js +12 -18
  18. package/src/scripts/Libraries/NativeSlider.js +2 -1
  19. package/src/scripts/Libraries/ReCaptcha.js +9 -4
  20. package/src/scripts/Libraries/Stimulus.js +1 -31
  21. package/src/scripts/Libraries/Swup.js +5 -1
  22. package/src/scripts/Libraries/Tabs.js +5 -5
  23. package/src/scripts/Libraries/Tippy.js +3 -1
  24. package/src/scripts/Ui/+.js +0 -1
  25. package/src/scripts/Ui/Checkbox.js +4 -13
  26. package/src/scripts/Ui/Input.js +18 -64
  27. package/src/scripts/Ui/Select.js +11 -39
  28. package/src/scripts/Ui/Text.js +2 -4
  29. package/src/scripts/Utils/Functions/+.js +1 -0
  30. package/src/scripts/Utils/Functions/checkValidity.js +44 -0
  31. package/src/scripts/Utils/Functions/inView.js +7 -8
  32. package/src/scripts/Utils/cdn.js +1 -1
  33. package/src/scripts/Utils/global.js +6 -8
  34. package/src/styles/Components/+.css +1 -1
  35. package/src/styles/Components/Dropdown/+.css +1 -0
  36. package/src/styles/{Ui/Dropdown.css → Components/Dropdown/Default.css} +1 -1
  37. package/src/styles/Libraries/+.css +0 -1
  38. package/src/styles/Libraries/Drawer.css +1 -1
  39. package/src/styles/Libraries/Hint.css +4 -3
  40. package/src/styles/Libraries/NativeSlider.css +8 -0
  41. package/src/styles/Libraries/Tippy.css +1 -1
  42. package/src/styles/Ui/+.css +0 -1
  43. package/src/styles/Ui/Badge.css +1 -1
  44. package/src/styles/Ui/Btn.css +24 -6
  45. package/src/styles/Ui/Checkbox.css +28 -2
  46. package/src/styles/Ui/Heading.css +2 -1
  47. package/src/styles/Ui/Icon.css +2 -2
  48. package/src/styles/Ui/Image.css +1 -7
  49. package/src/styles/Ui/Input.css +65 -18
  50. package/src/styles/Ui/Label.css +2 -2
  51. package/src/styles/Ui/Link.css +12 -5
  52. package/src/styles/Ui/Notice.css +1 -1
  53. package/src/styles/Ui/Select.css +3 -5
  54. package/src/styles/Ui/Text.css +13 -4
  55. package/src/styles/Ui/Title.css +3 -2
  56. package/src/styles/Utils/+.css +9 -9
  57. package/src/styles/Utils/default.css +0 -7
  58. package/src/styles/Utils/tailwind/+.css +2 -2
  59. package/src/styles/Utils/tailwind/base.css +25 -0
  60. package/src/styles/Utils/theme/+.css +1 -1
  61. package/src/styles/Utils/vars.css +32 -8
  62. package/src/templates/Layout/Main.twig +0 -6
  63. package/src/templates/Sections/Ui/Docs/@intro.html +97 -0
  64. package/src/templates/Sections/Ui/Docs/@nav.html +195 -0
  65. package/src/templates/Sections/Ui/Docs/@styles.html +100 -0
  66. package/src/templates/Sections/Ui/Docs/Default.twig +1600 -0
  67. package/src/templates/Sections/Ui/Icons.html +28 -0
  68. package/src/templates/Sections/Ui/Intro.html +136 -0
  69. package/src/templates/Sections/Ui.twig +5 -2090
  70. package/src/templates/Utils/sections.twig +2 -2
  71. package/src/views/{dialog-basic.json.twig → dialog/basic.json.twig} +0 -0
  72. package/src/views/{json-tippy.json.twig → dropdown/tippy.json.twig} +3 -3
  73. package/src/views/gdpr.json +2 -1
  74. package/src/views/index.json +2 -2
  75. package/src/views/ui-icons.json +12 -0
  76. package/src/views/ui.json +2 -2
  77. package/tailwind.config.cjs +69 -0
  78. package/vite.config.js +5 -1
  79. package/src/emails/email.twig +0 -60
  80. package/src/scripts/Ui/Radio.js +0 -23
  81. package/src/styles/Components/Item/+.css +0 -1
  82. package/src/styles/Libraries/Lazysizes.css +0 -9
@@ -1,62 +1,20 @@
1
1
  import cdn from '../Utils/cdn.js'
2
2
  import { LibStimulus, Controller } from '../Libraries/Stimulus.js'
3
- import { importStyle } from '../Utils/Functions/+.js'
3
+ import { importStyle, checkValidity } from '../Utils/Functions/+.js'
4
4
 
5
5
  LibStimulus.register('ui-input', class extends Controller {
6
6
  async connect() {
7
- const element = this.element
7
+ checkValidity(this.element, { validate: false })
8
8
 
9
- this.validate(element, false)
9
+ this.element.addEventListener('change', () => checkValidity(this.element))
10
10
 
11
- element.addEventListener('change', () => {
12
- this.validate(element, true)
13
- })
11
+ this.typeNumber(this.element)
14
12
 
15
- this.typeNumber(element)
13
+ this.typeFile(this.element)
16
14
 
17
- this.typeFile(element)
15
+ await this.typeDatetime(this.element)
18
16
 
19
- await this.typeDatetime(element)
20
-
21
- await this.typeColor(element)
22
- }
23
-
24
- validate(element, validate) {
25
- const input = element.querySelectorAll('input, textarea')
26
-
27
- input.forEach(input => {
28
- let validationMessage = input.validationMessage
29
-
30
- if (typeof input.dataset.validationMessage !== 'undefined') {
31
- validationMessage = input.dataset.validationMessage
32
- }
33
-
34
- if (input.outerHTML.match(/(data-novalidate|readonly|hidden|data-state="invalid")/) === null && validate) {
35
- element._removeDataValue('state', 'valid invalid active')
36
-
37
- if (element.querySelector('[class^="icon"][class*="valid"]') !== null) {
38
- element.querySelector('[class^="icon"][class*="valid"]').remove()
39
- }
40
-
41
- if (input.checkValidity()) {
42
- element._addDataValue('state', 'valid')
43
- } else {
44
- element._addDataValue('state', 'invalid')
45
-
46
- if (element.querySelector('[class^="icon"][class*="valid"]') === null) {
47
- const icon = element.querySelector('.icon-r')
48
- const elm = icon || element
49
- const where = icon ? 'afterend' : 'beforeend'
50
-
51
- elm.insertAdjacentHTML(where, `<div class="icon-r icon-invalid text-error lib-hint-top lib-hint-error" tabindex="0" aria-label="${validationMessage}"><svg><use href="#icon-exclamation-circle"></use></svg></div>`)
52
- }
53
- }
54
- }
55
-
56
- if (input.value !== '') {
57
- element._addDataValue('state', 'active')
58
- }
59
- })
17
+ await this.typeColor(this.element)
60
18
  }
61
19
 
62
20
  typeNumber(element) {
@@ -80,7 +38,7 @@ LibStimulus.register('ui-input', class extends Controller {
80
38
  const num = parseInt(input.value === '' ? 0 : input.value) + parseInt(input.step === '' ? 1 : input.step)
81
39
 
82
40
  if (num <= input.max || input.max === '') {
83
- input.value = num
41
+ input.value = num.toString()
84
42
  input.dispatchEvent(new Event('change', { bubbles: true }))
85
43
  }
86
44
  })
@@ -90,7 +48,7 @@ LibStimulus.register('ui-input', class extends Controller {
90
48
  const num = parseInt(input.value) - parseInt(input.step === '' ? 1 : input.step)
91
49
 
92
50
  if (num >= input.min || input.min === '') {
93
- input.value = num
51
+ input.value = num.toString()
94
52
  input.dispatchEvent(new Event('change', { bubbles: true }))
95
53
  }
96
54
  })
@@ -119,7 +77,7 @@ LibStimulus.register('ui-input', class extends Controller {
119
77
  const hidden = element.querySelector('[type="hidden"]')
120
78
 
121
79
  if (datetime && hidden.value.indexOf(':') !== -1) {
122
- hidden.setAttribute('data-time', hidden.value.substr(hidden.value.indexOf(':') - 2, hidden.value.length))
80
+ hidden.setAttribute('data-time', hidden.value.substring(hidden.value.indexOf(':') - 2, hidden.value.length))
123
81
  }
124
82
 
125
83
  const datepicker = new Datepicker(element.querySelector('[type="text"]'), Object.assign({
@@ -205,7 +163,7 @@ LibStimulus.register('ui-input', class extends Controller {
205
163
  datepicker.element.focus()
206
164
  })
207
165
 
208
- footer.querySelector('[data-ok]').addEventListener('click', e => {
166
+ footer.querySelector('[data-ok]').addEventListener('click', () => {
209
167
  if (hidden.value === '') {
210
168
  footer.querySelector('.today-btn').click()
211
169
  }
@@ -236,20 +194,16 @@ LibStimulus.register('ui-input', class extends Controller {
236
194
 
237
195
  async typeColor(element) {
238
196
  if (element.querySelector('[type="color"]') !== null) {
197
+ const Pickr = (await import('@simonwep/pickr')).default
198
+ const input = element.querySelector('input')
199
+
200
+ await importStyle(cdn.pickrCss)
201
+
239
202
  element.setAttribute('data-type', 'color')
240
203
  element.querySelector('[type="color"]').setAttribute('inputmode', 'none')
241
204
  element.querySelector('[type="color"]').setAttribute('type', 'text')
242
205
  element.insertAdjacentHTML('afterbegin', '<span class="color"></span>')
243
206
 
244
- await importStyle(cdn.pickr_css)
245
-
246
- let Pickr = (await import('@simonwep/pickr')).default
247
-
248
- if (typeof Pickr.default !== 'undefined') {
249
- Pickr = Pickr.default
250
- }
251
-
252
- const input = element.querySelector('input')
253
207
  input.setAttribute('maxlength', '9')
254
208
  input.setAttribute('pattern', '^#?([a-fA-F0-9]{8}|[a-fA-F0-9]{6}|[a-fA-F0-9]{3})$')
255
209
 
@@ -278,8 +232,8 @@ LibStimulus.register('ui-input', class extends Controller {
278
232
  input.dispatchEvent(new Event('change', { bubbles: true }))
279
233
  })
280
234
 
281
- input.addEventListener('change', e => {
282
- pickr.setColor(e.target.value)
235
+ input.addEventListener('change', ({ target }) => {
236
+ pickr.setColor(target.value)
283
237
  })
284
238
  }
285
239
  }
@@ -1,34 +1,7 @@
1
1
  import { LibStimulus, Controller } from '../Libraries/Stimulus.js'
2
+ import { checkValidity } from '../Utils/Functions/+.js'
2
3
 
3
4
  LibStimulus.register('ui-select', class extends Controller {
4
- validate(element, select) {
5
- element._removeDataValue('state', 'invalid valid focus')
6
-
7
- if (element.querySelector('[class^="icon"][class*="valid"]') !== null) {
8
- element.querySelector('[class^="icon"][class*="valid"]').remove()
9
- }
10
-
11
- let validationMessage = select.validationMessage
12
-
13
- if (typeof select.dataset.validationMessage !== 'undefined') {
14
- validationMessage = select.dataset.validationMessage
15
- }
16
-
17
- if (select.checkValidity()) {
18
- element._addDataValue('state', 'valid')
19
- } else {
20
- element._addDataValue('state', 'invalid')
21
-
22
- if (element.querySelector('[class^="icon"][class*="valid"]') === null) {
23
- const icon = element.querySelector('.icon-r')
24
- const elm = icon || element
25
- const where = icon ? 'afterend' : 'beforeend'
26
-
27
- elm.insertAdjacentHTML(where, `<div class="icon-r icon-invalid text-error lib-hint-top lib-hint-error" tabindex="0" aria-label="${validationMessage}"><svg><use href="#icon-exclamation-circle"></use></svg></div>`)
28
- }
29
- }
30
- }
31
-
32
5
  connect() {
33
6
  const element = this.element
34
7
  const select = element.querySelector('select')
@@ -44,8 +17,8 @@ LibStimulus.register('ui-select', class extends Controller {
44
17
  element.addEventListener('blur', function e() {
45
18
  element._removeDataValue('state', 'focus')
46
19
  element.removeEventListener('blur', e)
47
- }, true)
48
- }, true)
20
+ })
21
+ })
49
22
 
50
23
  element.addEventListener('click', e => {
51
24
  if ((element._hasDataValue('state', 'focus') && e.timeStamp === 0) || e.target.tagName === 'OPTION') {
@@ -54,13 +27,8 @@ LibStimulus.register('ui-select', class extends Controller {
54
27
  })
55
28
 
56
29
  select.addEventListener('change', () => {
57
- this.validate(element, select)
58
-
59
- if (select.value === '') {
60
- element._removeDataValue('state', 'active')
61
- } else {
62
- element._addDataValue('state', 'active')
63
- }
30
+ checkValidity(element)
31
+ this.valueCheck(select)
64
32
  })
65
33
 
66
34
  if (option[0] !== null) {
@@ -72,10 +40,14 @@ LibStimulus.register('ui-select', class extends Controller {
72
40
  })
73
41
  }
74
42
 
43
+ this.valueCheck(select)
44
+ }
45
+
46
+ valueCheck(select) {
75
47
  if (select.value === '') {
76
- element._removeDataValue('state', 'active')
48
+ this.element._removeDataValue('state', 'active')
77
49
  } else {
78
- element._addDataValue('state', 'active')
50
+ this.element._addDataValue('state', 'active')
79
51
  }
80
52
  }
81
53
  })
@@ -2,13 +2,11 @@ import { LibStimulus, Controller } from '../Libraries/Stimulus.js'
2
2
 
3
3
  LibStimulus.register('ui-text', class extends Controller {
4
4
  connect() {
5
- const element = this.element
6
-
7
- Array.from(element.querySelectorAll('table')).forEach(table => {
5
+ this.element.querySelectorAll('table').forEach(table => {
8
6
  this.wrap(table, new DOMParser().parseFromString('<div class="elm_text_table"></div>', 'text/html').body.firstChild)
9
7
  })
10
8
 
11
- Array.from(element.querySelectorAll('iframe')).forEach(iframe => {
9
+ this.element.querySelectorAll('iframe').forEach(iframe => {
12
10
  if (iframe.src.match(/youtube\.com/i)) {
13
11
  this.wrap(iframe, new DOMParser().parseFromString(`<div class="elm_text_video" style="max-width: ${iframe.width.includes('%') ? iframe.width : iframe.width + 'px'}"></div>`, 'text/html').body.firstChild)
14
12
  } else if (iframe.width && iframe.style.aspectRatio !== 'undefined') {
@@ -1,3 +1,4 @@
1
+ export { default as checkValidity } from './checkValidity.js'
1
2
  import './dataValue.js'
2
3
  export { default as importScript } from './importScript.js'
3
4
  export { default as importStyle } from './importStyle.js'
@@ -0,0 +1,44 @@
1
+ export default function checkValidity(element, options = {}) {
2
+ const { validate, message } = Object.assign({ validate: true, message: false }, options)
3
+ const selectors = element.querySelectorAll('input, textarea, select')
4
+
5
+ selectors.forEach(selector => {
6
+ const isInput = element.classList.contains('ui-input')
7
+ const isSelect = element.classList.contains('ui-select')
8
+ const validationMessage = selector.dataset.validationMessage ?? selector.validationMessage
9
+ const validityElement = element.closest('.ui-input-group')?.querySelector('em') ?? element.querySelector('em')
10
+
11
+ if (!selector.outerHTML.match(/(data-novalidate|readonly|hidden)/) && validate) {
12
+ element._removeDataValue('state', 'valid invalid active')
13
+
14
+ if ((isInput || isSelect) && element.querySelector('[class^="icon"][class*="valid"]') !== null) {
15
+ element.querySelector('[class^="icon"][class*="valid"]').remove()
16
+ }
17
+
18
+ if (selector.checkValidity()) {
19
+ element._addDataValue('state', 'valid')
20
+
21
+ if (validityElement) {
22
+ validityElement.remove()
23
+ }
24
+ } else {
25
+ element._addDataValue('state', 'invalid')
26
+
27
+ if (!validityElement && message) {
28
+ (element.closest('.ui-input-group') ?? element).insertAdjacentHTML('beforeend', `<em>${validationMessage}</em>`)
29
+ }
30
+
31
+ if ((isInput || isSelect) && element.querySelector('[class^="icon"][class*="valid"]') === null) {
32
+ const icon = element.querySelector('.icon-r')
33
+ const where = icon || element
34
+
35
+ where.insertAdjacentHTML(icon ? 'afterend' : 'beforeend', `<div class="icon-r icon-invalid text-error lib-hint-top lib-hint-error" tabindex="0" aria-label="${validationMessage}"><svg><use href="#icon-exclamation-circle"></use></svg></div>`)
36
+ }
37
+ }
38
+ }
39
+
40
+ if (isInput && selector.value !== '') {
41
+ element._addDataValue('state', 'active')
42
+ }
43
+ })
44
+ }
@@ -1,4 +1,4 @@
1
- export default function inView(element, options) {
1
+ export default function inView(element, options = {}) {
2
2
  let inView = false
3
3
 
4
4
  return new Promise((resolve) => {
@@ -7,19 +7,18 @@ export default function inView(element, options) {
7
7
  return false
8
8
  }
9
9
 
10
- if (typeof options === 'undefined') {
11
- options = {}
12
- }
13
-
14
- if (typeof options.rootMargin === 'undefined') {
10
+ if (!options.rootMargin) {
15
11
  options.rootMargin = '100px'
16
12
  }
17
13
 
18
- new IntersectionObserver(entries => {
14
+ const observer = new IntersectionObserver(entries => {
19
15
  if (entries[0].isIntersecting && inView === false) {
20
16
  inView = entries[0].isIntersecting
17
+ observer.disconnect()
21
18
  resolve()
22
19
  }
23
- }, options).observe(element)
20
+ }, options || {})
21
+
22
+ observer.observe(element)
24
23
  })
25
24
  }
@@ -1,7 +1,7 @@
1
1
  export default {
2
2
  recaptcha: 'https://www.google.com/recaptcha/enterprise.js?render={apikey}',
3
3
  seamless: 'https://cdn.jsdelivr.net/npm/seamless-scroll-polyfill@2.1.6/lib/bundle.min.js',
4
- pickr_css: 'https://cdn.jsdelivr.net/npm/@simonwep/pickr@1.8.0/dist/themes/nano.min.css',
4
+ pickrCss: 'https://cdn.jsdelivr.net/npm/@simonwep/pickr@1.8.0/dist/themes/nano.min.css',
5
5
  tippy: 'https://cdn.jsdelivr.net/combine/npm/tippy.js@6.3.7/dist/tippy.css,npm/tippy.js@6.3.1/dist/svg-arrow.css,npm/tippy.js@6.3.7/themes/light-border.css,npm/tippy.js@6.3.7/animations/scale.css',
6
6
  datepicker: 'https://cdn.jsdelivr.net/npm/vanillajs-datepicker@1.2.0/dist/css/datepicker.min.css'
7
7
  }
@@ -1,15 +1,13 @@
1
+ !CSS.supports('selector(:has(*))') && (async() => (await import('css-has-pseudo/browser')).default(document))()
2
+
1
3
  if ('serviceWorker' in navigator && location.protocol === 'https:') {
2
4
  window.addEventListener('load', () => {
3
5
  if (!document.documentElement.classList.contains('no-sw')) {
4
- navigator.serviceWorker.register('/sw.js').catch(e => {
5
- console.error('Error during service worker registration:', e)
6
- })
6
+ navigator.serviceWorker.register('/sw.js').catch(e => console.error(e))
7
7
  } else {
8
- navigator.serviceWorker.getRegistrations().then(registrations => {
9
- if (registrations.length > 0) {
10
- for (const registration of registrations) {
11
- registration.unregister()
12
- }
8
+ navigator.serviceWorker.getRegistrations().then(async registrations => {
9
+ for (const registration of registrations) {
10
+ await registration.unregister()
13
11
  }
14
12
  })
15
13
  }
@@ -1,4 +1,4 @@
1
1
  @import "CookieConsent.css";
2
2
  @import "Dialog/+.css";
3
+ @import "Dropdown/+.css";
3
4
  @import "Form/+.css";
4
- @import "Item/+.css";
@@ -0,0 +1 @@
1
+ @import "Default.css";
@@ -1,4 +1,4 @@
1
- .ui-dropdown {
1
+ .c-dropdown {
2
2
  padding: 1.25rem 1.5rem;
3
3
  overflow: hidden;
4
4
  max-width: 22rem;
@@ -2,7 +2,6 @@
2
2
  @import "Dialog.css";
3
3
  @import "Drawer.css";
4
4
  @import "Hint.css";
5
- @import "Lazysizes.css";
6
5
  @import "NativeSlider.css";
7
6
  @import "Ripple.css";
8
7
  @import "Tabs.css";
@@ -26,7 +26,7 @@
26
26
  -ms-overflow-style: none;
27
27
 
28
28
  &:--state-active {
29
- scroll-snap-type: x mandatory;
29
+ scroll-snap-type: x proximity;
30
30
  }
31
31
 
32
32
  &::-webkit-scrollbar {
@@ -41,7 +41,7 @@
41
41
  will-change: transform;
42
42
  backface-visibility: hidden;
43
43
 
44
- @nest :is(:hover, :focus)& {
44
+ @nest :is(:hover, :focus-visible)& {
45
45
  visibility: visible;
46
46
  opacity: 1;
47
47
  transition-delay: 100ms;
@@ -82,6 +82,7 @@
82
82
  line-height: 0.875rem;
83
83
  white-space: nowrap;
84
84
  box-shadow: 0.25rem 0.25rem 0.5rem rgb(var(--lib-hint-bg) / 0.15);
85
+ font-weight: var(--font-normal);
85
86
 
86
87
  @nest .lib-hint-light& {
87
88
  box-shadow: 0.25rem 0.25rem 0.5rem rgb(var(--color-dark) / 0.15);
@@ -120,7 +121,7 @@
120
121
  left: calc(50% - 0.375rem);
121
122
  margin-bottom: -0.6875rem;
122
123
 
123
- @nest :is(:hover, :focus)& {
124
+ @nest :is(:hover, :focus-visible)& {
124
125
  transform: translateY(-0.5rem);
125
126
  }
126
127
  }
@@ -128,7 +129,7 @@
128
129
  &::after {
129
130
  transform: translateX(-50%);
130
131
 
131
- @nest :is(:hover, :focus)& {
132
+ @nest :is(:hover, :focus-visible)& {
132
133
  transform: translateX(-50%) translateY(-0.5rem);
133
134
  }
134
135
  }
@@ -45,6 +45,14 @@
45
45
  height: 0.75rem;
46
46
  border: 0.125rem solid rgb(var(--color-current));
47
47
  border-radius: 50%;
48
+ cursor: pointer;
49
+ position: relative;
50
+
51
+ &::after {
52
+ position: absolute;
53
+ inset: -0.5rem;
54
+ content: "";
55
+ }
48
56
 
49
57
  &[data-state*="active"] {
50
58
  background-color: rgb(var(--color-current));
@@ -9,7 +9,7 @@
9
9
  background-color: rgb(var(--color-background));
10
10
  background-clip: padding-box;
11
11
  border: 1px solid rgb(0 8 16 / 0.05);
12
- color: rgb(var(--color-current));
12
+ color: rgb(var(--color-default));
13
13
  box-shadow: 0 3px 14px -0.5px rgb(0 8 16 / 0.08);
14
14
  border-radius: var(--radius);
15
15
  left: 0.1875rem;
@@ -1,7 +1,6 @@
1
1
  @import "Badge.css";
2
2
  @import "Btn.css";
3
3
  @import "Checkbox.css";
4
- @import "Dropdown.css";
5
4
  @import "Heading.css";
6
5
  @import "Icon.css";
7
6
  @import "Image.css";
@@ -29,7 +29,7 @@
29
29
  line-height: var(--ui-badge-size);
30
30
  transition: var(--transition-opacity);
31
31
 
32
- @nest .no-touch &:is([href]:hover, button:hover) {
32
+ @nest .no-touch &:is([href], button):is(:hover, :focus-visible) {
33
33
  opacity: var(--ui-badge-hover-opacity);
34
34
  }
35
35
 
@@ -32,12 +32,13 @@
32
32
  height: var(--ui-btn-height);
33
33
  padding: var(--ui-btn-py) var(--ui-btn-px);
34
34
  border-radius: var(--ui-btn-radius);
35
- transition: var(--transition-opacity), var(--transition-background);
35
+ transition: var(--transition-opacity), var(--transition-background), var(--transition-color);
36
36
  background-color: var(--ui-btn-bg);
37
37
  color: var(--ui-btn-color);
38
38
 
39
- @nest .dark &.bg-default {
39
+ @nest .dark &.accent-dark {
40
40
  --ui-btn-color: rgb(var(--color-dark));
41
+ --color-accent: var(--color-light);
41
42
  }
42
43
 
43
44
  &:--theme-light {
@@ -59,7 +60,7 @@
59
60
  opacity: 0;
60
61
  transition: var(--transition-opacity);
61
62
 
62
- @nest .no-touch :is(:hover, :focus)&, :is(:--state-active)& {
63
+ @nest .no-touch :is(:hover, :focus-visible)&, :is(:--state-active)& {
63
64
  opacity: var(--ui-btn-hover-opacity);
64
65
  }
65
66
  }
@@ -97,8 +98,16 @@
97
98
  }
98
99
  }
99
100
 
101
+ &:--type-text {
102
+ @nest :not(:hover, :focus-visible, :--state-active)& {
103
+ --ui-btn-color: currentColor;
104
+
105
+ background-color: transparent;
106
+ }
107
+ }
108
+
100
109
  &:--type-outline {
101
- --ui-btn-color: currentColor;
110
+ --ui-btn-color: rgb(var(--color-current));
102
111
  --ui-btn-hover-opacity: 0.1;
103
112
 
104
113
  background-color: transparent;
@@ -130,6 +139,11 @@
130
139
  border-radius: 50%;
131
140
  }
132
141
 
142
+ &:--size-sm {
143
+ --ui-btn-height: 2.25rem;
144
+ --ui-btn-px: 1rem;
145
+ }
146
+
133
147
  &:--size-lg {
134
148
  --ui-btn-icon-size: 1.5rem;
135
149
  --ui-btn-height: 3rem;
@@ -138,7 +152,11 @@
138
152
 
139
153
  &:--state-loading {
140
154
  pointer-events: none;
141
- color: var(--ui-btn-bg);
155
+ color: transparent;
156
+
157
+ & > * {
158
+ opacity: 0;
159
+ }
142
160
 
143
161
  &::before {
144
162
  z-index: 1;
@@ -155,7 +173,7 @@
155
173
  margin-top: -0.625rem;
156
174
  left: 50%;
157
175
  top: 50%;
158
- opacity: 1;
176
+ opacity: 1 !important;
159
177
  }
160
178
  }
161
179
 
@@ -12,9 +12,12 @@
12
12
  --ui-checkbox-radius: 0.375rem;
13
13
  --ui-checkbox-icon: var(--icon-check);
14
14
  --ui-checkbox-icon-size: 1.125rem;
15
+ --ui-checkbox-validity-size: 0.875rem;
16
+ --ui-checkbox-validity-offset: 0.375rem;
15
17
 
16
18
  transition: var(--transition-color);
17
19
  display: inline-flex;
20
+ flex-wrap: wrap;
18
21
  align-self: flex-start;
19
22
  position: relative;
20
23
  user-select: none;
@@ -22,6 +25,11 @@
22
25
  z-index: 1;
23
26
  color: var(--ui-checkbox-color);
24
27
 
28
+ &[disabled] {
29
+ pointer-events: none;
30
+ opacity: 0.5;
31
+ }
32
+
25
33
  @nest .text-light & {
26
34
  --ui-checkbox-border-color-raw: var(--color-light);
27
35
  }
@@ -39,6 +47,15 @@
39
47
  --ui-checkbox-color: rgb(var(--color-error));
40
48
  }
41
49
 
50
+ & em {
51
+ display: block;
52
+ width: 100%;
53
+ font-size: var(--ui-checkbox-validity-size);
54
+ color: rgb(var(--color-error));
55
+ font-style: normal;
56
+ margin-top: var(--ui-checkbox-validity-offset);
57
+ }
58
+
42
59
  & input {
43
60
  position: relative;
44
61
  display: inline-flex;
@@ -80,7 +97,7 @@
80
97
  }
81
98
  }
82
99
 
83
- &:focus, &:hover {
100
+ &:is(:hover, :focus-visible) {
84
101
  --ui-checkbox-bg-raw: var(--ui-checkbox-checked-bg-raw);
85
102
  --ui-checkbox-border-color-raw: var(--ui-checkbox-checked-bg-raw);
86
103
  --ui-checkbox-border-opacity: 0.75;
@@ -111,6 +128,15 @@
111
128
  transform: scale(1);
112
129
  }
113
130
  }
131
+
132
+ &[required] {
133
+ & + * {
134
+ &::after {
135
+ color: rgb(var(--color-error));
136
+ content: " *";
137
+ }
138
+ }
139
+ }
114
140
  }
115
141
 
116
142
  & a {
@@ -118,7 +144,7 @@
118
144
  transition: var(--transition-opacity);
119
145
  color: rgb(var(--color-accent));
120
146
 
121
- @nest .no-touch &[href]:hover {
147
+ @nest .no-touch &[href]:is(:hover, :focus-visible) {
122
148
  opacity: 0.8;
123
149
  }
124
150
  }
@@ -1,9 +1,10 @@
1
1
  .ui-heading {
2
2
  --ui-heading-size: 1.5rem;
3
+ --ui-heading-weight: var(--font-bold);
3
4
  --ui-heading-size-line: 0.5rem;
4
5
 
5
6
  display: block;
6
- font-weight: var(--font-bold);
7
+ font-weight: var(--ui-heading-weight);
7
8
  font-size: var(--ui-heading-size);
8
9
  line-height: calc(var(--ui-heading-size) + var(--ui-heading-size-line));
9
10
 
@@ -14,7 +14,7 @@
14
14
  & > * {
15
15
  transition: var(--transition-opacity);
16
16
 
17
- @nest .no-touch :is([href]:hover, button:hover)& {
17
+ @nest .no-touch :is([href], button):is(:hover, :focus-visible)& {
18
18
  opacity: var(--ui-icon-hover-opacity);
19
19
  }
20
20
  }
@@ -27,7 +27,7 @@
27
27
  align-items: center;
28
28
  transition: var(--transition-opacity), var(--transition-color);
29
29
 
30
- @nest .no-touch &:is([href]:hover, button:hover) {
30
+ @nest .no-touch &:is([href], button):is(:hover, :focus-visible) {
31
31
  opacity: var(--ui-icon-hover-opacity);
32
32
  }
33
33
  }
@@ -1,18 +1,12 @@
1
1
  .ui-image {
2
2
  position: relative;
3
+ display: block;
3
4
 
4
5
  &:not(.bg-transparent) {
5
6
  background-color: rgb(var(--color-background-100));
6
7
  }
7
8
 
8
- &::before {
9
- content: "";
10
- display: block;
11
- }
12
-
13
9
  & > * {
14
- position: absolute;
15
- inset: 0;
16
10
  width: 100%;
17
11
  height: 100%;
18
12
  }