@de-kit/st-ui 0.1.8 → 0.1.10
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.
- package/README.md +145 -143
- package/dist/components/button/button.cjs +26 -13
- package/dist/components/button/button.cjs.map +1 -1
- package/dist/components/button/button.d.cts +9 -8
- package/dist/components/button/button.d.ts +9 -8
- package/dist/components/button/button.js +29 -16
- package/dist/components/button/button.js.map +1 -1
- package/dist/components/button/button.scss +213 -147
- package/dist/components/button/index.d.cts +2 -2
- package/dist/components/button/index.d.ts +2 -2
- package/dist/components/checkbox/checkbox.cjs.map +1 -1
- package/dist/components/checkbox/checkbox.js.map +1 -1
- package/dist/components/checkbox/checkbox.scss +137 -137
- package/dist/components/field/field-context.cjs.map +1 -1
- package/dist/components/field/field-context.js.map +1 -1
- package/dist/components/field/field.cjs.map +1 -1
- package/dist/components/field/field.js.map +1 -1
- package/dist/components/field/field.scss +43 -43
- package/dist/components/input/input.cjs.map +1 -1
- package/dist/components/input/input.js.map +1 -1
- package/dist/components/input/input.scss +127 -127
- package/dist/components/radio/radio.cjs.map +1 -1
- package/dist/components/radio/radio.js.map +1 -1
- package/dist/components/radio/radio.scss +144 -144
- package/dist/components/spinner/spinner.cjs.map +1 -1
- package/dist/components/spinner/spinner.js.map +1 -1
- package/dist/components/spinner/spinner.scss +29 -29
- package/dist/components/textarea/textarea.cjs.map +1 -1
- package/dist/components/textarea/textarea.js.map +1 -1
- package/dist/components/textarea/textarea.scss +85 -85
- package/dist/icons/svg.cjs.map +1 -1
- package/dist/icons/svg.js.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/lib/cn.cjs.map +1 -1
- package/dist/lib/cn.js.map +1 -1
- package/dist/lib/slot.cjs +100 -0
- package/dist/lib/slot.cjs.map +1 -0
- package/dist/lib/slot.js +100 -0
- package/dist/lib/slot.js.map +1 -0
- package/dist/styles/global.scss +201 -201
- package/dist/styles/mixins.scss +51 -51
- package/dist/styles/vars.scss +87 -87
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot.js","names":[],"sources":["../../src/lib/slot.tsx"],"sourcesContent":["import {\n forwardRef,\n isValidElement,\n type CSSProperties,\n type ElementType,\n type ForwardedRef,\n type MouseEventHandler,\n type ReactNode,\n type Ref,\n} from 'react';\n\nimport { cn } from './cn';\n\ninterface SlotProps {\n children?: ReactNode;\n className?: string;\n style?: CSSProperties;\n onClick?: MouseEventHandler<HTMLElement>;\n disabled?: boolean;\n [key: string]: unknown;\n}\n\ntype AnyHandler = (...args: unknown[]) => void;\n\nconst isHandlerKey = (key: string) => /^on[A-Z]/.test(key);\n\nconst asHandler = (value: unknown): AnyHandler | undefined => {\n if (typeof value !== 'function') return undefined;\n return value as AnyHandler;\n};\n\nconst asClassName = (value: unknown) => {\n if (typeof value === 'string' || typeof value === 'number')\n return String(value);\n return undefined;\n};\n\nconst asStyle = (value: unknown): CSSProperties | undefined => {\n if (!value || typeof value !== 'object' || Array.isArray(value))\n return undefined;\n return value as CSSProperties;\n};\n\nconst isPrevented = (event: unknown) =>\n typeof event === 'object' &&\n event !== null &&\n 'defaultPrevented' in event &&\n event.defaultPrevented === true;\n\nconst composeHandlers = (childHandler: unknown, slotHandler: unknown) => {\n const child = asHandler(childHandler);\n const slot = asHandler(slotHandler);\n if (!child) return slot;\n if (!slot) return child;\n\n return (...args: unknown[]) => {\n child(...args);\n if (!isPrevented(args[0])) slot(...args);\n };\n};\n\nconst warnsOnRefRead = (getter: PropertyDescriptor['get']) => {\n if (!getter || !('isReactWarning' in getter)) return false;\n return Boolean((getter as { isReactWarning?: boolean }).isReactWarning);\n};\n\nconst readRef = (source: object): Ref<HTMLElement> | undefined => {\n if (!('ref' in source)) return undefined;\n const value = (source as { ref?: Ref<HTMLElement> | null }).ref;\n return value ?? undefined;\n};\n\n// React 18 кладёт ref на элемент, React 19 — в props. Геттер-заглушка\n// ругается при чтении «не той» стороны, поэтому берём ту, что без предупреждения.\nconst getElementRef = (element: object) => {\n const props =\n 'props' in element && element.props && typeof element.props === 'object'\n ? element.props\n : {};\n const propsGetter = Object.getOwnPropertyDescriptor(props, 'ref')?.get;\n if (warnsOnRefRead(propsGetter)) return readRef(element);\n\n const elementGetter = Object.getOwnPropertyDescriptor(element, 'ref')?.get;\n if (warnsOnRefRead(elementGetter)) return readRef(props);\n\n return readRef(props) ?? readRef(element);\n};\n\nconst mergeProps = (\n childProps: Record<string, unknown>,\n slotProps: SlotProps,\n) => {\n const merged: Record<string, unknown> = { ...slotProps };\n\n for (const key of Object.keys(childProps)) {\n if (key === 'ref') continue;\n\n const childValue = childProps[key];\n const slotValue = slotProps[key];\n\n if (key === 'className') continue;\n\n if (key === 'style') {\n merged.style = { ...asStyle(slotValue), ...asStyle(childValue) };\n continue;\n }\n\n if (key === 'onClick') continue;\n\n if (isHandlerKey(key)) {\n merged[key] = composeHandlers(childValue, slotValue);\n continue;\n }\n\n if (\n (key === 'disabled' && slotProps.disabled) ||\n (key === 'aria-busy' && slotProps['aria-busy']) ||\n (key === 'aria-disabled' && slotProps['aria-disabled'])\n ) {\n continue;\n }\n\n merged[key] = childValue;\n }\n\n const className = cn(\n asClassName(slotProps.className),\n asClassName(childProps.className),\n );\n if (className) merged.className = className;\n if (slotProps.onClick) merged.onClick = slotProps.onClick;\n\n return merged;\n};\n\nconst attachRef = (\n ref: ForwardedRef<HTMLElement> | Ref<HTMLElement> | undefined,\n node: HTMLElement | null,\n) => {\n if (typeof ref === 'function') return ref(node);\n if (ref) ref.current = node;\n return undefined;\n};\n\n/** Сливает пропы в единственного ребёнка, без своего DOM-узла. Как Radix Slot. */\nexport const Slot = forwardRef(function Slot(\n props: SlotProps,\n slotRef: ForwardedRef<HTMLElement>,\n) {\n const { children, ...slotProps } = props;\n\n if (!isValidElement(children)) {\n throw new Error('Button с asChild ждёт ровно один React-элемент.');\n }\n\n const childProps = children.props as Record<string, unknown>;\n const childRef = getElementRef(children);\n const Comp = children.type as ElementType;\n const merged = mergeProps(childProps, slotProps);\n\n return (\n <Comp\n {...merged}\n ref={(node: HTMLElement | null) => {\n const slotCleanup = attachRef(slotRef, node);\n const childCleanup = attachRef(childRef, node);\n if (\n typeof slotCleanup !== 'function' &&\n typeof childCleanup !== 'function'\n ) {\n return undefined;\n }\n\n return () => {\n if (typeof slotCleanup === 'function') slotCleanup();\n else attachRef(slotRef, null);\n if (typeof childCleanup === 'function') childCleanup();\n else attachRef(childRef, null);\n };\n }}\n />\n );\n});\n"],"mappings":"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"}
|
package/dist/styles/global.scss
CHANGED
|
@@ -1,201 +1,201 @@
|
|
|
1
|
-
// База приложения. Шрифт Inter подключает хост — файлы лежат в splittest-frontend/src/app/fonts.
|
|
2
|
-
// Токены (`--color-*`) подключает вход пакета, этот файл их не эмитит.
|
|
3
|
-
@use './mixins.scss' as mixins;
|
|
4
|
-
|
|
5
|
-
:root {
|
|
6
|
-
--window-max-height: 100vh;
|
|
7
|
-
--wrapper-padding: 20px;
|
|
8
|
-
|
|
9
|
-
@include mixins.min-width(md) {
|
|
10
|
-
--wrapper-padding: 30px;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
*,
|
|
15
|
-
*:before,
|
|
16
|
-
*:after {
|
|
17
|
-
box-sizing: border-box;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
* {
|
|
21
|
-
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
html,
|
|
25
|
-
body {
|
|
26
|
-
height: 100%;
|
|
27
|
-
scrollbar-gutter: stable;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
body {
|
|
31
|
-
display: flex;
|
|
32
|
-
flex-direction: column;
|
|
33
|
-
margin: 0;
|
|
34
|
-
font-family: var(--font-sans);
|
|
35
|
-
-webkit-font-smoothing: antialiased;
|
|
36
|
-
-moz-osx-font-smoothing: grayscale;
|
|
37
|
-
color: var(--color-foreground);
|
|
38
|
-
background-color: var(--color-background);
|
|
39
|
-
font-size: var(--text-sm);
|
|
40
|
-
line-height: var(--text-sm--line-height);
|
|
41
|
-
font-weight: 400;
|
|
42
|
-
|
|
43
|
-
&::after {
|
|
44
|
-
content: '';
|
|
45
|
-
display: block;
|
|
46
|
-
background-color: var(--color-overlay);
|
|
47
|
-
position: fixed;
|
|
48
|
-
left: 0;
|
|
49
|
-
top: 0;
|
|
50
|
-
right: 0;
|
|
51
|
-
bottom: 0;
|
|
52
|
-
z-index: 100;
|
|
53
|
-
opacity: 0;
|
|
54
|
-
visibility: hidden;
|
|
55
|
-
transition:
|
|
56
|
-
opacity 0.3s ease,
|
|
57
|
-
visibility 0.3s ease;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
.body {
|
|
62
|
-
&--close {
|
|
63
|
-
height: 100vh;
|
|
64
|
-
overflow-y: hidden;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
&--modal {
|
|
68
|
-
&::after {
|
|
69
|
-
opacity: 1;
|
|
70
|
-
visibility: visible;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
#root {
|
|
76
|
-
display: flex;
|
|
77
|
-
flex-direction: column;
|
|
78
|
-
height: 100%;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.main {
|
|
82
|
-
flex: 1 0 auto;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
.wrapper {
|
|
86
|
-
min-width: 340px;
|
|
87
|
-
width: 100%;
|
|
88
|
-
margin-left: auto;
|
|
89
|
-
margin-right: auto;
|
|
90
|
-
padding-left: var(--wrapper-padding);
|
|
91
|
-
padding-right: var(--wrapper-padding);
|
|
92
|
-
|
|
93
|
-
@include mixins.min-width(md) {
|
|
94
|
-
max-width: 680px;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
@include mixins.min-width(lg) {
|
|
98
|
-
max-width: 1000px;
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
.scroll-block::-webkit-scrollbar {
|
|
103
|
-
-webkit-appearance: none;
|
|
104
|
-
width: 8px;
|
|
105
|
-
height: 8px;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
// Ползунок — производная от текста, обводка — от фона: в тёмной теме
|
|
109
|
-
// ползунок светлеет вместе с ней, как и остальные серые в этом файле.
|
|
110
|
-
.scroll-block::-webkit-scrollbar-thumb {
|
|
111
|
-
border-radius: 4px;
|
|
112
|
-
background-color: color-mix(
|
|
113
|
-
in srgb,
|
|
114
|
-
var(--color-foreground) 24%,
|
|
115
|
-
var(--color-background)
|
|
116
|
-
);
|
|
117
|
-
box-shadow: 0 0 1px
|
|
118
|
-
color-mix(in srgb, var(--color-background) 50%, transparent);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
a {
|
|
122
|
-
text-decoration: none;
|
|
123
|
-
transition: color 0.3s ease;
|
|
124
|
-
color: var(--color-foreground);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
button {
|
|
128
|
-
color: var(--color-foreground);
|
|
129
|
-
font-size: var(--text-sm);
|
|
130
|
-
font-family: var(--font-sans);
|
|
131
|
-
|
|
132
|
-
&:not(:disabled) {
|
|
133
|
-
cursor: pointer;
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
img {
|
|
138
|
-
display: block;
|
|
139
|
-
max-width: 100%;
|
|
140
|
-
max-height: 100%;
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
table {
|
|
144
|
-
width: 100%;
|
|
145
|
-
border-collapse: collapse;
|
|
146
|
-
|
|
147
|
-
tr {
|
|
148
|
-
vertical-align: top;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
td {
|
|
152
|
-
word-break: break-word;
|
|
153
|
-
border-top: 1px solid var(--color-border);
|
|
154
|
-
padding: 15px 0;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
tr:last-of-type td {
|
|
158
|
-
border-bottom: 1px solid var(--color-border);
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
th {
|
|
162
|
-
color: var(--color-muted-foreground);
|
|
163
|
-
font-size: var(--text-xs);
|
|
164
|
-
line-height: var(--text-xs--line-height);
|
|
165
|
-
text-align: left;
|
|
166
|
-
font-weight: normal;
|
|
167
|
-
padding: 15px 0;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
h1,
|
|
172
|
-
h2,
|
|
173
|
-
h3 {
|
|
174
|
-
text-align: left;
|
|
175
|
-
font-weight: 900;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
h1 {
|
|
179
|
-
font-size: var(--text-2xl);
|
|
180
|
-
line-height: var(--text-2xl--line-height);
|
|
181
|
-
|
|
182
|
-
@include mixins.min-width(md) {
|
|
183
|
-
font-size: var(--text-3xl);
|
|
184
|
-
line-height: var(--text-3xl--line-height);
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
h2 {
|
|
189
|
-
font-size: var(--text-2xl);
|
|
190
|
-
line-height: var(--text-2xl--line-height);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
h3 {
|
|
194
|
-
font-size: var(--text-lg);
|
|
195
|
-
line-height: var(--text-lg--line-height);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
h4 {
|
|
199
|
-
font-size: var(--text-sm);
|
|
200
|
-
line-height: var(--text-sm--line-height);
|
|
201
|
-
}
|
|
1
|
+
// База приложения. Шрифт Inter подключает хост — файлы лежат в splittest-frontend/src/app/fonts.
|
|
2
|
+
// Токены (`--color-*`) подключает вход пакета, этот файл их не эмитит.
|
|
3
|
+
@use './mixins.scss' as mixins;
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--window-max-height: 100vh;
|
|
7
|
+
--wrapper-padding: 20px;
|
|
8
|
+
|
|
9
|
+
@include mixins.min-width(md) {
|
|
10
|
+
--wrapper-padding: 30px;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
*,
|
|
15
|
+
*:before,
|
|
16
|
+
*:after {
|
|
17
|
+
box-sizing: border-box;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
* {
|
|
21
|
+
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
html,
|
|
25
|
+
body {
|
|
26
|
+
height: 100%;
|
|
27
|
+
scrollbar-gutter: stable;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
body {
|
|
31
|
+
display: flex;
|
|
32
|
+
flex-direction: column;
|
|
33
|
+
margin: 0;
|
|
34
|
+
font-family: var(--font-sans);
|
|
35
|
+
-webkit-font-smoothing: antialiased;
|
|
36
|
+
-moz-osx-font-smoothing: grayscale;
|
|
37
|
+
color: var(--color-foreground);
|
|
38
|
+
background-color: var(--color-background);
|
|
39
|
+
font-size: var(--text-sm);
|
|
40
|
+
line-height: var(--text-sm--line-height);
|
|
41
|
+
font-weight: 400;
|
|
42
|
+
|
|
43
|
+
&::after {
|
|
44
|
+
content: '';
|
|
45
|
+
display: block;
|
|
46
|
+
background-color: var(--color-overlay);
|
|
47
|
+
position: fixed;
|
|
48
|
+
left: 0;
|
|
49
|
+
top: 0;
|
|
50
|
+
right: 0;
|
|
51
|
+
bottom: 0;
|
|
52
|
+
z-index: 100;
|
|
53
|
+
opacity: 0;
|
|
54
|
+
visibility: hidden;
|
|
55
|
+
transition:
|
|
56
|
+
opacity 0.3s ease,
|
|
57
|
+
visibility 0.3s ease;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.body {
|
|
62
|
+
&--close {
|
|
63
|
+
height: 100vh;
|
|
64
|
+
overflow-y: hidden;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
&--modal {
|
|
68
|
+
&::after {
|
|
69
|
+
opacity: 1;
|
|
70
|
+
visibility: visible;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#root {
|
|
76
|
+
display: flex;
|
|
77
|
+
flex-direction: column;
|
|
78
|
+
height: 100%;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
.main {
|
|
82
|
+
flex: 1 0 auto;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.wrapper {
|
|
86
|
+
min-width: 340px;
|
|
87
|
+
width: 100%;
|
|
88
|
+
margin-left: auto;
|
|
89
|
+
margin-right: auto;
|
|
90
|
+
padding-left: var(--wrapper-padding);
|
|
91
|
+
padding-right: var(--wrapper-padding);
|
|
92
|
+
|
|
93
|
+
@include mixins.min-width(md) {
|
|
94
|
+
max-width: 680px;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
@include mixins.min-width(lg) {
|
|
98
|
+
max-width: 1000px;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.scroll-block::-webkit-scrollbar {
|
|
103
|
+
-webkit-appearance: none;
|
|
104
|
+
width: 8px;
|
|
105
|
+
height: 8px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Ползунок — производная от текста, обводка — от фона: в тёмной теме
|
|
109
|
+
// ползунок светлеет вместе с ней, как и остальные серые в этом файле.
|
|
110
|
+
.scroll-block::-webkit-scrollbar-thumb {
|
|
111
|
+
border-radius: 4px;
|
|
112
|
+
background-color: color-mix(
|
|
113
|
+
in srgb,
|
|
114
|
+
var(--color-foreground) 24%,
|
|
115
|
+
var(--color-background)
|
|
116
|
+
);
|
|
117
|
+
box-shadow: 0 0 1px
|
|
118
|
+
color-mix(in srgb, var(--color-background) 50%, transparent);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
a {
|
|
122
|
+
text-decoration: none;
|
|
123
|
+
transition: color 0.3s ease;
|
|
124
|
+
color: var(--color-foreground);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
button {
|
|
128
|
+
color: var(--color-foreground);
|
|
129
|
+
font-size: var(--text-sm);
|
|
130
|
+
font-family: var(--font-sans);
|
|
131
|
+
|
|
132
|
+
&:not(:disabled) {
|
|
133
|
+
cursor: pointer;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
img {
|
|
138
|
+
display: block;
|
|
139
|
+
max-width: 100%;
|
|
140
|
+
max-height: 100%;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
table {
|
|
144
|
+
width: 100%;
|
|
145
|
+
border-collapse: collapse;
|
|
146
|
+
|
|
147
|
+
tr {
|
|
148
|
+
vertical-align: top;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
td {
|
|
152
|
+
word-break: break-word;
|
|
153
|
+
border-top: 1px solid var(--color-border);
|
|
154
|
+
padding: 15px 0;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
tr:last-of-type td {
|
|
158
|
+
border-bottom: 1px solid var(--color-border);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
th {
|
|
162
|
+
color: var(--color-muted-foreground);
|
|
163
|
+
font-size: var(--text-xs);
|
|
164
|
+
line-height: var(--text-xs--line-height);
|
|
165
|
+
text-align: left;
|
|
166
|
+
font-weight: normal;
|
|
167
|
+
padding: 15px 0;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
h1,
|
|
172
|
+
h2,
|
|
173
|
+
h3 {
|
|
174
|
+
text-align: left;
|
|
175
|
+
font-weight: 900;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
h1 {
|
|
179
|
+
font-size: var(--text-2xl);
|
|
180
|
+
line-height: var(--text-2xl--line-height);
|
|
181
|
+
|
|
182
|
+
@include mixins.min-width(md) {
|
|
183
|
+
font-size: var(--text-3xl);
|
|
184
|
+
line-height: var(--text-3xl--line-height);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
h2 {
|
|
189
|
+
font-size: var(--text-2xl);
|
|
190
|
+
line-height: var(--text-2xl--line-height);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
h3 {
|
|
194
|
+
font-size: var(--text-lg);
|
|
195
|
+
line-height: var(--text-lg--line-height);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
h4 {
|
|
199
|
+
font-size: var(--text-sm);
|
|
200
|
+
line-height: var(--text-sm--line-height);
|
|
201
|
+
}
|
package/dist/styles/mixins.scss
CHANGED
|
@@ -1,51 +1,51 @@
|
|
|
1
|
-
@use 'sass:list';
|
|
2
|
-
@use 'sass:map';
|
|
3
|
-
@use 'sass:math';
|
|
4
|
-
@use 'sass:meta';
|
|
5
|
-
|
|
6
|
-
// Брейкпоинты для адаптивной вёрстки и единственный их источник: vars.scss
|
|
7
|
-
// генерирует из этого же списка --breakpoint-*. Отдельный список нужен потому,
|
|
8
|
-
// что в @media custom properties не работают.
|
|
9
|
-
$breakpoints: (
|
|
10
|
-
sm: 480px,
|
|
11
|
-
md: 680px,
|
|
12
|
-
lg: 1000px,
|
|
13
|
-
xl: 1200px,
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
// Единицы, которые понимает @media. Проверяем их, потому что sass разбирает
|
|
17
|
-
// имя вроде `2xl` как число 2 с единицей xl: без проверки оно уехало бы в
|
|
18
|
-
// @media как есть и правило молча пропало бы.
|
|
19
|
-
$-length-units: 'px', 'em', 'rem';
|
|
20
|
-
|
|
21
|
-
// Имя брейкпоинта или произвольный размер: breakpoint(md), breakpoint(900px).
|
|
22
|
-
// Список проверяем первым, иначе имя, начинающееся с цифры, до него не дойдёт.
|
|
23
|
-
@function breakpoint($point) {
|
|
24
|
-
@if map.has-key($breakpoints, $point) {
|
|
25
|
-
@return map.get($breakpoints, $point);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
@if meta.type-of($point) ==
|
|
29
|
-
'number' and
|
|
30
|
-
list.index($-length-units, math.unit($point))
|
|
31
|
-
{
|
|
32
|
-
@return $point;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
@error 'Нет брейкпоинта «#{$point}». Есть: #{map.keys($breakpoints)} или размер в px, em, rem.';
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// От брейкпоинта и шире, включая его.
|
|
39
|
-
@mixin min-width($point) {
|
|
40
|
-
@media (min-width: breakpoint($point)) {
|
|
41
|
-
@content;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Уже брейкпоинта, не включая его: граница 679.98px, а не 680px, иначе на
|
|
46
|
-
// ровно 680px сработали бы оба правила сразу.
|
|
47
|
-
@mixin max-width($point) {
|
|
48
|
-
@media (max-width: (breakpoint($point) - 0.02px)) {
|
|
49
|
-
@content;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
1
|
+
@use 'sass:list';
|
|
2
|
+
@use 'sass:map';
|
|
3
|
+
@use 'sass:math';
|
|
4
|
+
@use 'sass:meta';
|
|
5
|
+
|
|
6
|
+
// Брейкпоинты для адаптивной вёрстки и единственный их источник: vars.scss
|
|
7
|
+
// генерирует из этого же списка --breakpoint-*. Отдельный список нужен потому,
|
|
8
|
+
// что в @media custom properties не работают.
|
|
9
|
+
$breakpoints: (
|
|
10
|
+
sm: 480px,
|
|
11
|
+
md: 680px,
|
|
12
|
+
lg: 1000px,
|
|
13
|
+
xl: 1200px,
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
// Единицы, которые понимает @media. Проверяем их, потому что sass разбирает
|
|
17
|
+
// имя вроде `2xl` как число 2 с единицей xl: без проверки оно уехало бы в
|
|
18
|
+
// @media как есть и правило молча пропало бы.
|
|
19
|
+
$-length-units: 'px', 'em', 'rem';
|
|
20
|
+
|
|
21
|
+
// Имя брейкпоинта или произвольный размер: breakpoint(md), breakpoint(900px).
|
|
22
|
+
// Список проверяем первым, иначе имя, начинающееся с цифры, до него не дойдёт.
|
|
23
|
+
@function breakpoint($point) {
|
|
24
|
+
@if map.has-key($breakpoints, $point) {
|
|
25
|
+
@return map.get($breakpoints, $point);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@if meta.type-of($point) ==
|
|
29
|
+
'number' and
|
|
30
|
+
list.index($-length-units, math.unit($point))
|
|
31
|
+
{
|
|
32
|
+
@return $point;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@error 'Нет брейкпоинта «#{$point}». Есть: #{map.keys($breakpoints)} или размер в px, em, rem.';
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// От брейкпоинта и шире, включая его.
|
|
39
|
+
@mixin min-width($point) {
|
|
40
|
+
@media (min-width: breakpoint($point)) {
|
|
41
|
+
@content;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Уже брейкпоинта, не включая его: граница 679.98px, а не 680px, иначе на
|
|
46
|
+
// ровно 680px сработали бы оба правила сразу.
|
|
47
|
+
@mixin max-width($point) {
|
|
48
|
+
@media (max-width: (breakpoint($point) - 0.02px)) {
|
|
49
|
+
@content;
|
|
50
|
+
}
|
|
51
|
+
}
|