@elcrm/form 0.0.76 → 0.0.78

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/package.json CHANGED
@@ -1,18 +1,34 @@
1
1
  {
2
2
  "name": "@elcrm/form",
3
- "version": "0.0.76",
3
+ "version": "0.0.78",
4
4
  "description": "React-компоненты полей формы и хук useForm для elCRM: текст, даты, маски, деньги, селект, связка с формой по имени поля (tree-shakeable ESM).",
5
5
  "type": "module",
6
6
  "author": "MaSkal <dev@elcrm.online>",
7
7
  "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/elcrm-lib/elcrm.form.git"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/elcrm-lib/elcrm.form/issues"
14
+ },
15
+ "homepage": "https://www.npmjs.com/package/@elcrm/form",
16
+ "publishConfig": {
17
+ "access": "public"
18
+ },
19
+ "engines": {
20
+ "node": ">=18"
21
+ },
8
22
  "files": [
9
- "dist",
10
- "src/lib/styles"
23
+ "dist"
11
24
  ],
12
25
  "keywords": [
13
26
  "elcrm",
14
27
  "form",
15
- "react"
28
+ "react",
29
+ "fields",
30
+ "useForm",
31
+ "input"
16
32
  ],
17
33
  "sideEffects": [
18
34
  "./dist/index.js",
@@ -60,38 +76,53 @@
60
76
  },
61
77
  "./style.css": {
62
78
  "import": "./dist/style.css",
63
- "require": "./dist/style.css"
79
+ "require": "./dist/style.css",
80
+ "default": "./dist/style.css"
64
81
  },
65
82
  "./light.css": {
66
- "import": "./src/lib/styles/light.css",
67
- "require": "./src/lib/styles/light.css"
83
+ "import": "./dist/light.css",
84
+ "require": "./dist/light.css",
85
+ "default": "./dist/light.css"
68
86
  },
69
87
  "./dark.css": {
70
- "import": "./src/lib/styles/dark.css",
71
- "require": "./src/lib/styles/dark.css"
88
+ "import": "./dist/dark.css",
89
+ "require": "./dist/dark.css",
90
+ "default": "./dist/dark.css"
72
91
  },
73
92
  "./dist/style.css": {
74
93
  "import": "./dist/style.css",
75
- "require": "./dist/style.css"
76
- }
94
+ "require": "./dist/style.css",
95
+ "default": "./dist/style.css"
96
+ },
97
+ "./package.json": "./package.json"
77
98
  },
78
99
  "scripts": {
79
100
  "dev": "vite --config test/vite.config.ts",
80
- "prepublishOnly": "npm run build",
81
- "build": "vite build && node scripts/merge-dist-css.mjs && node scripts/postbuild-styles.mjs && vite build --config vite.umd.config.ts",
101
+ "build": "node scripts/build.mjs",
82
102
  "test": "vitest run",
83
103
  "test:watch": "vitest",
84
104
  "test:build": "vite build --config test/vite.config.ts",
85
- "test:preview": "vite preview --config test/vite.config.ts"
105
+ "test:preview": "vite preview --config test/vite.config.ts",
106
+ "prepublishOnly": "vitest run && node scripts/build.mjs",
107
+ "pack:check": "npm pack --dry-run"
86
108
  },
87
109
  "peerDependencies": {
88
- "react": ">=18",
89
- "react-dom": ">=18"
110
+ "@types/react": ">=18.0.0",
111
+ "react": ">=18.0.0",
112
+ "react-dom": ">=18.0.0"
113
+ },
114
+ "peerDependenciesMeta": {
115
+ "@types/react": {
116
+ "optional": true
117
+ }
90
118
  },
91
119
  "devDependencies": {
92
120
  "@elcrm/storybook": "^0.0.3",
93
121
  "@testing-library/dom": "^10.4.1",
122
+ "@testing-library/jest-dom": "^6.6.3",
94
123
  "@testing-library/react": "^16.3.2",
124
+ "@testing-library/user-event": "^14.6.1",
125
+ "@types/node": "^22.13.10",
95
126
  "@types/react": "^19.2.14",
96
127
  "@types/react-dom": "^19.2.3",
97
128
  "@vitejs/plugin-react": "^6.0.1",
@@ -99,7 +130,11 @@
99
130
  "react": "^19.2.4",
100
131
  "react-dom": "^19.2.4",
101
132
  "sass-embedded": "^1.98.0",
133
+ "typescript": "^5.8.2",
102
134
  "vite": "^8.0.1",
135
+ "vite-plugin-dts": "^4.0.3",
136
+ "vite-plugin-dynamic-import": "^1.6.0",
137
+ "vite-plugin-lib-inject-css": "^2.1.1",
103
138
  "vitest": "^4.1.0"
104
139
  }
105
140
  }
@@ -1,434 +0,0 @@
1
- .l {
2
- display: flex;
3
- flex-direction: column;
4
- position: relative;
5
- min-width: var(--field-width);
6
- gap: var(--field-block-gap, 0);
7
- margin: 0;
8
- padding: 0;
9
- & > dt,
10
- & > dd {
11
- margin: 0;
12
- }
13
- &[data-field="group"] {
14
- & div {
15
- cursor: pointer;
16
- border-bottom: var(--field-border);
17
- margin: 0;
18
- padding: var(--field-padding);
19
- }
20
- & div:last-child {
21
- border-bottom: 0;
22
- }
23
- }
24
- /* contentEditable: псевдо-placeholder — тот же вес и насыщенность, что у нативного ::placeholder */
25
- & [placeholder]:empty:before {
26
- content: attr(placeholder);
27
- display: block;
28
- color: var(--field-placeholder);
29
- font-weight: 400;
30
- font-style: normal;
31
- opacity: 1;
32
- }
33
- & [placeholder]:focus:before {
34
- display: none;
35
- }
36
- }
37
-
38
- .f {
39
- box-sizing: border-box;
40
- display: flex;
41
- align-items: center;
42
- gap: var(--field-icon-gap, 10px);
43
- border: var(--field-border);
44
- border-radius: var(--field-radius);
45
- overflow: hidden;
46
- background: var(--field-background);
47
- color: var(--field-color);
48
- /* Внутренний отступ теперь на контейнере dd (.f), а не на дочернем div */
49
- padding: var(--control-inner-padding, 0 var(--field-side-padding, 14px));
50
- transition:
51
- border-color 0.16s ease,
52
- box-shadow 0.16s ease,
53
- background-color 0.16s ease,
54
- opacity 0.16s ease;
55
- &:hover {
56
- border-color: var(--field-border-hover, var(--field-border));
57
- }
58
- &:focus-within {
59
- border-color: var(--field-border-focus, var(--field-border));
60
- box-shadow: 0 0 0 3px var(--field-focus-ring, #0000);
61
- background: var(--field-background-focus, var(--field-background));
62
- }
63
- /* при ошибке оставляем фон ошибки, не подсветку обычного фокуса */
64
- &.e:focus-within {
65
- background: var(--field-error-background);
66
- color: var(--field-error-color);
67
- }
68
- &[data-disabled="true"] {
69
- background: var(--field-background-disabled, var(--field-background));
70
- border-color: var(--field-border-disabled, var(--field-border));
71
- color: var(--field-color-disabled, var(--field-placeholder));
72
- cursor: not-allowed;
73
- opacity: 0.85;
74
- }
75
- &[data-disabled="true"] > * {
76
- cursor: not-allowed;
77
- }
78
- & > div {
79
- outline: 0;
80
-
81
- flex: 1;
82
- margin: 0;
83
- min-height: var(--field-height);
84
- line-height: calc(var(--field-height) - 2px);
85
- padding: 0;
86
- font-size: var(--control-font-size, 14px);
87
- text-wrap: pretty;
88
-
89
- &::selection {
90
- background: var(--field-selection-bg, #b3d4fc);
91
- color: var(--field-selection-color, inherit);
92
- }
93
- }
94
- & > :not(div) {
95
- display: inline-flex;
96
- align-items: center;
97
- justify-content: center;
98
- flex: 0 0 auto;
99
- color: var(--field-icon-color, var(--field-placeholder));
100
- & svg {
101
- width: 20px;
102
- height: 20px;
103
- }
104
- }
105
-
106
- /*
107
- Нативный placeholder: без UA-«обесцвечивания» (Firefox/WebKit снижают opacity по умолчанию).
108
- Цвет = --field-placeholder, как у [placeholder]:empty:before у contentEditable.
109
- */
110
- input::placeholder,
111
- textarea::placeholder {
112
- color: var(--field-placeholder);
113
- opacity: 1;
114
- font-weight: 400;
115
- }
116
- input::-webkit-input-placeholder,
117
- textarea::-webkit-input-placeholder {
118
- color: var(--field-placeholder);
119
- opacity: 1;
120
- font-weight: 400;
121
- }
122
- input::-moz-placeholder,
123
- textarea::-moz-placeholder {
124
- color: var(--field-placeholder);
125
- opacity: 1;
126
- font-weight: 400;
127
- }
128
- }
129
-
130
- // textarea
131
- .n {
132
- & div {
133
- min-height: var(--field-note-height);
134
- line-height: var(--field-note-line-height);
135
- padding-top: var(
136
- --field-note-padding,
137
- var(--field-note-padding-top, 8px)
138
- );
139
- padding-bottom: var(
140
- --field-note-padding,
141
- var(--field-note-padding-top, 8px)
142
- );
143
- }
144
- }
145
-
146
- .w {
147
- & > div {
148
- text-wrap: nowrap;
149
- overflow: hidden;
150
- overflow-x: scroll;
151
- &::-webkit-scrollbar {
152
- width: 0;
153
- height: 0;
154
- }
155
- }
156
- }
157
-
158
- // время: два поля часы / минуты
159
- .time {
160
- & > div {
161
- display: flex;
162
- align-items: center;
163
- min-width: 0;
164
- overflow: visible;
165
- text-wrap: nowrap;
166
- }
167
-
168
- .timeInner {
169
- display: flex;
170
- align-items: center;
171
- justify-content: flex-start;
172
- gap: 4px;
173
- width: 100%;
174
- min-width: 0;
175
- }
176
-
177
- /* центрирование — опционально через проп align="center" у Time */
178
- &.timeAlignCenter .timeInner {
179
- justify-content: center;
180
- }
181
-
182
- .timeSep {
183
- flex: none;
184
- font-weight: 500;
185
- opacity: 0.65;
186
- user-select: none;
187
- padding: 0 2px;
188
- transform: translateY(-1px);
189
- }
190
-
191
- /* contentEditable, как у текстового поля */
192
- .timePart {
193
- box-sizing: border-box;
194
- width: 1em;
195
- min-width: 0;
196
- margin: 0;
197
- padding: 0;
198
- border: 0;
199
- background: transparent;
200
- color: inherit;
201
- font: inherit;
202
- line-height: inherit;
203
- text-align: left;
204
- min-height: var(--field-height);
205
- outline: none;
206
- border-radius: 6px;
207
- cursor: text;
208
- flex: 0 0 auto;
209
-
210
- &[contenteditable="false"] {
211
- cursor: not-allowed;
212
- opacity: 0.7;
213
- }
214
-
215
- &:empty:before {
216
- content: attr(placeholder);
217
- color: var(--field-placeholder);
218
- font-weight: 400;
219
- opacity: 1;
220
- }
221
-
222
- &:focus:empty:before {
223
- content: none;
224
- }
225
-
226
- /* фон капсулы .f уже через :focus-within; здесь не перекрываем */
227
- &:focus-visible {
228
- background: transparent;
229
- }
230
- }
231
-
232
- &.timeAlignCenter .timePart {
233
- text-align: center;
234
- }
235
- }
236
-
237
- .t {
238
- color: var(--field-label-color);
239
- font-size: var(--field-label-size);
240
- padding-bottom: 10px;
241
- }
242
-
243
- .affix {
244
- display: inline-flex;
245
- align-items: center;
246
- justify-content: center;
247
- flex: 0 0 auto;
248
- padding: 0;
249
- margin: 0;
250
- color: var(--field-icon-color, var(--field-placeholder));
251
- font-size: inherit;
252
- line-height: 1;
253
- user-select: none;
254
- }
255
-
256
- /* Отступ аффиксов от краёв капсулы (как визуально у Password), без увеличения зазора до текста */
257
-
258
- .g {
259
- flex-direction: column;
260
- }
261
-
262
- // range — капсула .f + .w как у Input; внутри «таблетка» трек (div): серый фон + бирюзовая заливка слева
263
- .range {
264
- & > div {
265
- box-sizing: border-box;
266
- flex: 1;
267
- min-width: 0;
268
- min-height: var(--field-height);
269
- display: flex;
270
- align-items: center;
271
- line-height: normal;
272
- }
273
-
274
- .rangeTrack {
275
- box-sizing: border-box;
276
- position: relative;
277
- width: 100%;
278
- height: var(--field-range-bar-height, 14px);
279
- flex-shrink: 0;
280
- border-radius: 999px;
281
- background: var(--field-range-track, #e0e0e0);
282
- overflow: hidden;
283
- cursor: pointer;
284
- outline: none;
285
- touch-action: none;
286
-
287
- &:focus-visible {
288
- box-shadow: 0 0 0 3px var(--field-focus-ring, #0000);
289
- }
290
-
291
- &[data-disabled="true"] {
292
- cursor: not-allowed;
293
- opacity: 0.55;
294
- pointer-events: none;
295
- }
296
- }
297
-
298
- .rangeFill {
299
- height: 100%;
300
- width: 0;
301
- min-width: 0;
302
- background: var(--field-range-fill, #00b5ad);
303
- border-radius: 999px 0 0 999px;
304
- pointer-events: none;
305
- }
306
-
307
- /* при 100% — полностью скруглённая «капсула» заливки */
308
- .rangeFillFull {
309
- border-radius: 999px;
310
- }
311
- }
312
-
313
- // checkbox — капсула с квадратом слева и текстом справа
314
- .checkbox {
315
- & > div {
316
- min-height: var(--field-height);
317
- display: flex;
318
- align-items: flex-start;
319
- width: 100%;
320
- padding: 0;
321
- line-height: normal;
322
- }
323
- }
324
-
325
- .checkControl {
326
- width: 100%;
327
- min-height: var(--field-height);
328
- display: flex;
329
- align-items: flex-start;
330
- gap: 12px;
331
- border: 0;
332
- margin: 0;
333
- padding: 10px 0;
334
- background: transparent;
335
- color: inherit;
336
- font: inherit;
337
- text-align: left;
338
- cursor: pointer;
339
- outline: none;
340
-
341
- &:focus-visible {
342
- box-shadow: 0 0 0 3px var(--field-focus-ring, #0000);
343
- border-radius: calc(var(--field-radius) - 2px);
344
- }
345
-
346
- &[aria-disabled="true"] {
347
- cursor: not-allowed;
348
- }
349
- }
350
-
351
- .checkBox {
352
- width: 22px;
353
- height: 22px;
354
- border-radius: 8px;
355
- border: var(--field-check-box-border, var(--field-border));
356
- background: transparent;
357
- display: inline-flex;
358
- align-items: center;
359
- justify-content: center;
360
- flex: 0 0 auto;
361
- transition:
362
- background-color 0.16s ease,
363
- border-color 0.16s ease,
364
- opacity 0.16s ease;
365
- }
366
-
367
- .checkMark {
368
- width: 11px;
369
- height: 6px;
370
- border: 2px solid #fcfff4;
371
- border-top: none;
372
- border-right: none;
373
- transform: translateY(-1px) rotate(-45deg);
374
- }
375
-
376
- .checkText {
377
- flex: 1 1 auto;
378
- min-width: 0;
379
- color: inherit;
380
- font-size: var(--control-font-size, 14px);
381
- line-height: 1.25;
382
- padding-top: 2px;
383
- }
384
-
385
- .checkControl[aria-checked="true"] .checkBox {
386
- background: var(--field-background-active);
387
- }
388
-
389
- // checkBox
390
- .h {
391
- --field-border: 0;
392
- & div {
393
- border: var(--field-check-box-border, --field-border);
394
- width: var(--field-height);
395
- height: var(--field-height);
396
- border-radius: var(--field-radius);
397
- background: var(--field-background);
398
- margin: 0;
399
- flex: none;
400
- cursor: pointer;
401
- position: relative;
402
- gap: 10px;
403
- &[aria-checked="true"] {
404
- background: var(--field-background-active);
405
- }
406
- &:after {
407
- content: "";
408
- width: 9px;
409
- height: 5px;
410
- position: absolute;
411
- top: 5px;
412
- left: 4px;
413
- border: 3px solid #fcfff4;
414
- border-top: none;
415
- border-right: none;
416
- background: transparent;
417
- transform: rotate(-45deg);
418
- margin: 4px;
419
- }
420
- }
421
- }
422
-
423
- .e {
424
- border-color: var(--field-error-border);
425
- background: var(--field-error-background);
426
- color: var(--field-error-color);
427
- }
428
-
429
- .m {
430
- color: var(--field-error-color);
431
- font-size: 12px;
432
- font-style: normal;
433
- margin-top: 6px;
434
- }