citry-bootstrap 0.1.0__py3-none-any.whl

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 (47) hide show
  1. citry_bootstrap/__init__.py +440 -0
  2. citry_bootstrap/components/__init__.py +0 -0
  3. citry_bootstrap/components/bootstrap5/__init__.py +82 -0
  4. citry_bootstrap/components/bootstrap5/accordion.py +197 -0
  5. citry_bootstrap/components/bootstrap5/alert.py +94 -0
  6. citry_bootstrap/components/bootstrap5/badge.py +42 -0
  7. citry_bootstrap/components/bootstrap5/breadcrumb.py +73 -0
  8. citry_bootstrap/components/bootstrap5/button.py +98 -0
  9. citry_bootstrap/components/bootstrap5/button_group.py +64 -0
  10. citry_bootstrap/components/bootstrap5/card.py +307 -0
  11. citry_bootstrap/components/bootstrap5/carousel.py +297 -0
  12. citry_bootstrap/components/bootstrap5/close_button.py +33 -0
  13. citry_bootstrap/components/bootstrap5/collapse.py +109 -0
  14. citry_bootstrap/components/bootstrap5/dropdown.py +298 -0
  15. citry_bootstrap/components/bootstrap5/dropdown_button.py +104 -0
  16. citry_bootstrap/components/bootstrap5/figure.py +78 -0
  17. citry_bootstrap/components/bootstrap5/form.py +533 -0
  18. citry_bootstrap/components/bootstrap5/form_range.py +46 -0
  19. citry_bootstrap/components/bootstrap5/form_textarea.py +57 -0
  20. citry_bootstrap/components/bootstrap5/image.py +48 -0
  21. citry_bootstrap/components/bootstrap5/input_group.py +133 -0
  22. citry_bootstrap/components/bootstrap5/layout.py +181 -0
  23. citry_bootstrap/components/bootstrap5/list_group.py +137 -0
  24. citry_bootstrap/components/bootstrap5/modal.py +231 -0
  25. citry_bootstrap/components/bootstrap5/nav.py +193 -0
  26. citry_bootstrap/components/bootstrap5/nav_dropdown.py +56 -0
  27. citry_bootstrap/components/bootstrap5/navbar.py +239 -0
  28. citry_bootstrap/components/bootstrap5/offcanvas.py +186 -0
  29. citry_bootstrap/components/bootstrap5/pagination.py +300 -0
  30. citry_bootstrap/components/bootstrap5/placeholder.py +72 -0
  31. citry_bootstrap/components/bootstrap5/popover.py +43 -0
  32. citry_bootstrap/components/bootstrap5/progress.py +125 -0
  33. citry_bootstrap/components/bootstrap5/spinner.py +40 -0
  34. citry_bootstrap/components/bootstrap5/stack.py +43 -0
  35. citry_bootstrap/components/bootstrap5/table.py +74 -0
  36. citry_bootstrap/components/bootstrap5/tabs.py +309 -0
  37. citry_bootstrap/components/bootstrap5/toast.py +160 -0
  38. citry_bootstrap/components/bootstrap5/toggle_button.py +126 -0
  39. citry_bootstrap/components/bootstrap5/tooltip.py +40 -0
  40. citry_bootstrap/components/bootstrap5/types.py +123 -0
  41. citry_bootstrap/plain_inputs.py +60 -0
  42. citry_bootstrap/py.typed +0 -0
  43. citry_bootstrap/text.py +20 -0
  44. citry_bootstrap-0.1.0.dist-info/METADATA +108 -0
  45. citry_bootstrap-0.1.0.dist-info/RECORD +47 -0
  46. citry_bootstrap-0.1.0.dist-info/WHEEL +4 -0
  47. citry_bootstrap-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,440 @@
1
+ """citry-bootstrap"""
2
+
3
+ from collections.abc import Mapping
4
+
5
+ from citry import Citry, ComponentLibrary, LibraryComponent, LibraryInstallation
6
+
7
+ from citry_bootstrap.components.bootstrap5.accordion import (
8
+ Accordion,
9
+ AccordionBody,
10
+ AccordionButton,
11
+ AccordionHeader,
12
+ AccordionItem,
13
+ )
14
+ from citry_bootstrap.components.bootstrap5.alert import Alert, AlertHeading, AlertLink
15
+ from citry_bootstrap.components.bootstrap5.badge import Badge
16
+ from citry_bootstrap.components.bootstrap5.breadcrumb import Breadcrumb, BreadcrumbItem
17
+ from citry_bootstrap.components.bootstrap5.button import Button
18
+ from citry_bootstrap.components.bootstrap5.button_group import ButtonGroup, ButtonToolbar
19
+ from citry_bootstrap.components.bootstrap5.card import (
20
+ Card,
21
+ CardBody,
22
+ CardFooter,
23
+ CardGroup,
24
+ CardHeader,
25
+ CardImg,
26
+ CardImgOverlay,
27
+ CardLink,
28
+ CardSubtitle,
29
+ CardText,
30
+ CardTitle,
31
+ )
32
+ from citry_bootstrap.components.bootstrap5.carousel import (
33
+ Carousel,
34
+ CarouselCaption,
35
+ CarouselIndicator,
36
+ CarouselItem,
37
+ CarouselRenderer,
38
+ )
39
+ from citry_bootstrap.components.bootstrap5.close_button import CloseButton
40
+ from citry_bootstrap.components.bootstrap5.collapse import Collapse, CollapseToggle
41
+ from citry_bootstrap.components.bootstrap5.dropdown import (
42
+ Dropdown,
43
+ DropdownDivider,
44
+ DropdownHeader,
45
+ DropdownItem,
46
+ DropdownItemText,
47
+ DropdownMenu,
48
+ DropdownToggle,
49
+ )
50
+ from citry_bootstrap.components.bootstrap5.dropdown_button import DropdownButton, SplitButton
51
+ from citry_bootstrap.components.bootstrap5.figure import Figure, FigureCaption, FigureImage
52
+ from citry_bootstrap.components.bootstrap5.form import (
53
+ Form,
54
+ FormCheck,
55
+ FormCheckInput,
56
+ FormCheckLabel,
57
+ FormControl,
58
+ FormFloating,
59
+ FormGroup,
60
+ FormLabel,
61
+ FormSelect,
62
+ FormText,
63
+ FormTextarea,
64
+ )
65
+ from citry_bootstrap.components.bootstrap5.form_range import FormRange
66
+ from citry_bootstrap.components.bootstrap5.image import Image
67
+ from citry_bootstrap.components.bootstrap5.input_group import (
68
+ FloatingLabel,
69
+ InputGroup,
70
+ InputGroupCheckbox,
71
+ InputGroupRadio,
72
+ InputGroupText,
73
+ )
74
+ from citry_bootstrap.components.bootstrap5.layout import Col, Container, Row
75
+ from citry_bootstrap.components.bootstrap5.list_group import ListGroup, ListGroupItem
76
+ from citry_bootstrap.components.bootstrap5.modal import (
77
+ Modal,
78
+ ModalBody,
79
+ ModalFooter,
80
+ ModalHeader,
81
+ ModalTitle,
82
+ ModalToggle,
83
+ )
84
+ from citry_bootstrap.components.bootstrap5.nav import Nav, NavItem, NavLink
85
+ from citry_bootstrap.components.bootstrap5.nav_dropdown import NavDropdown
86
+ from citry_bootstrap.components.bootstrap5.navbar import (
87
+ Navbar,
88
+ NavbarBrand,
89
+ NavbarCollapse,
90
+ NavbarNav,
91
+ NavbarText,
92
+ NavbarToggler,
93
+ )
94
+ from citry_bootstrap.components.bootstrap5.offcanvas import (
95
+ Offcanvas,
96
+ OffcanvasBody,
97
+ OffcanvasHeader,
98
+ OffcanvasTitle,
99
+ OffcanvasToggle,
100
+ )
101
+ from citry_bootstrap.components.bootstrap5.pagination import (
102
+ PageLink,
103
+ Pagination,
104
+ PaginationEllipsis,
105
+ PaginationFirst,
106
+ PaginationItem,
107
+ PaginationLast,
108
+ PaginationNext,
109
+ PaginationPrev,
110
+ )
111
+ from citry_bootstrap.components.bootstrap5.placeholder import Placeholder, PlaceholderButton
112
+ from citry_bootstrap.components.bootstrap5.popover import Popover
113
+ from citry_bootstrap.components.bootstrap5.progress import Progress, ProgressBar, ProgressStacked
114
+ from citry_bootstrap.components.bootstrap5.spinner import Spinner
115
+ from citry_bootstrap.components.bootstrap5.stack import Stack
116
+ from citry_bootstrap.components.bootstrap5.table import Table
117
+ from citry_bootstrap.components.bootstrap5.tabs import (
118
+ Tab,
119
+ TabContainer,
120
+ TabContent,
121
+ TabPane,
122
+ Tabs,
123
+ TabsRenderer,
124
+ )
125
+ from citry_bootstrap.components.bootstrap5.toast import (
126
+ Toast,
127
+ ToastBody,
128
+ ToastContainer,
129
+ ToastHeader,
130
+ )
131
+ from citry_bootstrap.components.bootstrap5.toggle_button import ToggleButton, ToggleButtonGroup
132
+ from citry_bootstrap.components.bootstrap5.tooltip import Tooltip
133
+ from citry_bootstrap.plain_inputs import PlainInputs
134
+
135
+ #: Every component is published under this prefix; `install(alias=...)` adds more.
136
+ PREFIX = "bs-"
137
+
138
+ __citry_library__ = ComponentLibrary(
139
+ name="citry-bootstrap",
140
+ required_extensions=("plain_inputs",),
141
+ components=(
142
+ Accordion,
143
+ AccordionItem,
144
+ AccordionButton,
145
+ AccordionHeader,
146
+ AccordionBody,
147
+ Alert,
148
+ AlertLink,
149
+ AlertHeading,
150
+ Badge,
151
+ Breadcrumb,
152
+ BreadcrumbItem,
153
+ Button,
154
+ ButtonGroup,
155
+ ButtonToolbar,
156
+ Card,
157
+ CardHeader,
158
+ CardBody,
159
+ CardFooter,
160
+ CardTitle,
161
+ CardSubtitle,
162
+ CardText,
163
+ CardLink,
164
+ CardImg,
165
+ CardImgOverlay,
166
+ CardGroup,
167
+ Carousel,
168
+ CarouselRenderer,
169
+ CarouselItem,
170
+ CarouselCaption,
171
+ CarouselIndicator,
172
+ CloseButton,
173
+ Collapse,
174
+ CollapseToggle,
175
+ Dropdown,
176
+ DropdownToggle,
177
+ DropdownMenu,
178
+ DropdownItem,
179
+ DropdownDivider,
180
+ DropdownHeader,
181
+ DropdownItemText,
182
+ DropdownButton,
183
+ SplitButton,
184
+ Figure,
185
+ FigureImage,
186
+ FigureCaption,
187
+ Form,
188
+ FormGroup,
189
+ FormLabel,
190
+ FormControl,
191
+ FormTextarea,
192
+ FormSelect,
193
+ FormCheckInput,
194
+ FormCheckLabel,
195
+ FormCheck,
196
+ FormText,
197
+ FormFloating,
198
+ FormRange,
199
+ Image,
200
+ InputGroup,
201
+ InputGroupText,
202
+ InputGroupRadio,
203
+ InputGroupCheckbox,
204
+ FloatingLabel,
205
+ Container,
206
+ Row,
207
+ Col,
208
+ ListGroup,
209
+ ListGroupItem,
210
+ Modal,
211
+ ModalHeader,
212
+ ModalBody,
213
+ ModalFooter,
214
+ ModalTitle,
215
+ ModalToggle,
216
+ Nav,
217
+ NavItem,
218
+ NavLink,
219
+ NavDropdown,
220
+ Navbar,
221
+ NavbarBrand,
222
+ NavbarToggler,
223
+ NavbarCollapse,
224
+ NavbarNav,
225
+ NavbarText,
226
+ Offcanvas,
227
+ OffcanvasHeader,
228
+ OffcanvasBody,
229
+ OffcanvasTitle,
230
+ OffcanvasToggle,
231
+ Pagination,
232
+ PaginationItem,
233
+ PageLink,
234
+ PaginationFirst,
235
+ PaginationPrev,
236
+ PaginationNext,
237
+ PaginationLast,
238
+ PaginationEllipsis,
239
+ Placeholder,
240
+ PlaceholderButton,
241
+ Popover,
242
+ Progress,
243
+ ProgressStacked,
244
+ ProgressBar,
245
+ Spinner,
246
+ Stack,
247
+ Table,
248
+ TabContainer,
249
+ TabContent,
250
+ TabPane,
251
+ TabsRenderer,
252
+ Tabs,
253
+ Tab,
254
+ ToastContainer,
255
+ Toast,
256
+ ToastHeader,
257
+ ToastBody,
258
+ ToggleButtonGroup,
259
+ ToggleButton,
260
+ Tooltip,
261
+ ),
262
+ )
263
+
264
+
265
+ def _republished(
266
+ component: type[LibraryComponent], prefix: str, override: "Mapping[type, type]"
267
+ ) -> type[LibraryComponent]:
268
+ """One component under `prefix`, with its sibling references following."""
269
+ definition = override.get(component, component)
270
+ name = prefix + component.name.removeprefix(PREFIX)
271
+ changes: dict[str, object] = {"name": name}
272
+ template = getattr(definition, "template", None)
273
+ if isinstance(template, str) and f"<c-{PREFIX}" in template:
274
+ changes["template"] = template.replace(f"<c-{PREFIX}", f"<c-{prefix}").replace(
275
+ f"</c-{PREFIX}", f"</c-{prefix}"
276
+ )
277
+ return type(definition.__name__, (definition,), changes)
278
+
279
+
280
+ def library(
281
+ *, prefix: str = PREFIX, override: "Mapping[type, type] | None" = None
282
+ ) -> ComponentLibrary:
283
+ """The manifest, published under `prefix`, with components replaced.
284
+
285
+ A component's template names its siblings, so the prefix is rewritten in
286
+ both places at once. Nothing is published under the old prefix afterwards.
287
+ """
288
+ override = dict(override or {})
289
+ unknown = set(override) - set(__citry_library__.components)
290
+ if unknown:
291
+ names = ", ".join(sorted(c.__name__ for c in unknown))
292
+ msg = f"not part of this library: {names}"
293
+ raise ValueError(msg)
294
+ if prefix == PREFIX and not override:
295
+ return __citry_library__
296
+ return ComponentLibrary(
297
+ name="citry-bootstrap",
298
+ required_extensions=("plain_inputs",),
299
+ components=tuple(_republished(c, prefix, override) for c in __citry_library__.components),
300
+ )
301
+
302
+
303
+ def install(
304
+ app: Citry, *, prefix: str = PREFIX, override: "Mapping[type, type] | None" = None
305
+ ) -> LibraryInstallation:
306
+ """Register the library.
307
+
308
+ Components are published as `<c-bs-button>`. `prefix` changes that for all
309
+ of them - `prefix=""` gives `<c-button>` - and `override` swaps one for your
310
+ own subclass, which every sibling then renders too:
311
+
312
+ install(app, prefix="ui-", override={CardBody: MyCardBody})
313
+ """
314
+ return app.register_library(library(prefix=prefix, override=override))
315
+
316
+
317
+ __all__ = [
318
+ "install",
319
+ "__citry_library__",
320
+ "PlainInputs",
321
+ "Accordion",
322
+ "AccordionItem",
323
+ "AccordionButton",
324
+ "AccordionHeader",
325
+ "AccordionBody",
326
+ "Alert",
327
+ "AlertLink",
328
+ "AlertHeading",
329
+ "Badge",
330
+ "Breadcrumb",
331
+ "BreadcrumbItem",
332
+ "Button",
333
+ "ButtonGroup",
334
+ "ButtonToolbar",
335
+ "Card",
336
+ "CardHeader",
337
+ "CardBody",
338
+ "CardFooter",
339
+ "CardTitle",
340
+ "CardSubtitle",
341
+ "CardText",
342
+ "CardLink",
343
+ "CardImg",
344
+ "CardImgOverlay",
345
+ "CardGroup",
346
+ "Carousel",
347
+ "CarouselRenderer",
348
+ "CarouselItem",
349
+ "CarouselCaption",
350
+ "CarouselIndicator",
351
+ "CloseButton",
352
+ "Collapse",
353
+ "CollapseToggle",
354
+ "Dropdown",
355
+ "DropdownToggle",
356
+ "DropdownMenu",
357
+ "DropdownItem",
358
+ "DropdownDivider",
359
+ "DropdownHeader",
360
+ "DropdownItemText",
361
+ "DropdownButton",
362
+ "SplitButton",
363
+ "Figure",
364
+ "FigureImage",
365
+ "FigureCaption",
366
+ "Form",
367
+ "FormGroup",
368
+ "FormLabel",
369
+ "FormControl",
370
+ "FormTextarea",
371
+ "FormSelect",
372
+ "FormCheckInput",
373
+ "FormCheckLabel",
374
+ "FormCheck",
375
+ "FormText",
376
+ "FormFloating",
377
+ "FormRange",
378
+ "Image",
379
+ "InputGroup",
380
+ "InputGroupText",
381
+ "InputGroupRadio",
382
+ "InputGroupCheckbox",
383
+ "FloatingLabel",
384
+ "Container",
385
+ "Row",
386
+ "Col",
387
+ "ListGroup",
388
+ "ListGroupItem",
389
+ "Modal",
390
+ "ModalHeader",
391
+ "ModalBody",
392
+ "ModalFooter",
393
+ "ModalTitle",
394
+ "ModalToggle",
395
+ "Nav",
396
+ "NavItem",
397
+ "NavLink",
398
+ "NavDropdown",
399
+ "Navbar",
400
+ "NavbarBrand",
401
+ "NavbarToggler",
402
+ "NavbarCollapse",
403
+ "NavbarNav",
404
+ "NavbarText",
405
+ "Offcanvas",
406
+ "OffcanvasHeader",
407
+ "OffcanvasBody",
408
+ "OffcanvasTitle",
409
+ "OffcanvasToggle",
410
+ "Pagination",
411
+ "PaginationItem",
412
+ "PageLink",
413
+ "PaginationFirst",
414
+ "PaginationPrev",
415
+ "PaginationNext",
416
+ "PaginationLast",
417
+ "PaginationEllipsis",
418
+ "Placeholder",
419
+ "PlaceholderButton",
420
+ "Popover",
421
+ "Progress",
422
+ "ProgressStacked",
423
+ "ProgressBar",
424
+ "Spinner",
425
+ "Stack",
426
+ "Table",
427
+ "TabContainer",
428
+ "TabContent",
429
+ "TabPane",
430
+ "TabsRenderer",
431
+ "Tabs",
432
+ "Tab",
433
+ "ToastContainer",
434
+ "Toast",
435
+ "ToastHeader",
436
+ "ToastBody",
437
+ "ToggleButtonGroup",
438
+ "ToggleButton",
439
+ "Tooltip",
440
+ ]
File without changes
@@ -0,0 +1,82 @@
1
+ from .accordion import Accordion, AccordionBody, AccordionButton, AccordionHeader, AccordionItem
2
+ from .alert import Alert, AlertHeading, AlertLink
3
+ from .badge import Badge
4
+ from .breadcrumb import Breadcrumb, BreadcrumbItem
5
+ from .button import Button
6
+ from .button_group import ButtonGroup, ButtonToolbar
7
+ from .card import (
8
+ Card,
9
+ CardBody,
10
+ CardFooter,
11
+ CardGroup,
12
+ CardHeader,
13
+ CardImg,
14
+ CardImgOverlay,
15
+ CardLink,
16
+ CardSubtitle,
17
+ CardText,
18
+ CardTitle,
19
+ )
20
+ from .carousel import Carousel, CarouselCaption, CarouselIndicator, CarouselItem, CarouselRenderer
21
+ from .close_button import CloseButton
22
+ from .collapse import Collapse, CollapseToggle
23
+ from .dropdown import (
24
+ Dropdown,
25
+ DropdownDivider,
26
+ DropdownHeader,
27
+ DropdownItem,
28
+ DropdownItemText,
29
+ DropdownMenu,
30
+ DropdownToggle,
31
+ )
32
+ from .dropdown_button import DropdownButton, SplitButton
33
+ from .figure import Figure, FigureCaption, FigureImage
34
+ from .form import (
35
+ Form,
36
+ FormCheck,
37
+ FormCheckInput,
38
+ FormCheckLabel,
39
+ FormControl,
40
+ FormFloating,
41
+ FormGroup,
42
+ FormLabel,
43
+ FormSelect,
44
+ FormText,
45
+ FormTextarea,
46
+ )
47
+ from .form_range import FormRange
48
+ from .image import Image
49
+ from .input_group import (
50
+ FloatingLabel,
51
+ InputGroup,
52
+ InputGroupCheckbox,
53
+ InputGroupRadio,
54
+ InputGroupText,
55
+ )
56
+ from .layout import Col, Container, Row
57
+ from .list_group import ListGroup, ListGroupItem
58
+ from .modal import Modal, ModalBody, ModalFooter, ModalHeader, ModalTitle, ModalToggle
59
+ from .nav import Nav, NavItem, NavLink
60
+ from .nav_dropdown import NavDropdown
61
+ from .navbar import Navbar, NavbarBrand, NavbarCollapse, NavbarNav, NavbarText, NavbarToggler
62
+ from .offcanvas import Offcanvas, OffcanvasBody, OffcanvasHeader, OffcanvasTitle, OffcanvasToggle
63
+ from .pagination import (
64
+ PageLink,
65
+ Pagination,
66
+ PaginationEllipsis,
67
+ PaginationFirst,
68
+ PaginationItem,
69
+ PaginationLast,
70
+ PaginationNext,
71
+ PaginationPrev,
72
+ )
73
+ from .placeholder import Placeholder, PlaceholderButton
74
+ from .popover import Popover
75
+ from .progress import Progress, ProgressBar, ProgressStacked
76
+ from .spinner import Spinner
77
+ from .stack import Stack
78
+ from .table import Table
79
+ from .tabs import Tab, TabContainer, TabContent, TabPane, Tabs, TabsRenderer
80
+ from .toast import Toast, ToastBody, ToastContainer, ToastHeader
81
+ from .toggle_button import ToggleButton, ToggleButtonGroup
82
+ from .tooltip import Tooltip
@@ -0,0 +1,197 @@
1
+ from citry import LibraryComponent, SlotInput, merge_attrs
2
+
3
+
4
+ class Accordion(LibraryComponent):
5
+ name = "bs-accordion"
6
+
7
+ class Kwargs:
8
+ flush: bool = False
9
+ always_open: bool = False
10
+ attrs: dict | None = None
11
+
12
+ class Slots:
13
+ default: SlotInput
14
+
15
+ def template_data(self, kwargs: Kwargs, slots: Slots):
16
+ accordion_id = (kwargs.attrs or {}).get("id") or f"accordion-{self.id}"
17
+
18
+ css_classes = ["accordion"]
19
+ if kwargs.flush:
20
+ css_classes.append("accordion-flush")
21
+
22
+ data = {
23
+ "accordion_id": accordion_id,
24
+ "css_class": " ".join(css_classes),
25
+ "always_open": kwargs.always_open,
26
+ "attrs": kwargs.attrs,
27
+ }
28
+ data["div_attrs"] = merge_attrs(
29
+ {"id": data["accordion_id"]}, (data["attrs"] or {}), {"class": data["css_class"]}
30
+ )
31
+ return data
32
+
33
+ template = """
34
+ <c-provide key="accordion" c-accordion_id="accordion_id" c-always_open="always_open">
35
+ <div c-bind="div_attrs">
36
+ <c-slot />
37
+ </div>
38
+ </c-provide>
39
+ """
40
+
41
+
42
+ class AccordionItem(LibraryComponent):
43
+ name = "bs-accordion-item"
44
+
45
+ class Kwargs:
46
+ default_open: bool = False
47
+ attrs: dict | None = None
48
+
49
+ class Slots:
50
+ default: SlotInput
51
+
52
+ def template_data(self, kwargs: Kwargs, slots: Slots):
53
+ accordion = self.inject("accordion")
54
+
55
+ item_id = (kwargs.attrs or {}).get("id") or f"accordion-item-{self.id}"
56
+ heading_id = f"{item_id}-heading"
57
+ collapse_id = f"{item_id}-collapse"
58
+ data_bs_parent = f"#{accordion.accordion_id}"
59
+
60
+ data = {
61
+ "heading_id": heading_id,
62
+ "collapse_id": collapse_id,
63
+ "is_open": kwargs.default_open,
64
+ "data_bs_parent": data_bs_parent,
65
+ "always_open": accordion.always_open,
66
+ "attrs": kwargs.attrs,
67
+ }
68
+ data["div_attrs"] = merge_attrs((data["attrs"] or {}), {"class": "accordion-item"})
69
+ return data
70
+
71
+ template = """
72
+ <c-provide key="accordion_item" c-heading_id="heading_id" c-collapse_id="collapse_id" c-is_open="is_open" c-data_bs_parent="data_bs_parent" c-always_open="always_open">
73
+ <div c-bind="div_attrs">
74
+ <c-slot />
75
+ </div>
76
+ </c-provide>
77
+ """
78
+
79
+
80
+ class AccordionButton(LibraryComponent):
81
+ name = "bs-accordion-button"
82
+
83
+ class Kwargs:
84
+ disabled: bool = False
85
+ attrs: dict | None = None
86
+
87
+ class Slots:
88
+ default: SlotInput
89
+
90
+ def template_data(self, kwargs: Kwargs, slots: Slots):
91
+ accordion_item = self.inject("accordion_item")
92
+
93
+ classes = ["accordion-button"]
94
+ if not accordion_item.is_open:
95
+ classes.append("collapsed")
96
+
97
+ data = {
98
+ "button_classes": " ".join(classes),
99
+ "collapse_id": accordion_item.collapse_id,
100
+ "aria_expanded": "true" if accordion_item.is_open else "false",
101
+ "disabled": kwargs.disabled,
102
+ "attrs": kwargs.attrs,
103
+ }
104
+ data["button_attrs"] = merge_attrs(
105
+ {
106
+ "aria-expanded": data["aria_expanded"],
107
+ "aria-controls": data["collapse_id"],
108
+ "disabled": data["disabled"],
109
+ },
110
+ (data["attrs"] or {}),
111
+ {
112
+ "class": data["button_classes"],
113
+ "type": "button",
114
+ "data-bs-toggle": "collapse",
115
+ "data-bs-target": f"#{data['collapse_id']}",
116
+ },
117
+ )
118
+ return data
119
+
120
+ template = """
121
+ <button c-bind="button_attrs">
122
+ <c-slot />
123
+ </button>
124
+ """
125
+
126
+
127
+ class AccordionHeader(LibraryComponent):
128
+ name = "bs-accordion-header"
129
+
130
+ class Kwargs:
131
+ disabled: bool = False
132
+ attrs: dict | None = None
133
+
134
+ class Slots:
135
+ default: SlotInput
136
+
137
+ def template_data(self, kwargs: Kwargs, slots: Slots):
138
+ accordion_item = self.inject("accordion_item")
139
+
140
+ data = {
141
+ "heading_id": accordion_item.heading_id,
142
+ "disabled": kwargs.disabled,
143
+ "attrs": kwargs.attrs,
144
+ }
145
+ data["h2_attrs"] = merge_attrs(
146
+ {"id": data["heading_id"]}, (data["attrs"] or {}), {"class": "accordion-header"}
147
+ )
148
+ return data
149
+
150
+ template = """
151
+ <h2 c-bind="h2_attrs">
152
+ <c-bs-accordion-button c-disabled="disabled">
153
+ <c-slot />
154
+ </c-bs-accordion-button>
155
+ </h2>
156
+ """
157
+
158
+
159
+ class AccordionBody(LibraryComponent):
160
+ name = "bs-accordion-body"
161
+
162
+ class Kwargs:
163
+ attrs: dict | None = None
164
+
165
+ class Slots:
166
+ default: SlotInput
167
+
168
+ def template_data(self, kwargs: Kwargs, slots: Slots):
169
+ accordion_item = self.inject("accordion_item")
170
+
171
+ collapse_classes = ["accordion-collapse", "collapse"]
172
+ if accordion_item.is_open:
173
+ collapse_classes.append("show")
174
+
175
+ data = {
176
+ "heading_id": accordion_item.heading_id,
177
+ "collapse_id": accordion_item.collapse_id,
178
+ "collapse_classes": " ".join(collapse_classes),
179
+ "data_bs_parent": accordion_item.data_bs_parent,
180
+ "always_open": accordion_item.always_open,
181
+ "attrs": kwargs.attrs,
182
+ }
183
+ data["div_attrs"] = merge_attrs(
184
+ {"aria-labelledby": data["heading_id"]},
185
+ {"id": data["collapse_id"], "class": data["collapse_classes"]},
186
+ ({"data-bs-parent": data["data_bs_parent"]} if (not data["always_open"]) else {}),
187
+ )
188
+ data["div_attrs2"] = merge_attrs((data["attrs"] or {}), {"class": "accordion-body"})
189
+ return data
190
+
191
+ template = """
192
+ <div c-bind="div_attrs" >
193
+ <div c-bind="div_attrs2">
194
+ <c-slot />
195
+ </div>
196
+ </div>
197
+ """