fh-pydantic-form 0.2.1__tar.gz → 0.2.3__tar.gz
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.
Potentially problematic release.
This version of fh-pydantic-form might be problematic. Click here for more details.
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/PKG-INFO +1 -1
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/RELEASE_NOTES.md +11 -2
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/pyproject.toml +1 -1
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/src/fh_pydantic_form/__init__.py +2 -2
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/src/fh_pydantic_form/field_renderers.py +83 -34
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/src/fh_pydantic_form/form_renderer.py +2 -12
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/src/fh_pydantic_form/ui_style.py +30 -51
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/.github/workflows/build.yaml +0 -0
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/.github/workflows/publish.yaml +0 -0
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/.gitignore +0 -0
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/.pre-commit-config.yaml +0 -0
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/LICENSE +0 -0
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/README.md +0 -0
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/src/fh_pydantic_form/defaults.py +0 -0
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/src/fh_pydantic_form/form_parser.py +0 -0
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/src/fh_pydantic_form/list_path.py +0 -0
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/src/fh_pydantic_form/py.typed +0 -0
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/src/fh_pydantic_form/registry.py +0 -0
- {fh_pydantic_form-0.2.1 → fh_pydantic_form-0.2.3}/src/fh_pydantic_form/type_helpers.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: fh-pydantic-form
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: a library to turn any pydantic BaseModel object into a fasthtml/monsterui input form
|
|
5
5
|
Project-URL: Homepage, https://github.com/Marcura/fh-pydantic-form
|
|
6
6
|
Project-URL: Repository, https://github.com/Marcura/fh-pydantic-form
|
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
# Release Notes
|
|
2
2
|
|
|
3
|
-
## Version 0.2.
|
|
3
|
+
## Version 0.2.3 (2025-06-16 )
|
|
4
|
+
|
|
5
|
+
- Removed the custom css injection for compact spacing. Instead applying to components directly.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## Version 0.2.2 (2025-06-16 )
|
|
9
|
+
|
|
10
|
+
- fix left alignment issue with inputs in the presence of outside css influences
|
|
11
|
+
|
|
12
|
+
## Version 0.2.1
|
|
4
13
|
|
|
5
14
|
### 🔧 UI/UX Improvements
|
|
6
15
|
|
|
@@ -44,7 +53,7 @@ While v0.2.0 introduced major features like enum support and compact mode, v0.2.
|
|
|
44
53
|
|
|
45
54
|
---
|
|
46
55
|
|
|
47
|
-
## Version 0.2.0
|
|
56
|
+
## Version 0.2.0
|
|
48
57
|
|
|
49
58
|
### 🎉 Major Features
|
|
50
59
|
|
|
@@ -24,7 +24,7 @@ from fh_pydantic_form.ui_style import (
|
|
|
24
24
|
SpacingTheme,
|
|
25
25
|
SpacingValue,
|
|
26
26
|
spacing,
|
|
27
|
-
|
|
27
|
+
spacing_many,
|
|
28
28
|
)
|
|
29
29
|
from fh_pydantic_form.defaults import (
|
|
30
30
|
default_dict_for_model,
|
|
@@ -119,7 +119,7 @@ __all__ = [
|
|
|
119
119
|
"SpacingTheme",
|
|
120
120
|
"SpacingValue",
|
|
121
121
|
"spacing",
|
|
122
|
-
"
|
|
122
|
+
"spacing_many",
|
|
123
123
|
"default_dict_for_model",
|
|
124
124
|
"default_for_annotation",
|
|
125
125
|
]
|
|
@@ -27,6 +27,7 @@ from fh_pydantic_form.ui_style import (
|
|
|
27
27
|
SpacingValue,
|
|
28
28
|
_normalize_spacing,
|
|
29
29
|
spacing,
|
|
30
|
+
spacing_many,
|
|
30
31
|
)
|
|
31
32
|
|
|
32
33
|
logger = logging.getLogger(__name__)
|
|
@@ -214,9 +215,9 @@ class BaseFieldRenderer:
|
|
|
214
215
|
fh.Div(
|
|
215
216
|
label_component,
|
|
216
217
|
input_component,
|
|
217
|
-
cls=f"flex {spacing('horizontal_gap', self.spacing)} {spacing('label_align', self.spacing)}",
|
|
218
|
+
cls=f"flex {spacing('horizontal_gap', self.spacing)} {spacing('label_align', self.spacing)} w-full",
|
|
218
219
|
),
|
|
219
|
-
cls=spacing(
|
|
220
|
+
cls=f"{spacing('outer_margin', self.spacing)} w-full",
|
|
220
221
|
)
|
|
221
222
|
else:
|
|
222
223
|
# Vertical layout for normal mode (existing behavior)
|
|
@@ -252,6 +253,14 @@ class StringFieldRenderer(BaseFieldRenderer):
|
|
|
252
253
|
if self.is_optional:
|
|
253
254
|
placeholder_text += " (Optional)"
|
|
254
255
|
|
|
256
|
+
input_cls_parts = ["w-full"]
|
|
257
|
+
input_spacing_cls = spacing_many(
|
|
258
|
+
["input_size", "input_padding", "input_line_height", "input_font_size"],
|
|
259
|
+
self.spacing,
|
|
260
|
+
)
|
|
261
|
+
if input_spacing_cls:
|
|
262
|
+
input_cls_parts.append(input_spacing_cls)
|
|
263
|
+
|
|
255
264
|
input_attrs = {
|
|
256
265
|
"value": self.value or "",
|
|
257
266
|
"id": self.field_name,
|
|
@@ -259,10 +268,7 @@ class StringFieldRenderer(BaseFieldRenderer):
|
|
|
259
268
|
"type": "text",
|
|
260
269
|
"placeholder": placeholder_text,
|
|
261
270
|
"required": is_field_required,
|
|
262
|
-
"cls":
|
|
263
|
-
"w-full",
|
|
264
|
-
f"{spacing('input_size', self.spacing)} {spacing('input_padding', self.spacing)}".strip(),
|
|
265
|
-
),
|
|
271
|
+
"cls": " ".join(input_cls_parts),
|
|
266
272
|
}
|
|
267
273
|
|
|
268
274
|
# Only add the disabled attribute if the field should actually be disabled
|
|
@@ -290,6 +296,14 @@ class NumberFieldRenderer(BaseFieldRenderer):
|
|
|
290
296
|
if self.is_optional:
|
|
291
297
|
placeholder_text += " (Optional)"
|
|
292
298
|
|
|
299
|
+
input_cls_parts = ["w-full"]
|
|
300
|
+
input_spacing_cls = spacing_many(
|
|
301
|
+
["input_size", "input_padding", "input_line_height", "input_font_size"],
|
|
302
|
+
self.spacing,
|
|
303
|
+
)
|
|
304
|
+
if input_spacing_cls:
|
|
305
|
+
input_cls_parts.append(input_spacing_cls)
|
|
306
|
+
|
|
293
307
|
input_attrs = {
|
|
294
308
|
"value": str(self.value) if self.value is not None else "",
|
|
295
309
|
"id": self.field_name,
|
|
@@ -297,10 +311,7 @@ class NumberFieldRenderer(BaseFieldRenderer):
|
|
|
297
311
|
"type": "number",
|
|
298
312
|
"placeholder": placeholder_text,
|
|
299
313
|
"required": is_field_required,
|
|
300
|
-
"cls":
|
|
301
|
-
"w-full",
|
|
302
|
-
f"{spacing('input_size', self.spacing)} {spacing('input_padding', self.spacing)}".strip(),
|
|
303
|
-
),
|
|
314
|
+
"cls": " ".join(input_cls_parts),
|
|
304
315
|
"step": "any"
|
|
305
316
|
if self.field_info.annotation is float
|
|
306
317
|
or get_origin(self.field_info.annotation) is float
|
|
@@ -354,9 +365,9 @@ class BooleanFieldRenderer(BaseFieldRenderer):
|
|
|
354
365
|
fh.Div(
|
|
355
366
|
label_component,
|
|
356
367
|
checkbox_component,
|
|
357
|
-
cls="flex items-center gap-2", # Use flexbox to align items horizontally with a small gap
|
|
368
|
+
cls="flex items-center gap-2 w-full", # Use flexbox to align items horizontally with a small gap
|
|
358
369
|
),
|
|
359
|
-
cls=spacing(
|
|
370
|
+
cls=f"{spacing('outer_margin', self.spacing)} w-full",
|
|
360
371
|
)
|
|
361
372
|
|
|
362
373
|
|
|
@@ -386,6 +397,14 @@ class DateFieldRenderer(BaseFieldRenderer):
|
|
|
386
397
|
if self.is_optional:
|
|
387
398
|
placeholder_text += " (Optional)"
|
|
388
399
|
|
|
400
|
+
input_cls_parts = ["w-full"]
|
|
401
|
+
input_spacing_cls = spacing_many(
|
|
402
|
+
["input_size", "input_padding", "input_line_height", "input_font_size"],
|
|
403
|
+
self.spacing,
|
|
404
|
+
)
|
|
405
|
+
if input_spacing_cls:
|
|
406
|
+
input_cls_parts.append(input_spacing_cls)
|
|
407
|
+
|
|
389
408
|
input_attrs = {
|
|
390
409
|
"value": formatted_value,
|
|
391
410
|
"id": self.field_name,
|
|
@@ -393,10 +412,7 @@ class DateFieldRenderer(BaseFieldRenderer):
|
|
|
393
412
|
"type": "date",
|
|
394
413
|
"placeholder": placeholder_text,
|
|
395
414
|
"required": is_field_required,
|
|
396
|
-
"cls":
|
|
397
|
-
"w-full",
|
|
398
|
-
f"{spacing('input_size', self.spacing)} {spacing('input_padding', self.spacing)}".strip(),
|
|
399
|
-
),
|
|
415
|
+
"cls": " ".join(input_cls_parts),
|
|
400
416
|
}
|
|
401
417
|
|
|
402
418
|
# Only add the disabled attribute if the field should actually be disabled
|
|
@@ -433,6 +449,14 @@ class TimeFieldRenderer(BaseFieldRenderer):
|
|
|
433
449
|
if self.is_optional:
|
|
434
450
|
placeholder_text += " (Optional)"
|
|
435
451
|
|
|
452
|
+
input_cls_parts = ["w-full"]
|
|
453
|
+
input_spacing_cls = spacing_many(
|
|
454
|
+
["input_size", "input_padding", "input_line_height", "input_font_size"],
|
|
455
|
+
self.spacing,
|
|
456
|
+
)
|
|
457
|
+
if input_spacing_cls:
|
|
458
|
+
input_cls_parts.append(input_spacing_cls)
|
|
459
|
+
|
|
436
460
|
input_attrs = {
|
|
437
461
|
"value": formatted_value,
|
|
438
462
|
"id": self.field_name,
|
|
@@ -440,10 +464,7 @@ class TimeFieldRenderer(BaseFieldRenderer):
|
|
|
440
464
|
"type": "time",
|
|
441
465
|
"placeholder": placeholder_text,
|
|
442
466
|
"required": is_field_required,
|
|
443
|
-
"cls":
|
|
444
|
-
"w-full",
|
|
445
|
-
f"{spacing('input_size', self.spacing)} {spacing('input_padding', self.spacing)}".strip(),
|
|
446
|
-
),
|
|
467
|
+
"cls": " ".join(input_cls_parts),
|
|
447
468
|
}
|
|
448
469
|
|
|
449
470
|
# Only add the disabled attribute if the field should actually be disabled
|
|
@@ -503,18 +524,22 @@ class LiteralFieldRenderer(BaseFieldRenderer):
|
|
|
503
524
|
placeholder_text += " (Optional)"
|
|
504
525
|
|
|
505
526
|
# Prepare attributes dictionary
|
|
527
|
+
select_cls_parts = ["w-full"]
|
|
528
|
+
select_spacing_cls = spacing_many(
|
|
529
|
+
["input_size", "input_padding", "input_line_height", "input_font_size"],
|
|
530
|
+
self.spacing,
|
|
531
|
+
)
|
|
532
|
+
if select_spacing_cls:
|
|
533
|
+
select_cls_parts.append(select_spacing_cls)
|
|
534
|
+
|
|
506
535
|
select_attrs = {
|
|
507
536
|
"id": self.field_name,
|
|
508
537
|
"name": self.field_name,
|
|
509
538
|
"required": is_field_required,
|
|
510
539
|
"placeholder": placeholder_text,
|
|
511
|
-
"cls":
|
|
512
|
-
"w-full",
|
|
513
|
-
f"{spacing('input_size', self.spacing)} {spacing('input_padding', self.spacing)}".strip(),
|
|
514
|
-
),
|
|
540
|
+
"cls": " ".join(select_cls_parts),
|
|
515
541
|
}
|
|
516
542
|
|
|
517
|
-
# Only add the disabled attribute if the field should actually be disabled
|
|
518
543
|
if self.disabled:
|
|
519
544
|
select_attrs["disabled"] = True
|
|
520
545
|
|
|
@@ -667,12 +692,15 @@ class BaseModelFieldRenderer(BaseFieldRenderer):
|
|
|
667
692
|
)
|
|
668
693
|
|
|
669
694
|
# 5. Wrap the single AccordionItem in an Accordion container
|
|
695
|
+
accordion_cls = spacing_many(
|
|
696
|
+
["accordion_divider", "accordion_content"], self.spacing
|
|
697
|
+
)
|
|
670
698
|
accordion_container = mui.Accordion(
|
|
671
699
|
accordion_item, # The single item to include
|
|
672
700
|
id=accordion_id, # ID for the accordion container (ul)
|
|
673
701
|
multiple=True, # Allow multiple open (though only one exists)
|
|
674
702
|
collapsible=True, # Allow toggling
|
|
675
|
-
cls=f"{
|
|
703
|
+
cls=f"{accordion_cls} w-full".strip(),
|
|
676
704
|
)
|
|
677
705
|
|
|
678
706
|
return accordion_container
|
|
@@ -929,7 +957,7 @@ class ListFieldRenderer(BaseFieldRenderer):
|
|
|
929
957
|
return fh.Div(
|
|
930
958
|
label_with_icon,
|
|
931
959
|
self.render_input(),
|
|
932
|
-
cls=spacing(
|
|
960
|
+
cls=f"{spacing('outer_margin', self.spacing)} w-full",
|
|
933
961
|
)
|
|
934
962
|
|
|
935
963
|
def render_input(self) -> FT:
|
|
@@ -987,12 +1015,15 @@ class ListFieldRenderer(BaseFieldRenderer):
|
|
|
987
1015
|
container_id = self._container_id()
|
|
988
1016
|
|
|
989
1017
|
# Use mui.Accordion component
|
|
1018
|
+
accordion_cls = spacing_many(
|
|
1019
|
+
["inner_gap_small", "accordion_content", "accordion_divider"], self.spacing
|
|
1020
|
+
)
|
|
990
1021
|
accordion = mui.Accordion(
|
|
991
1022
|
*item_elements,
|
|
992
1023
|
id=container_id,
|
|
993
1024
|
multiple=True, # Allow multiple items to be open at once
|
|
994
1025
|
collapsible=True, # Make it collapsible
|
|
995
|
-
cls=
|
|
1026
|
+
cls=accordion_cls.strip(), # Add space between items and accordion content styling
|
|
996
1027
|
)
|
|
997
1028
|
|
|
998
1029
|
# Empty state message if no items
|
|
@@ -1344,10 +1375,19 @@ class ListFieldRenderer(BaseFieldRenderer):
|
|
|
1344
1375
|
)
|
|
1345
1376
|
li_attrs = {"id": full_card_id}
|
|
1346
1377
|
|
|
1347
|
-
# Build card classes
|
|
1348
|
-
|
|
1378
|
+
# Build card classes using spacing tokens
|
|
1379
|
+
card_cls_parts = ["uk-card"]
|
|
1349
1380
|
if self.spacing == SpacingTheme.NORMAL:
|
|
1350
|
-
|
|
1381
|
+
card_cls_parts.append("uk-card-default")
|
|
1382
|
+
|
|
1383
|
+
# Add spacing-based classes
|
|
1384
|
+
card_spacing_cls = spacing_many(
|
|
1385
|
+
["accordion_item_margin", "card_border_thin"], self.spacing
|
|
1386
|
+
)
|
|
1387
|
+
if card_spacing_cls:
|
|
1388
|
+
card_cls_parts.append(card_spacing_cls)
|
|
1389
|
+
|
|
1390
|
+
card_cls = " ".join(card_cls_parts)
|
|
1351
1391
|
|
|
1352
1392
|
return mui.AccordionItem(
|
|
1353
1393
|
title_component, # Title as first positional argument
|
|
@@ -1370,10 +1410,19 @@ class ListFieldRenderer(BaseFieldRenderer):
|
|
|
1370
1410
|
t = self.spacing
|
|
1371
1411
|
content_wrapper = fh.Div(content_component, cls=spacing("card_body_pad", t))
|
|
1372
1412
|
|
|
1373
|
-
# Build card classes
|
|
1374
|
-
|
|
1413
|
+
# Build card classes using spacing tokens
|
|
1414
|
+
card_cls_parts = ["uk-card"]
|
|
1375
1415
|
if self.spacing == SpacingTheme.NORMAL:
|
|
1376
|
-
|
|
1416
|
+
card_cls_parts.append("uk-card-default")
|
|
1417
|
+
|
|
1418
|
+
# Add spacing-based classes
|
|
1419
|
+
card_spacing_cls = spacing_many(
|
|
1420
|
+
["accordion_item_margin", "card_border_thin"], self.spacing
|
|
1421
|
+
)
|
|
1422
|
+
if card_spacing_cls:
|
|
1423
|
+
card_cls_parts.append(card_spacing_cls)
|
|
1424
|
+
|
|
1425
|
+
card_cls = " ".join(card_cls_parts)
|
|
1377
1426
|
|
|
1378
1427
|
return mui.AccordionItem(
|
|
1379
1428
|
title_component, # Title as first positional argument
|
|
@@ -32,7 +32,6 @@ from fh_pydantic_form.list_path import walk_path
|
|
|
32
32
|
from fh_pydantic_form.registry import FieldRendererRegistry
|
|
33
33
|
from fh_pydantic_form.type_helpers import _UNSET, get_default
|
|
34
34
|
from fh_pydantic_form.ui_style import (
|
|
35
|
-
COMPACT_EXTRA_CSS,
|
|
36
35
|
SpacingTheme,
|
|
37
36
|
SpacingValue,
|
|
38
37
|
_normalize_spacing,
|
|
@@ -213,19 +212,10 @@ class PydanticForm(Generic[ModelType]):
|
|
|
213
212
|
|
|
214
213
|
def _compact_wrapper(self, inner: FT) -> FT:
|
|
215
214
|
"""
|
|
216
|
-
Wrap inner markup in a
|
|
217
|
-
Auto-inject the compact CSS the *first* time any compact form is rendered.
|
|
215
|
+
Wrap inner markup in a wrapper div.
|
|
218
216
|
"""
|
|
219
217
|
wrapper_cls = "fhpf-wrapper w-full flex-1"
|
|
220
|
-
|
|
221
|
-
if self.spacing != SpacingTheme.COMPACT:
|
|
222
|
-
return fh.Div(inner, cls=wrapper_cls)
|
|
223
|
-
|
|
224
|
-
return fh.Div(
|
|
225
|
-
COMPACT_EXTRA_CSS,
|
|
226
|
-
fh.Div(inner, cls="fhpf-fields fhpf-compact"),
|
|
227
|
-
cls=wrapper_cls,
|
|
228
|
-
)
|
|
218
|
+
return fh.Div(inner, cls=wrapper_cls)
|
|
229
219
|
|
|
230
220
|
def _clone_with_values(self, values: Dict[str, Any]) -> "PydanticForm":
|
|
231
221
|
"""
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
from enum import Enum, auto
|
|
2
2
|
from typing import Dict, Literal, Union
|
|
3
3
|
|
|
4
|
-
import fasthtml.common as fh
|
|
5
|
-
|
|
6
4
|
|
|
7
5
|
class SpacingTheme(Enum):
|
|
8
6
|
NORMAL = auto()
|
|
@@ -44,13 +42,19 @@ SPACING_MAP: Dict[SpacingTheme, Dict[str, str]] = {
|
|
|
44
42
|
"padding_sm": "p-3",
|
|
45
43
|
"padding_card": "px-4 py-3",
|
|
46
44
|
"card_border": "border",
|
|
45
|
+
"card_border_thin": "",
|
|
47
46
|
"section_divider": "border-t border-gray-200",
|
|
48
47
|
"accordion_divider": "uk-accordion-divider",
|
|
48
|
+
"accordion_title_pad": "",
|
|
49
|
+
"accordion_content_pad": "",
|
|
50
|
+
"accordion_item_margin": "uk-margin-small-bottom",
|
|
49
51
|
"label_gap": "mb-1",
|
|
50
52
|
"card_body_pad": "px-4 py-3",
|
|
51
53
|
"accordion_content": "",
|
|
52
54
|
"input_size": "",
|
|
53
55
|
"input_padding": "",
|
|
56
|
+
"input_line_height": "",
|
|
57
|
+
"input_font_size": "",
|
|
54
58
|
"horizontal_gap": "gap-3",
|
|
55
59
|
"label_align": "items-start",
|
|
56
60
|
},
|
|
@@ -64,15 +68,21 @@ SPACING_MAP: Dict[SpacingTheme, Dict[str, str]] = {
|
|
|
64
68
|
"padding_sm": "p-0.5",
|
|
65
69
|
"padding_card": "px-2 py-1",
|
|
66
70
|
"card_border": "",
|
|
71
|
+
"card_border_thin": "",
|
|
67
72
|
"section_divider": "",
|
|
68
73
|
"accordion_divider": "",
|
|
74
|
+
"accordion_title_pad": "py-1",
|
|
75
|
+
"accordion_content_pad": "py-1",
|
|
76
|
+
"accordion_item_margin": "mb-0",
|
|
69
77
|
"label_gap": "mb-0",
|
|
70
78
|
"card_body_pad": "px-2 py-0.5",
|
|
71
79
|
"accordion_content": "uk-padding-remove-vertical",
|
|
72
80
|
"input_size": "uk-form-small",
|
|
73
|
-
"input_padding": "
|
|
81
|
+
"input_padding": "py-0.5 px-1",
|
|
82
|
+
"input_line_height": "leading-tight",
|
|
83
|
+
"input_font_size": "text-sm",
|
|
74
84
|
"horizontal_gap": "gap-2",
|
|
75
|
-
"label_align": "items-
|
|
85
|
+
"label_align": "items-start",
|
|
76
86
|
},
|
|
77
87
|
}
|
|
78
88
|
|
|
@@ -83,52 +93,21 @@ def spacing(token: str, spacing: SpacingValue) -> str:
|
|
|
83
93
|
return SPACING_MAP[theme][token]
|
|
84
94
|
|
|
85
95
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
/* Compact polish – applies ONLY inside .fhpf-compact ------------------- */
|
|
90
|
-
.fhpf-compact {
|
|
91
|
-
|
|
92
|
-
/* Accordion chrome: remove border and default 20 px gap */
|
|
93
|
-
.uk-accordion > li,
|
|
94
|
-
.uk-accordion > li + li { /* second & later items */
|
|
95
|
-
border-top: 0 !important;
|
|
96
|
-
margin-top: 0 !important;
|
|
97
|
-
}
|
|
98
|
-
.uk-accordion-title::after { /* the hair-line we still see */
|
|
99
|
-
border-top: 0 !important;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/* Tighter title and content padding */
|
|
103
|
-
li > a.uk-accordion-title,
|
|
104
|
-
.uk-accordion-content {
|
|
105
|
-
padding-top: 0.25rem !important;
|
|
106
|
-
padding-bottom: 0.25rem !important;
|
|
107
|
-
}
|
|
96
|
+
def spacing_many(tokens: list[str], spacing: SpacingValue) -> str:
|
|
97
|
+
"""
|
|
98
|
+
Return combined Tailwind utility classes for multiple semantic tokens.
|
|
108
99
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
100
|
+
Args:
|
|
101
|
+
tokens: List of spacing token names
|
|
102
|
+
spacing: Spacing theme to use
|
|
112
103
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
select.uk-form-small,
|
|
124
|
-
textarea.uk-textarea-small {
|
|
125
|
-
padding-top: 2px !important;
|
|
126
|
-
padding-bottom: 2px !important;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/* Kill generic uk-margin utilities inside the form */
|
|
130
|
-
.uk-margin-small-bottom,
|
|
131
|
-
.uk-margin,
|
|
132
|
-
.uk-margin-bottom { margin-bottom: 2px !important; }
|
|
133
|
-
}
|
|
134
|
-
""")
|
|
104
|
+
Returns:
|
|
105
|
+
String of space-separated CSS classes
|
|
106
|
+
"""
|
|
107
|
+
theme = _normalize_spacing(spacing)
|
|
108
|
+
classes = []
|
|
109
|
+
for token in tokens:
|
|
110
|
+
class_value = SPACING_MAP[theme].get(token, "")
|
|
111
|
+
if class_value: # Only add non-empty class values
|
|
112
|
+
classes.append(class_value)
|
|
113
|
+
return " ".join(classes)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|