@omnisass/library 0.2.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 (93) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/LICENSE +21 -0
  3. package/README.md +2 -0
  4. package/_configs.scss +68 -0
  5. package/index.scss +95 -0
  6. package/modules/utilities/converters/_convert-camel2kebab.scss +186 -0
  7. package/modules/utilities/converters/_convert-em2px.scss +239 -0
  8. package/modules/utilities/converters/_convert-hex2rgb.scss +97 -0
  9. package/modules/utilities/converters/_convert-hex2rgba.scss +124 -0
  10. package/modules/utilities/converters/_convert-kebab2camel.scss +232 -0
  11. package/modules/utilities/converters/_convert-kebab2snake.scss +118 -0
  12. package/modules/utilities/converters/_convert-px2em.scss +236 -0
  13. package/modules/utilities/converters/_convert-px2rem.scss +180 -0
  14. package/modules/utilities/converters/_convert-rem2px.scss +207 -0
  15. package/modules/utilities/converters/_convert-snake2kebab.scss +173 -0
  16. package/modules/utilities/getters/color/_get-color-brightness.scss +138 -0
  17. package/modules/utilities/getters/color/_get-color-darkest.scss +178 -0
  18. package/modules/utilities/getters/list/_get-list-item-end.scss +114 -0
  19. package/modules/utilities/getters/list/_get-list-item-start.scss +109 -0
  20. package/modules/utilities/getters/list/_get-list-item.scss +179 -0
  21. package/modules/utilities/getters/number/_get-number-from-percent.scss +139 -0
  22. package/modules/utilities/getters/number/_get-number-height-by-ratio.scss +199 -0
  23. package/modules/utilities/getters/number/_get-number-max.scss +168 -0
  24. package/modules/utilities/getters/number/_get-number-min.scss +162 -0
  25. package/modules/utilities/getters/number/_get-number-percentage-of.scss +149 -0
  26. package/modules/utilities/getters/number/_get-number-unit.scss +111 -0
  27. package/modules/utilities/getters/number/_get-number-width-by-ratio.scss +223 -0
  28. package/modules/utilities/helpers/color/_color-blend-steps.scss +210 -0
  29. package/modules/utilities/helpers/color/_color-blend.scss +183 -0
  30. package/modules/utilities/helpers/color/_color-hue-shift.scss +148 -0
  31. package/modules/utilities/helpers/color/_color-scale.scss +208 -0
  32. package/modules/utilities/helpers/color/_color-shade.scss +113 -0
  33. package/modules/utilities/helpers/color/_color-tint.scss +118 -0
  34. package/modules/utilities/helpers/color/_color-triad.scss +141 -0
  35. package/modules/utilities/helpers/list/_list-dedupe.scss +146 -0
  36. package/modules/utilities/helpers/list/_list-insert-at.scss +166 -0
  37. package/modules/utilities/helpers/list/_list-merge.scss +86 -0
  38. package/modules/utilities/helpers/list/_list-remove-at.scss +160 -0
  39. package/modules/utilities/helpers/list/_list-sum-numbers-safe.scss +175 -0
  40. package/modules/utilities/helpers/list/_list-sum-numbers.scss +128 -0
  41. package/modules/utilities/helpers/misc/_url-encode.configs.scss +64 -0
  42. package/modules/utilities/helpers/misc/_url-encode.scss +148 -0
  43. package/modules/utilities/helpers/number/_number-ceil-to.scss +111 -0
  44. package/modules/utilities/helpers/number/_number-clamp-max.scss +92 -0
  45. package/modules/utilities/helpers/number/_number-clamp-min.scss +100 -0
  46. package/modules/utilities/helpers/number/_number-clamp.scss +109 -0
  47. package/modules/utilities/helpers/number/_number-denormalize.scss +172 -0
  48. package/modules/utilities/helpers/number/_number-fibonacci.scss +235 -0
  49. package/modules/utilities/helpers/number/_number-floor-to.scss +114 -0
  50. package/modules/utilities/helpers/number/_number-format-with-separator.scss +122 -0
  51. package/modules/utilities/helpers/number/_number-normalize.scss +160 -0
  52. package/modules/utilities/helpers/number/_number-random-between-int.scss +84 -0
  53. package/modules/utilities/helpers/number/_number-random-between.scss +120 -0
  54. package/modules/utilities/helpers/number/_number-range.scss +268 -0
  55. package/modules/utilities/helpers/number/_number-round-to-nearest.scss +131 -0
  56. package/modules/utilities/helpers/number/_number-round-to.scss +118 -0
  57. package/modules/utilities/helpers/number/_number-strip-unit.scss +97 -0
  58. package/modules/utilities/helpers/string/_string-capitalize.scss +84 -0
  59. package/modules/utilities/helpers/string/_string-replace.scss +69 -0
  60. package/modules/utilities/helpers/string/_string-trim-end.scss +62 -0
  61. package/modules/utilities/helpers/string/_string-trim-start.scss +62 -0
  62. package/modules/utilities/helpers/string/_string-trim.scss +69 -0
  63. package/modules/utilities/loggers/_log-invalid-type.scss +151 -0
  64. package/modules/utilities/loggers/_log-invalid-value.scss +151 -0
  65. package/modules/utilities/setters/_index.scss +3 -0
  66. package/modules/utilities/validators/color/_is-color-light.scss +132 -0
  67. package/modules/utilities/validators/color/_is-color-list.scss +124 -0
  68. package/modules/utilities/validators/list/_is-list-contained.scss +65 -0
  69. package/modules/utilities/validators/misc/_is-time.scss +115 -0
  70. package/modules/utilities/validators/number/_is-int-even.scss +69 -0
  71. package/modules/utilities/validators/number/_is-int-odd.scss +70 -0
  72. package/modules/utilities/validators/number/_is-int.scss +124 -0
  73. package/modules/utilities/validators/number/_is-number-has-unit.scss +85 -0
  74. package/modules/utilities/validators/number/_is-number-negative.scss +76 -0
  75. package/modules/utilities/validators/number/_is-number-positive.scss +74 -0
  76. package/modules/utilities/validators/number/_is-number-unitless.scss +88 -0
  77. package/modules/utilities/validators/number/_is-number-zero.scss +75 -0
  78. package/modules/utilities/validators/string/_is-string-contained.scss +108 -0
  79. package/modules/utilities/validators/string/_is-string-empty.scss +56 -0
  80. package/modules/utilities/validators/string/_is-string-ending-with.scss +66 -0
  81. package/modules/utilities/validators/string/_is-string-starting-with.scss +66 -0
  82. package/modules/utilities/validators/type-of/_is-boolean.scss +92 -0
  83. package/modules/utilities/validators/type-of/_is-color.scss +96 -0
  84. package/modules/utilities/validators/type-of/_is-list.scss +105 -0
  85. package/modules/utilities/validators/type-of/_is-map.scss +105 -0
  86. package/modules/utilities/validators/type-of/_is-number.scss +103 -0
  87. package/modules/utilities/validators/type-of/_is-string.scss +110 -0
  88. package/modules/utilities/validators/type-of/_is-type.scss +77 -0
  89. package/package.json +54 -0
  90. package/package.scss +156 -0
  91. package/test.md +168 -0
  92. package/test.scss +405 -0
  93. package/test.sh +149 -0
@@ -0,0 +1,173 @@
1
+ @use '../helpers/string/string-replace' as *;
2
+ @use '../loggers/log-invalid-type' as *;
3
+ @use '../validators/type-of/is-string' as *;
4
+
5
+ /// Преобразует строку из `snake_case` (змеиная нотация) в
6
+ /// `kebab-case` (кебаб-нотация).
7
+ ///
8
+ /// Функция заменяет все символы нижнего подчеркивания (`_`)
9
+ /// на дефисы (`-`) в переданной строке. Это простое
10
+ /// преобразование позволяет конвертировать имена переменных
11
+ /// из языков программирования, использующих snake_case
12
+ /// (Python, Ruby, PHP) в CSS-совместимый kebab-case формат.
13
+ ///
14
+ /// Важные особенности функции:
15
+ /// - Заменяет все вхождения нижнего подчеркивания на дефисы
16
+ /// - Сохраняет все остальные символы без изменений
17
+ /// - Не изменяет регистр символов
18
+ /// - Работает с любыми строками, содержащими подчеркивания
19
+ /// - Простая и эффективная реализация через замену символов
20
+ /// - Полезно для конвертации имен из backend в frontend
21
+ /// - Используется для унификации именования в full-stack проектах
22
+ /// - Поддерживает строки любой длины и сложности
23
+ /// - Обрабатывает множественные подчеркивания подряд
24
+ /// - Учитывает граничные случаи (пустая строка, отсутствие
25
+ /// подчеркиваний)
26
+ /// ---
27
+ /// @name convert-snake2kebab
28
+ /// @group utilities-converters
29
+ /// @since 2026.01.13
30
+ /// @access public
31
+ /// @author Murad Rustamov (therteenten)
32
+ /// @link https://sourcecraft.dev/users/therteenten/overview SourceCraft - therteenten
33
+ /// @link https://sourcecraft.dev/omnisass/library SourceCraft - OmniSass
34
+ /// @link https://sass-lang.com/documentation/modules/string См. также: Официальная документация Sass - Модуль String
35
+ /// @link https://sass-lang.com/documentation/values/strings См. также: Официальная документация Sass - Тип данных "Строки"
36
+ /// @link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace См. также: MDN Web Docs - Метод String.replace()
37
+ /// @link https://developer.mozilla.org/en-US/docs/Glossary/Snake_case См. также: MDN Web Docs - Глоссарий: Snake_case
38
+ /// @link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_selectors См. также: MDN Web Docs - CSS селекторы
39
+ /// @link https://css-tricks.com/snippets/sass/string-replace-function/ См. также: CSS-Tricks - Функция замены строк в Sass
40
+ /// @link https://css-tricks.com/whats-the-difference-between-kebab-case-camel-case-and-snake-case/ См. также: CSS-Tricks - Разница между kebab-case, camelCase и snake_case
41
+ /// @link https://sass-guidelin.es/ru/#section-42 См. также: Sass Guidelines - Раздел про строки
42
+ /// @link https://www.python.org/dev/peps/pep-0008/ См. также: PEP 8 - Style Guide for Python Code
43
+ /// @link https://rubystyle.guide/#naming См. также: Ruby Style Guide - Именование
44
+ /// @example scss - Базовые преобразования
45
+ /// @debug convert-snake2kebab('snake_case'); // 'snake-case'
46
+ /// @debug convert-snake2kebab('background_color'); // 'background-color'
47
+ /// @debug convert-snake2kebab('font_size'); // 'font-size'
48
+ /// @debug convert-snake2kebab('border_radius'); // 'border-radius'
49
+ /// @debug convert-snake2kebab('padding_left'); // 'padding-left'
50
+ /// @debug convert-snake2kebab('margin_bottom'); // 'margin-bottom'
51
+ /// @example scss - Множественные подчеркивания
52
+ /// @debug convert-snake2kebab('border_top_left_radius'); // 'border-top-left-radius'
53
+ /// @debug convert-snake2kebab('font_weight_bold'); // 'font-weight-bold'
54
+ /// @debug convert-snake2kebab('text_decoration_line'); // 'text-decoration-line'
55
+ /// @debug convert-snake2kebab('background_image_url'); // 'background-image-url'
56
+ /// @debug convert-snake2kebab('grid_template_columns'); // 'grid-template-columns'
57
+ /// @debug convert-snake2kebab('transition_property_all'); // 'transition-property-all'
58
+ /// @example scss - Сложные случаи с цифрами и аббревиатурами
59
+ /// @debug convert-snake2kebab('xml_http_request'); // 'xml-http-request'
60
+ /// @debug convert-snake2kebab('css_animation'); // 'css-animation'
61
+ /// @debug convert-snake2kebab('html5_canvas'); // 'html5-canvas'
62
+ /// @debug convert-snake2kebab('ui_component'); // 'ui-component'
63
+ /// @debug convert-snake2kebab('api_endpoint'); // 'api-endpoint'
64
+ /// @debug convert-snake2kebab('user_id'); // 'user-id'
65
+ /// @example scss - Граничные случаи
66
+ /// @debug convert-snake2kebab('single'); // 'single'
67
+ /// @debug convert-snake2kebab(''); // '' (пустая строка)
68
+ /// @debug convert-snake2kebab('already-kebab'); // 'already-kebab' (без изменений)
69
+ /// @debug convert-snake2kebab('multiple___underscores'); // 'multiple---hyphens'
70
+ /// @debug convert-snake2kebab('_leading_underscore'); // '-leading-underscore'
71
+ /// @debug convert-snake2kebab('trailing_underscore_'); // 'trailing-underscore-'
72
+ /// @example scss - Интеграция с Python/Ruby конфигурациями
73
+ /// // Конвертация переменных из backend (Python/Ruby) в CSS
74
+ /// $backend-variables: (
75
+ /// 'primary_color': #3498db,
76
+ /// 'secondary_color': #2ecc71,
77
+ /// 'font_size_base': 16px,
78
+ /// 'border_radius_small': 4px,
79
+ /// 'max_width_container': 1200px
80
+ /// );
81
+ ///
82
+ /// :root {
83
+ /// @each $name, $value in $backend-variables {
84
+ /// --#{convert-snake2kebab($name)}: #{$value};
85
+ /// }
86
+ /// }
87
+ /// @example css - Результат интеграции с backend
88
+ /// :root {
89
+ /// --primary-color: #3498db;
90
+ /// --secondary-color: #2ecc71;
91
+ /// --font-size-base: 16px;
92
+ /// --border-radius-small: 4px;
93
+ /// --max-width-container: 1200px;
94
+ /// }
95
+ /// @example scss - Работа с API-ответами
96
+ /// // Преобразование ключей JSON из snake_case в kebab-case
97
+ /// $api-response: (
98
+ /// 'user_name': 'John Doe',
99
+ /// 'email_address': 'john@example.com',
100
+ /// 'is_active': true,
101
+ /// 'created_at': '2023-01-15',
102
+ /// 'updated_at': '2023-12-28'
103
+ /// );
104
+ ///
105
+ /// .user-data {
106
+ /// @each $key, $value in $api-response {
107
+ /// data-#{convert-snake2kebab($key)}: "#{$value}";
108
+ /// }
109
+ /// }
110
+ /// @example css - Результат для data-атрибутов
111
+ /// .user-data {
112
+ /// data-user-name: "John Doe";
113
+ /// data-email-address: "john@example.com";
114
+ /// data-is-active: true;
115
+ /// data-created-at: "2023-01-15";
116
+ /// data-updated-at: "2023-12-28";
117
+ /// }
118
+ /// @param {String} $value - Строка в snake_case нотации для
119
+ /// конвертации. Может содержать буквы, цифры, символы
120
+ /// нижнего подчеркивания и другие символы. Функция заменяет
121
+ /// все вхождения `_` на `-`, сохраняя остальные символы
122
+ /// без изменений.
123
+ /// @return {String} - Строка в kebab-case нотации, где все
124
+ /// символы нижнего подчеркивания заменены на дефисы.
125
+ /// Результат готов к использованию как CSS-класс, часть
126
+ /// селектора или имя CSS-переменной.
127
+ /// @throws {Error} - Может выбросить ошибку при передаче
128
+ /// нестроковых значений или если функция `string-replace`
129
+ /// не определена. Требуется наличие функции `string-replace`
130
+ /// в доступном scope.
131
+ /// @require {function} string-replace - Вспомогательная
132
+ /// функция замены подстрок в строке из модуля `helpers`.
133
+ /// Должна быть определена и доступна для корректной работы
134
+ /// данной функции.
135
+ @function convert-snake2kebab($value) {
136
+
137
+ // Проверка типа входного параметра: ожидается
138
+ // строковое значение.
139
+ // Функция is-string() проверяет, является ли $value
140
+ // строкой (тип данных string).
141
+ @if not is-string($value) {
142
+
143
+ // Если $value не является строкой, возвращаем ошибку
144
+ // через стандартную функцию логирования.
145
+ // Это предотвращает выполнение операции замены с
146
+ // некорректными данными.
147
+ @return log-invalid-type(
148
+ 'convert-snake2kebab',
149
+ $value,
150
+ '$value',
151
+ 'string'
152
+ );
153
+
154
+ } @else {
155
+
156
+ // Основная логика выполняется только если $value
157
+ // является корректной строкой.
158
+ //
159
+ // Используем вспомогательную функцию string-replace()
160
+ // для замены символов:
161
+ // - Первый параметр: $value - исходная строка для
162
+ // преобразования
163
+ // - Второй параметр: "_" - искомый символ (нижнее
164
+ // подчеркивание, snake_case разделитель)
165
+ // - Третий параметр: "-" - заменяющий символ (дефис,
166
+ // kebab-case разделитель)
167
+ //
168
+ // Результат: строка, в которой все символы "_" заменены на "-".
169
+ @return string-replace($value, "_", "-");
170
+
171
+ }
172
+
173
+ }
@@ -0,0 +1,138 @@
1
+ @use 'sass:color';
2
+ @use '../../loggers/log-invalid-type' as *;
3
+ @use '../../validators/type-of/is-color' as *;
4
+
5
+ /// Рассчитывает яркость (светлоту) цвета.
6
+ ///
7
+ /// Функция `get-color-brightness()` возвращает значение
8
+ /// светлоты цвета в соответствии с моделью HSL.
9
+ ///
10
+ /// Это упрощенный интерфейс к стандартной функции
11
+ /// `lightness()`. Значение яркости варьируется от 0%
12
+ /// (абсолютно черный) до 100% (абсолютно белый).
13
+ ///
14
+ /// Полезно для динамического определения контрастности
15
+ /// текста, автоматической корректировки цветов или создания
16
+ /// доступных цветовых схем.
17
+ /// ---
18
+ /// @name get-color-brightness
19
+ /// @group utilities-getters
20
+ /// @since 2025.12.27
21
+ /// @access public
22
+ /// @author Murad Rustamov (therteenten)
23
+ /// @link https://sourcecraft.dev/users/therteenten/overview SourceCraft - therteenten
24
+ /// @link https://sourcecraft.dev/omnisass/library SourceCraft - OmniSass
25
+ /// @link https://sass-lang.com/documentation/modules/color#lightness См. также: Sass - Документация функции lightness()
26
+ /// @link https://developer.mozilla.org/en-US/docs/Web/Accessibility/Understanding_WCAG/Perceivable/Color_contrast См. также: MDN - Понимание WCAG: Контрастность цветов
27
+ /// @link https://webaim.org/resources/contrastchecker/ См. также: WebAIM - Проверка контрастности цветов
28
+ /// @link https://www.w3.org/TR/WCAG21/#contrast-minimum См. также: W3C - Рекомендации по минимальному контрасту
29
+ /// @link https://css-tricks.com/switch-font-color-for-different-backgrounds-with-css/ См. также: CSS-Tricks - Смена цвета текста для разных фонов
30
+ /// @example scss - Пример использования
31
+ /// $primary: #3498db;
32
+ /// $brightness: get-color-brightness($primary); // Пример: ~53%
33
+ ///
34
+ /// // Автоматический выбор цвета текста в зависимости от фона
35
+ /// .element {
36
+ /// background-color: $primary;
37
+ /// color: color: if($brightness > 50%, #000, #fff);
38
+ /// }
39
+ /// @example css - Результат
40
+ /// .element {
41
+ /// background-color: #3498db;
42
+ /// color: #000;
43
+ /// }
44
+ /// @example scss - Стандартные цвета
45
+ /// @debug get-color-brightness(#ffffff); // 100%
46
+ /// @debug get-color-brightness(#000000); // 0%
47
+ /// @debug get-color-brightness(#ff0000); // 50%
48
+ /// @debug get-color-brightness(#00ff00); // 50%
49
+ /// @debug get-color-brightness(#0000ff); // 50%
50
+ /// @debug get-color-brightness(#ffff00); // 50%
51
+ /// @debug get-color-brightness(#ff00ff); // 50%
52
+ /// @debug get-color-brightness(#00ffff); // 50%
53
+ /// @debug get-color-brightness(#808080); // 50.196078431372555%
54
+ /// @debug get-color-brightness(#c0c0c0); // 75.29411764705883%
55
+ /// @example scss - Цвета в разных форматах
56
+ /// @debug get-color-brightness(rgb(255, 0, 0)); // 50%
57
+ /// @debug get-color-brightness(rgba(255, 0, 0, 0.5)); // 50%
58
+ /// @debug get-color-brightness(hsl(0, 100%, 50%)); // 50%
59
+ /// @debug get-color-brightness(hsla(0, 100%, 50%, 0.5)); // 50%
60
+ /// @debug get-color-brightness(hsl(120, 100%, 50%)); // 50%
61
+ /// @debug get-color-brightness(hsl(240, 100%, 50%)); // 50%
62
+ /// @example scss - Градации серого
63
+ /// @debug get-color-brightness(#000000); // 0%
64
+ /// @debug get-color-brightness(#333333); // 20%
65
+ /// @debug get-color-brightness(#666666); // 40%
66
+ /// @debug get-color-brightness(#999999); // 60%
67
+ /// @debug get-color-brightness(#cccccc); // 80%
68
+ /// @debug get-color-brightness(#ffffff); // 100%
69
+ /// @example scss - Пастельные цвета
70
+ /// @debug get-color-brightness(#ffcccc); // 90%
71
+ /// @debug get-color-brightness(#ccffcc); // 90%
72
+ /// @debug get-color-brightness(#ccccff); // 90%
73
+ /// @debug get-color-brightness(#ffe6cc); // 90%
74
+ /// @debug get-color-brightness(#e6ccff); // 90%
75
+ /// @example scss - Яркие и темные цвета
76
+ /// @debug get-color-brightness(#ff9900); // 50%
77
+ /// @debug get-color-brightness(#00cc99); // 40%
78
+ /// @debug get-color-brightness(#663399); // 40%
79
+ /// @debug get-color-brightness(#330066); // 20%
80
+ /// @debug get-color-brightness(#003366); // 20%
81
+ /// @example scss - Полупрозрачные цвета
82
+ /// @debug get-color-brightness(rgba(0, 0, 0, 0.5)); // 0% (яркость не зависит от альфа-канала)
83
+ /// @debug get-color-brightness(rgba(255, 255, 255, 0.3)); // 100%
84
+ /// @debug get-color-brightness(rgba(128, 128, 128, 0.8)); // 50.196078431372555%
85
+ /// @param {Color} $color - Цвет для анализа яркости. Может
86
+ /// быть в любом формате, который поддерживает Sass (HEX,
87
+ /// RGB, HSL, имя цвета).
88
+ /// @return {Number} - Значение светлоты в процентах (0% - 100%).
89
+ /// Черный цвет вернет значение около 0%, белый - 100%,
90
+ /// серые тона - промежуточные значения в зависимости от
91
+ /// их светлоты.
92
+ @function get-color-brightness($color) {
93
+
94
+ // Проверка типа входного параметра: ожидается
95
+ // цветовое значение.
96
+ //
97
+ // Функция is-color() проверяет, является ли $color
98
+ // валидным цветом CSS.
99
+ // Поддерживаемые форматы: hex, rgb, rgba, hsl,
100
+ // hsla, названия цветов.
101
+ @if not is-color($color) {
102
+
103
+ // Если $color не является цветом, логируем ошибку
104
+ // через отладочное сообщение:
105
+ @return log-invalid-type(
106
+ 'get-color-brightness',
107
+ $color,
108
+ '$color',
109
+ 'color'
110
+ );
111
+
112
+ } @else {
113
+
114
+ // Основная логика выполняется только если $color
115
+ // является валидным цветом.
116
+ //
117
+ // Используем функцию color.channel() для извлечения
118
+ // компонента яркости:
119
+ // - Первый параметр: $color - исходный цвет
120
+ // - Второй параметр: "lightness" - извлекаем компонент
121
+ // яркости
122
+ // - Третий параметр: $space: hsl - указываем цветовое
123
+ // пространство HSL
124
+ //
125
+ // HSL (Hue, Saturation, Lightness) - цветовая модель:
126
+ // - Hue (оттенок): угол на цветовом круге (0-360deg)
127
+ // - Saturation (насыщенность): процент (0%-100%)
128
+ // - Lightness (яркость): процент (0%-100%)
129
+ //
130
+ // Возвращаемое значение: процент от 0% до 100%, где:
131
+ // - 0% = абсолютно черный
132
+ // - 100% = абсолютно белый
133
+ // - 50% = чистый цвет (без добавления черного или белого)
134
+ @return color.channel($color, "lightness", $space: hsl);
135
+
136
+ }
137
+
138
+ }
@@ -0,0 +1,178 @@
1
+ @use 'sass:color';
2
+ @use '../../loggers/log-invalid-type' as *;
3
+ @use '../../validators/type-of/is-list' as *;
4
+
5
+ /// Находит самый темный цвет в списке по значению lightness
6
+ /// в HSL-пространстве.
7
+ ///
8
+ /// Функция проходит по всем цветам в списке, вычисляет
9
+ /// lightness каждого цвета в HSL-пространстве и возвращает
10
+ /// цвет с наименьшим значением `lightness`.
11
+ ///
12
+ /// Если несколько цветов имеют одинаковое минимальное
13
+ /// значение `lightness`, возвращается первый найденный
14
+ /// такой цвет.
15
+ ///
16
+ /// Важные особенности функции:
17
+ /// - Использует HSL-пространство для вычисления lightness
18
+ /// - Значение `lightness` измеряется в процентах (0% - черный,
19
+ /// 100% - белый)
20
+ /// - Возвращает `null` для пустого списка
21
+ /// - Ожидает, что все элементы списка являются цветами
22
+ /// - Не проверяет тип элементов (используйте is-color-list()
23
+ /// для валидации)
24
+ /// - Использует локальные переменные с префиксом `$-` для
25
+ /// избежания конфликтов
26
+ /// ---
27
+ /// @name get-color-darkest
28
+ /// @group utilities-getters
29
+ /// @since 2025.12.27
30
+ /// @access public
31
+ /// @author Murad Rustamov (therteenten)
32
+ /// @link https://sourcecraft.dev/users/therteenten/overview SourceCraft - therteenten
33
+ /// @link https://sourcecraft.dev/omnisass/library SourceCraft - OmniSass
34
+ /// @link https://sass-lang.com/documentation/modules/color#channel См. также: Официальная документация Sass - Функция color.channel()
35
+ /// @link https://sass-lang.com/documentation/values/colors#hsl См. также: Официальная документация Sass - HSL цвета
36
+ /// @link https://developer.mozilla.org/en-US/docs/Web/CSS/color_value/hsl MDN Web Docs - CSS функция hsl()
37
+ /// @link https://css-tricks.com/snippets/sass/ См. также: CSS-Tricks - Коллекция сниппетов Sass
38
+ /// @link https://sass-guidelin.es/ru/#color-functions См. также: Sass Guidelines - Функции для работы с цветами
39
+ /// @link https://frontender.info/sass-colors/ См. также: Frontender Magazine - Работа с цветами в Sass
40
+ /// @link https://www.w3schools.com/sass/sass_functions_color.php См. также: W3Schools - Функции для работы с цветами в Sass
41
+ /// @link https://habr.com/ru/post/247881/ См. также: Habr - Статья "Sass для верстальщика: цвета"
42
+ /// @example scss - Поиск самого темного цвета
43
+ /// @debug get-color-darkest((#000000, #333333, #666666)); // #000000
44
+ /// @debug get-color-darkest((#ff0000, #00ff00, #0000ff)); // #ff000000
45
+ /// @debug get-color-darkest((hsl(0, 100%, 20%), hsl(0, 100%, 50%))); // hsl(0, 100%, 20%)
46
+ /// @example scss - Градации серого
47
+ /// @debug get-color-darkest((#ffffff, #cccccc, #999999, #666666, #333333, #000000)); // #000000
48
+ /// @debug get-color-darkest((#f8f9fa, #e9ecef, #dee2e6, #ced4da, #adb5bd)); // #adb5bd
49
+ /// @example scss - Разные цветовые пространства (конвертируются в HSL)
50
+ /// @debug get-color-darkest((rgb(0, 0, 0), rgb(100, 100, 100))); // rgb(0, 0, 0)
51
+ /// @debug get-color-darkest((#f00, #0f0, #00f)); // #f00
52
+ /// @debug get-color-darkest((hsl(0, 100%, 30%), hsl(120, 100%, 30%))); // hsl(0, 100%, 30%)
53
+ /// @example scss - Практическое использование для определения акцентного цвета
54
+ /// $brand-colors: (#3498db, #2ecc71, #e74c3c, #f1c40f);
55
+ /// $darkest-brand: get-color-darkest($brand-colors);
56
+ /// // $darkest-brand: #3498db (синий самый темный в HSL)
57
+ ///
58
+ /// .dark-element {
59
+ /// background-color: $darkest-brand;
60
+ /// color: white;
61
+ /// }
62
+ /// @example css - Результат
63
+ /// .dark-element {
64
+ /// background-color: #2ecc71;
65
+ /// color: white;
66
+ /// }
67
+ /// @example scss - Создание градиента от самого темного
68
+ /// $palette: (#ff6b6b, #4ecdc4, #45b7d1, #96ceb4, #ffeaa7);
69
+ /// $base-color: get-color-darkest($palette);
70
+ /// .gradient-box {
71
+ /// background: linear-gradient(135deg, $base-color, color.adjust($base-color, $lightness: 30%));
72
+ /// }
73
+ /// @example css - Результат
74
+ /// .gradient-box {
75
+ /// background: linear-gradient(135deg, #45b7d1, rgb(191.6637931034, 230.4827586207, 239.3362068966));
76
+ /// }
77
+ /// @example scss - Выбор цвета текста на темном фоне
78
+ /// $background-options: (#2c3e50, #34495e, #7f8c8d);
79
+ /// $darkest-bg: get-color-darkest($background-options);
80
+ ///
81
+ /// .card {
82
+ /// background: $darkest-bg;
83
+ /// color: if(color.channel($darkest-bg, "lightness", $space: hsl) < 50%, white, black);
84
+ /// }
85
+ /// @example css - Результат
86
+ /// .card {
87
+ /// background: #2c3e50;
88
+ /// color: white;
89
+ /// }
90
+ /// @example scss - Обработка пустых и некорректных списков
91
+ /// @debug get-color-darkest(()); // null
92
+ /// @debug get-color-darkest((#ff0000)); // #ff0000
93
+ ///
94
+ /// // Важно: функция не валидирует типы элементов!
95
+ /// @debug get-color-darkest((#ff0000, 10px, #0000ff)); // Ошибка при вычислении lightness
96
+ /// @param {List} $color-list - Список цветов для анализа.
97
+ /// Ожидается, что все элементы списка являются валидными
98
+ /// цветами в любом формате (hex, rgb, hsl, названия и т.д.).
99
+ /// @return {Color | Null} - Самый темный цвет из списка по
100
+ /// значению lightness в HSL-пространстве. Возвращает
101
+ /// `null`, если список пустой. Если несколько цветов
102
+ /// имеют одинаковую минимальную lightness, возвращает
103
+ /// первый из них.
104
+ /// @throws {Error} - Может выбросить ошибку, если в списке
105
+ /// встречаются элементы, не являющиеся цветами, при
106
+ /// попытке вызова `color.channel()`.
107
+ @function get-color-darkest($color-list) {
108
+
109
+ // Инициализация переменных для хранения результата поиска.
110
+ // - $-result: будет содержать самый темный цвет из списка
111
+ // - $-min-lightness: будет содержать минимальное значение
112
+ // яркости (наименьшая яркость = самый темный)
113
+ $-result: '';
114
+ $-min-lightness: null;
115
+
116
+ // Проверка типа входного параметра: ожидается список
117
+ // (list) или arglist цветов.
118
+ // Функция предназначена для работы со списком цветовых
119
+ // значений.
120
+ @if not is-list($color-list) {
121
+
122
+ // Если $color-list не является списком, возвращаем
123
+ // ошибку через стандартную функцию логирования. Это
124
+ // предотвращает дальнейшее выполнение с некорректными
125
+ // данными.
126
+ @return log-invalid-type(
127
+ 'get-color-darkest',
128
+ $color-list,
129
+ '$color-list',
130
+ ('list', 'arglist')
131
+ );
132
+
133
+ }
134
+
135
+ // Основная логика выполняется только если входной параметр
136
+ // прошел валидацию.
137
+ @else {
138
+
139
+ // Итерация по всем цветам в списке.
140
+ @each $-color in $color-list {
141
+
142
+ // Для каждого цвета вычисляем его яркость (lightness) в
143
+ // пространстве HSL.
144
+ // - color.channel() извлекает компонент яркости из цвета.
145
+ // - $space: hsl указывает использовать HSL цветовое
146
+ // пространство
147
+ // Результат: процентное значение от 0% до 100%.
148
+ // 0% = абсолютно черный, 100% = абсолютно белый.
149
+ $-lightness: color.channel($-color, "lightness", $space: hsl);
150
+
151
+ // Поиск цвета с минимальной яркостью (самого темного).
152
+ // Условие выполняется в двух случаях:
153
+ // 1. $-min-lightness == null: это первый обрабатываемый
154
+ // цвет в списке
155
+ // 2. $-lightness < $-min-lightness: текущий цвет темнее
156
+ // предыдущего найденного
157
+ @if $-min-lightness == null or $-lightness < $-min-lightness {
158
+
159
+ // Обновляем значения:
160
+ // - $-min-lightness: запоминаем новое минимальное значение
161
+ // яркости
162
+ // - $-result: сохраняем ссылку на самый темный цвет на
163
+ // данный момент
164
+ $-min-lightness: $-lightness;
165
+ $-result: $-color;
166
+
167
+ }
168
+
169
+ }
170
+
171
+ // Возвращаем самый темный цвет из списка.
172
+ // Если список был пустым, вернется начальное
173
+ // значение '' (пустая строка).
174
+ @return $-result;
175
+
176
+ }
177
+
178
+ }
@@ -0,0 +1,114 @@
1
+ @use 'sass:list';
2
+ @use '../../loggers/log-invalid-type' as *;
3
+ @use '../../validators/type-of/is-list' as *;
4
+
5
+ /// Возвращает последний элемент списка.
6
+ ///
7
+ /// Функция извлекает последний элемент из переданного
8
+ /// списка. Использует индекс `-1`, который в Sass
9
+ /// означает "последний элемент". Работает с любыми
10
+ /// типами списков: разделенными запятыми, пробелами
11
+ /// или скобками.
12
+ /// ---
13
+ /// @name get-list-item-end
14
+ /// @group utilities-getters
15
+ /// @since 2025.12.27
16
+ /// @access public
17
+ /// @author Sindre Sorhus
18
+ /// @author Murad Rustamov (therteenten)
19
+ /// @link https://github.com/sindresorhus GitHub - Sindre Sorhus
20
+ /// @link https://sourcecraft.dev/users/therteenten/overview SourceCraft - therteenten
21
+ /// @link https://sourcecraft.dev/omnisass/library SourceCraft - OmniSass
22
+ /// @link https://sass-lang.com/documentation/modules/list#nth См. также: Официальная документация Sass - Функция `list.nth()`
23
+ /// @link https://sass-lang.com/documentation/modules/list#slice См. также: Официальная документация Sass - Функция `list.slice()`
24
+ /// @link https://sass-lang.com/documentation/values/lists См. также: Официальная документация Sass - Тип данных "Списки" (`Lists`)
25
+ /// @link https://sass-lang.com/documentation/at-rules/function См. также: Официальная документация Sass - Правило `@function`
26
+ /// @link https://sass-lang.com/documentation/style-rules/declarations#custom-properties См. также: Документация Sass - Пользовательские функции
27
+ /// @link https://developer.mozilla.org/en-US/docs/Web/CSS/:last-child См. также: MDN Web Docs - Псевдокласс `:last-child`
28
+ /// @link https://developer.mozilla.org/en-US/docs/Web/CSS/:nth-last-child См. также: MDN Web Docs - Псевдокласс `:nth-last-child()`
29
+ /// @link https://www.w3schools.com/sass/sass_functions_list.php См. также: W3Schools - Функции для работы со списками в Sass
30
+ /// @link https://www.sass.hk/docs/ См. также: Китайская документация Sass - Полное руководство
31
+ /// @link https://sass-guidelin.es/ru/#functions См. также: Sass Guidelines - Руководство по написанию функций в Sass
32
+ /// @link https://github.com/sass/sass/blob/main/accepted/module-system.md См. также: GitHub - Документация по модульной системе Sass
33
+ /// @link https://stackoverflow.com/questions/12548035/sass-get-last-child-using-nth-child См. также: Stack Overflow - Как получить последний элемент в Sass
34
+ /// @link https://stackoverflow.com/questions/36885966/sass-get-first-item-from-a-list См. также: Stack Overflow - Получение первого и последнего элемента списка
35
+ /// @link https://css-tricks.com/snippets/sass/ См. также: CSS-Tricks - Коллекция сниппетов Sass
36
+ /// @link https://web.dev/learn/css/lists/ См. также: web.dev - Изучение CSS списков
37
+ /// @link https://frontender.info/sass-lists/ См. также: Frontender Magazine - Работа со списками в Sass
38
+ /// @link https://habr.com/ru/post/156549/ См. также: Habr - Статья "Sass для верстальщика: списки и циклы"
39
+ /// @link https://www.sitepoint.com/sass-basics-operators/ См. также: SitePoint - Основы Sass: операторы
40
+ /// @link https://www.freecodecamp.org/news/how-to-use-lists-in-sass/ См. также: freeCodeCamp - Как использовать списки в Sass
41
+ /// @link https://code.tutsplus.com/tutorials/understanding-sass-lists--cms-22020 См. также: Envato Tuts+ - Понимание списков в Sass
42
+ /// @link https://dev.to/kathryngrayson/using-sass-list-functions-4lp См. также: Dev.to - Использование функций для работы со списками в Sass
43
+ /// @link https://css-live.ru/vecssti-i-sovety/vse-o-spiskax-v-sass.html См. также: CSS-Live - Все о списках в Sass
44
+ /// @link https://itchief.ru/sass/cycles-and-lists См. также: itchief - Циклы и списки в Sass
45
+ /// @link https://htmlacademy.ru/blog/boost/tools/sass-3 См. также: HTML Academy - Sass: списки, циклы, условия
46
+ /// @link https://metanit.com/web/html5/13.6.php См. также: Metanit - Списки и циклы в Sass
47
+ /// @link https://ru.hexlet.io/courses/sass-basics/lessons/conditionals/theory_unit См. также: Hexlet - Условные операторы и списки в Sass
48
+ /// @link https://www.youtube.com/watch?v=roywYSEPSvc См. также: YouTube - Sass Tutorial #10 - Lists (The Net Ninja)
49
+ /// @link https://www.youtube.com/watch?v=BIz02qY5BRA См. также: YouTube - Sass списки и циклы (на русском)
50
+ /// @link https://codelabs.developers.google.com/codelabs/cloud-sass-cli#5 См. также: Google Codelabs - Создание пользовательских функций в Sass
51
+ /// @link https://www.npmjs.com/package/sass См. также: npm - Документация пакета Dart Sass
52
+ /// @link https://marketplace.visualstudio.com/items?itemName=Syler.sass-indented См. также: VS Code Marketplace - Поддержка синтаксиса Sass
53
+ /// @link https://stylelint.io/user-guide/rules/list/ См. также: Stylelint - Правила для работы со списками
54
+ /// @link https://sass-lang.com/documentation/js-api См. также: JavaScript API - Работа с Sass через JavaScript
55
+ /// @link https://sass-lang.com/documentation/cli/dart-sass См. также: CLI - Командная строка Dart Sass
56
+ /// @link https://sass-lang.com/documentation/breaking-changes/module-system См. также: Breaking Changes - Изменения в модульной системе
57
+ /// @link https://sass-lang.com/documentation/values/numbers#units См. также: Документация Sass - Числа и единицы измерения (отрицательные индексы)
58
+ /// @link https://sass-lang.com/documentation/values/strings См. также: Документация Sass - Строки
59
+ /// @link https://sass-lang.com/documentation/values/booleans См. также: Документация Sass - Логические значения
60
+ /// @link https://sass-lang.com/documentation/values/null См. также: Документация Sass - Значение `null`
61
+ /// @link https://sass-lang.com/documentation/values/maps См. также: Документация Sass - Карты (`maps`)
62
+ /// @link https://sass-lang.com/documentation/interpolation См. также: Документация Sass - Интерполяция
63
+ /// @example scss - Извлечение последнего элемента
64
+ /// @debug get-list-item-end(apple banana cherry); // cherry
65
+ /// @debug get-list-item-end((1, 2, 3, 4)); // 4
66
+ /// @debug get-list-item-end(red blue green); // green
67
+ /// @debug get-list-item-end(("one", "two", "three")); // "three"
68
+ /// @example scss - Использование для получения акцентного цвета
69
+ /// $colors: primary, secondary, accent, warning;
70
+ /// $accent-color: get-list-item-end($colors); // $accent-color: warning
71
+ /// @example scss - Краевые случаи
72
+ /// @debug get-list-item-end(()); // error
73
+ /// @debug get-list-item-end(none); // null
74
+ /// @debug get-list-item-end((single)); // single
75
+ /// @example scss - Получение последнего аргумента функции
76
+ /// @function example($args...) {
77
+ /// $last-arg: get-list-item-end($args);
78
+ /// @return $last-arg * 2;
79
+ /// }
80
+ /// @see get-list-item-start
81
+ /// @param {List} $list - Список, из которого нужно
82
+ /// извлечь последний элемент
83
+ /// @return {*} - Последний элемент списка. Возвращает
84
+ /// `null`, если список пустой.
85
+ /// @throws Не выбрасывает ошибок, возвращает
86
+ /// `null` для пустых списков
87
+ @function get-list-item-end($list) {
88
+
89
+ @if not is-list($list) {
90
+
91
+ // Валидация типа входного параметра.
92
+ // Функция ожидает получить список (list) или arglist.
93
+ @return log-invalid-type(
94
+ 'get-list-item-end',
95
+ $list,
96
+ '$list',
97
+ ('list', 'arglist')
98
+ );
99
+
100
+ } @else {
101
+
102
+ // Основная логика выполняется только если $list является
103
+ // корректным списком.
104
+ //
105
+ // Используем встроенную функцию Sass list.nth():
106
+ // - Извлекает элемент по указанному индексу (в данном
107
+ // случае -1 - последний)
108
+ // - Для пустого списка возвращает null
109
+ // - Сохраняет тип и значение элемента без изменений
110
+ @return list.nth($list, -1);
111
+
112
+ }
113
+
114
+ }