fluent-blue 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 (95) hide show
  1. fluent_blue/__init__.py +27 -0
  2. fluent_blue/agent_prompts.py +197 -0
  3. fluent_blue/compatibility/__init__.py +4 -0
  4. fluent_blue/compatibility/qt.py +108 -0
  5. fluent_blue/components/__init__.py +10 -0
  6. fluent_blue/components/advanced/__init__.py +10 -0
  7. fluent_blue/components/advanced/datetime_pickers.py +380 -0
  8. fluent_blue/components/advanced/editors.py +557 -0
  9. fluent_blue/components/advanced/pickers.py +344 -0
  10. fluent_blue/components/advanced/structure.py +534 -0
  11. fluent_blue/components/base.py +124 -0
  12. fluent_blue/components/buttons/__init__.py +18 -0
  13. fluent_blue/components/buttons/button.py +230 -0
  14. fluent_blue/components/buttons/split_button.py +50 -0
  15. fluent_blue/components/data/__init__.py +5 -0
  16. fluent_blue/components/data/model.py +232 -0
  17. fluent_blue/components/data/table.py +473 -0
  18. fluent_blue/components/display/__init__.py +12 -0
  19. fluent_blue/components/display/card.py +192 -0
  20. fluent_blue/components/display/console.py +139 -0
  21. fluent_blue/components/display/content.py +387 -0
  22. fluent_blue/components/display/media.py +379 -0
  23. fluent_blue/components/display/text.py +215 -0
  24. fluent_blue/components/feedback/__init__.py +17 -0
  25. fluent_blue/components/feedback/feedback.py +566 -0
  26. fluent_blue/components/inputs/__init__.py +9 -0
  27. fluent_blue/components/inputs/form.py +125 -0
  28. fluent_blue/components/inputs/input.py +287 -0
  29. fluent_blue/components/inputs/tags_otp.py +286 -0
  30. fluent_blue/components/layout/__init__.py +9 -0
  31. fluent_blue/components/layout/containers.py +318 -0
  32. fluent_blue/components/layout/overlays.py +247 -0
  33. fluent_blue/components/layout/window.py +159 -0
  34. fluent_blue/components/navigation/__init__.py +10 -0
  35. fluent_blue/components/navigation/command_palette.py +185 -0
  36. fluent_blue/components/navigation/menu.py +118 -0
  37. fluent_blue/components/navigation/sidebar.py +243 -0
  38. fluent_blue/components/navigation/wayfinding.py +252 -0
  39. fluent_blue/components/popup.py +61 -0
  40. fluent_blue/components/selection/__init__.py +8 -0
  41. fluent_blue/components/selection/choice.py +242 -0
  42. fluent_blue/components/selection/controls.py +317 -0
  43. fluent_blue/core/__init__.py +6 -0
  44. fluent_blue/core/animations.py +51 -0
  45. fluent_blue/core/configuration.py +25 -0
  46. fluent_blue/core/palette.py +315 -0
  47. fluent_blue/core/theme_manager.py +273 -0
  48. fluent_blue/core/tokens.py +175 -0
  49. fluent_blue/core/typography.py +57 -0
  50. fluent_blue/icons/__init__.py +8 -0
  51. fluent_blue/icons/engine.py +137 -0
  52. fluent_blue/icons/library.py +147 -0
  53. fluent_blue/resources/fonts/Inter-Bold.ttf +0 -0
  54. fluent_blue/resources/fonts/Inter-Medium.ttf +0 -0
  55. fluent_blue/resources/fonts/Inter-Regular.ttf +0 -0
  56. fluent_blue/resources/fonts/Inter-SemiBold.ttf +0 -0
  57. fluent_blue/studio/CHANGELOG.md +23 -0
  58. fluent_blue/studio/__init__.py +1 -0
  59. fluent_blue/studio/app.py +324 -0
  60. fluent_blue/studio/art.py +164 -0
  61. fluent_blue/studio/catalog/__init__.py +46 -0
  62. fluent_blue/studio/catalog/added.py +49 -0
  63. fluent_blue/studio/catalog/advanced.py +120 -0
  64. fluent_blue/studio/catalog/buttons.py +88 -0
  65. fluent_blue/studio/catalog/data_tables.py +43 -0
  66. fluent_blue/studio/catalog/display.py +132 -0
  67. fluent_blue/studio/catalog/feedback.py +100 -0
  68. fluent_blue/studio/catalog/inputs.py +63 -0
  69. fluent_blue/studio/catalog/layout.py +82 -0
  70. fluent_blue/studio/catalog/navigation.py +105 -0
  71. fluent_blue/studio/catalog/selection.py +65 -0
  72. fluent_blue/studio/introspect.py +156 -0
  73. fluent_blue/studio/pages/__init__.py +1 -0
  74. fluent_blue/studio/pages/components.py +217 -0
  75. fluent_blue/studio/pages/foundations.py +316 -0
  76. fluent_blue/studio/pages/overview.py +669 -0
  77. fluent_blue/studio/pages/tools.py +191 -0
  78. fluent_blue/themes/__init__.py +4 -0
  79. fluent_blue/themes/stylesheet/__init__.py +11 -0
  80. fluent_blue/themes/stylesheet/base.py +85 -0
  81. fluent_blue/themes/stylesheet/buttons.py +56 -0
  82. fluent_blue/themes/stylesheet/context.py +55 -0
  83. fluent_blue/themes/stylesheet/data.py +20 -0
  84. fluent_blue/themes/stylesheet/display.py +82 -0
  85. fluent_blue/themes/stylesheet/feedback.py +30 -0
  86. fluent_blue/themes/stylesheet/inputs.py +85 -0
  87. fluent_blue/themes/stylesheet/navigation.py +51 -0
  88. fluent_blue/themes/stylesheet/selection.py +56 -0
  89. fluent_blue/themes/stylesheet/studio.py +26 -0
  90. fluent_blue/utilities/__init__.py +0 -0
  91. fluent_blue-0.1.0.dist-info/METADATA +303 -0
  92. fluent_blue-0.1.0.dist-info/RECORD +95 -0
  93. fluent_blue-0.1.0.dist-info/WHEEL +4 -0
  94. fluent_blue-0.1.0.dist-info/entry_points.txt +2 -0
  95. fluent_blue-0.1.0.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,27 @@
1
+ """Fluent Blue: a design system for PyQt6 and PySide6 desktop applications.
2
+
3
+ >>> from fluent_blue import Button, ThemeManager # doctest: +SKIP
4
+ """
5
+ from .compatibility import BINDING, BINDING_VERSION, QT_VERSION
6
+ from .components import advanced, buttons, data, display, feedback, inputs, layout, navigation, selection
7
+ from .components.advanced import * # noqa: F403
8
+ from .components.buttons import * # noqa: F403
9
+ from .components.data import * # noqa: F403
10
+ from .components.display import * # noqa: F403
11
+ from .components.feedback import * # noqa: F403
12
+ from .components.inputs import * # noqa: F403
13
+ from .components.layout import * # noqa: F403
14
+ from .components.navigation import * # noqa: F403
15
+ from .components.selection import * # noqa: F403
16
+ from .core import Configuration, DesignTokens, Theme, ThemeManager, config, configure
17
+ from .icons import has_icon, icon, icon_names, icon_pixmap, register_icon, register_icon_file
18
+
19
+ __version__ = "0.1.0"
20
+
21
+ __all__ = [
22
+ "BINDING", "BINDING_VERSION", "QT_VERSION", "Configuration", "DesignTokens", "Theme", "ThemeManager", "__version__",
23
+ "config", "configure", "has_icon", "icon", "icon_names", "icon_pixmap", "register_icon", "register_icon_file",
24
+ ]
25
+ for _module in (advanced, buttons, data, display, feedback, inputs, layout, navigation, selection):
26
+ __all__ += _module.__all__
27
+ del _module
@@ -0,0 +1,197 @@
1
+ """Ready-to-use briefs that let an AI coding agent work with each Fluent Blue component.
2
+
3
+ Every brief is generated from the installed source: constructor signatures, docstrings,
4
+ signals, public methods and the catalog snippet that the test suite executes. It therefore
5
+ cannot describe an API that does not exist.
6
+
7
+ python -m fluent_blue.agent_prompts Button # print one brief
8
+ python -m fluent_blue.agent_prompts --list # list component names
9
+ python -m fluent_blue.agent_prompts --export DIR # write AGENTS.md, llms.txt and one file each
10
+ """
11
+ from __future__ import annotations
12
+
13
+ import argparse
14
+ import inspect
15
+ from pathlib import Path
16
+
17
+ from .studio import catalog, introspect
18
+
19
+ PROJECT_RULES = """\
20
+ - Import components from `fluent_blue`, and Qt names from `fluent_blue.compatibility.qt`. Never import `PyQt6` or `PySide6` directly in library code, and never load both in one process.
21
+ - Style through props and design tokens. Do not call `setStyleSheet` on components, and do not hardcode colors, spacing, radii or fonts.
22
+ - Read theme values with `ThemeManager.color("role")`, `.qcolor("role")`, `.spacing(step)`, `.radius("md")` and `.font("role")`. For custom painting, read them inside `paintEvent`.
23
+ - Subclass with `ThemedMixin`, call `self.bind_theme()`, and rebuild cached pixmaps in `refresh_theme()`, so that runtime theme switches work.
24
+ - Never connect a lambda or closure that captures a widget to `ThemeManager` signals: it outlives the widget, and PyQt aborts when it fires. Use `ThemedMixin` or a bound method.
25
+ - Keep theme switches fast: do not rebuild child widgets in `refresh_theme()`, and free one-shot menus and dialogs with `WA_DeleteOnClose` or `finished.connect(dialog.deleteLater)`.
26
+ - Use icon names from `icon_names()`, or add one with `register_icon`. Icon-only controls need a `tooltip`, which also becomes the accessible name.
27
+ - Text needs at least 4.5:1 contrast. Keep keyboard access and visible focus.
28
+ - Fluent Blue signals and methods use `snake_case`. Inherited Qt API stays `camelCase`.
29
+ - Verify your change on both bindings: `FLUENT_BLUE_QT_BINDING=PyQt6 pytest` and `FLUENT_BLUE_QT_BINDING=PySide6 pytest`, then `python scripts/ui_audit.py`. Never report a result you did not run."""
30
+
31
+
32
+ _INTERNAL_METHODS = {"bind_theme", "refresh_theme", "paint_gutter", "show"}
33
+
34
+
35
+ def public_classes() -> list[str]:
36
+ """Names of every exported widget and helper class that needs a brief."""
37
+ import fluent_blue
38
+
39
+ skip = {"Configuration", "DesignTokens", "Theme"}
40
+ names = []
41
+ for name in fluent_blue.__all__:
42
+ value = getattr(fluent_blue, name)
43
+ if inspect.isclass(value) and name not in skip and value.__module__.startswith("fluent_blue.components"):
44
+ names.append(name)
45
+ return sorted(set(names))
46
+
47
+
48
+ def _entries() -> dict[str, catalog.Entry]:
49
+ return {entry.name: entry for entry in catalog.entries()}
50
+
51
+
52
+ def _signature(cls) -> str:
53
+ target = introspect._api_target(cls)
54
+ label = f"{cls.__name__}.show" if target is not cls.__init__ else cls.__name__
55
+ parameters = []
56
+ for prop in introspect.properties(cls):
57
+ parameters.append(prop.name if prop.default == "required" else f"{prop.name}={prop.default}")
58
+ return f"{label}({', '.join(parameters)})"
59
+
60
+
61
+ def _methods(cls) -> list[tuple[str, str]]:
62
+ found = {}
63
+ for klass in cls.__mro__:
64
+ if not klass.__module__.startswith("fluent_blue"):
65
+ continue
66
+ for name, value in vars(klass).items():
67
+ if name.startswith("_") or name[0].isupper() or name in found or name in _INTERNAL_METHODS:
68
+ continue
69
+ function = value.__func__ if isinstance(value, (staticmethod, classmethod)) else value
70
+ if inspect.isfunction(function) and name[0].islower() and not any(c.isupper() for c in name):
71
+ doc = inspect.cleandoc(function.__doc__ or "").split("\n")[0]
72
+ signature = str(inspect.signature(function)).replace("(self, ", "(").replace("(self)", "()").replace("'", "")
73
+ found[name] = (f"{name}{signature}".replace(" -> None", ""), introspect.clean_markup(doc))
74
+ return sorted(found.values())
75
+
76
+
77
+ def group_of(name: str) -> str:
78
+ entry = _entries().get(name)
79
+ return entry.group if entry else "Uncatalogued"
80
+
81
+
82
+ def component_prompt(name: str) -> str:
83
+ """Return the Markdown brief for one component. Raises ``KeyError`` for an unknown name."""
84
+ if name not in public_classes():
85
+ raise KeyError(f"Unknown component {name!r}. Available: {', '.join(public_classes())}")
86
+ import fluent_blue
87
+
88
+ cls = getattr(fluent_blue, name)
89
+ entry = _entries().get(name)
90
+ bases = [b.__name__ for b in cls.__mro__[1:] if b.__module__.split(".")[0] in ("PyQt6", "PySide6")]
91
+ lines = [
92
+ f"# {name}", "",
93
+ "You are working with the Fluent Blue design system for PyQt6 and PySide6. Use this brief as the source of truth for this component's API, and do not invent parameters.", "",
94
+ "## Purpose", "", introspect.summary(cls), "",
95
+ f"Group: {group_of(name)}. " + (f"Qt base: `{bases[0]}`, whose full API stays available." if bases else "Plain Python helper."), "",
96
+ "## Import", "", "```python", f"from fluent_blue import {name}", "```", "",
97
+ "## Signature", "", "```python", _signature(cls), "```", "",
98
+ ]
99
+ props = [p for p in introspect.properties(cls)]
100
+ if props:
101
+ lines += ["## Parameters", "", "| Name | Default | Description |", "| --- | --- | --- |"]
102
+ lines += [f"| `{p.name}` | `{p.default}` | {introspect.clean_markup(p.description).replace('|', chr(92) + '|')} |" for p in props]
103
+ lines.append("")
104
+ signals = introspect.signals(cls)
105
+ note = introspect.inherited_signals_note(cls)
106
+ if signals or note:
107
+ lines += ["## Signals", ""]
108
+ lines += [f"- `{s.name}({s.args})`: {introspect.clean_markup(s.description)}" for s in signals]
109
+ if note:
110
+ lines.append(f"- {introspect.clean_markup(note)}")
111
+ lines.append("")
112
+ methods = _methods(cls)
113
+ if methods:
114
+ lines += ["## Public methods", ""]
115
+ lines += [f"- `{signature}`" + (f": {doc}" if doc else "") for signature, doc in methods]
116
+ lines.append("")
117
+ if entry:
118
+ lines += ["## Verified example", "", "This snippet is executed by the test suite on both Qt bindings.", "", "```python", entry.code.strip(), "```", ""]
119
+ lines += ["## Usage guidance", ""] + [f"- {tip}" for tip in entry.tips] + [""]
120
+ lines += ["## Project rules", "", PROJECT_RULES, ""]
121
+ return "\n".join(lines)
122
+
123
+
124
+ def library_prompt() -> str:
125
+ """Return the brief for the whole library, suitable for ``AGENTS.md``."""
126
+ lines = [
127
+ "# Fluent Blue: guide for AI coding agents", "",
128
+ "Fluent Blue is a design system for Python desktop applications on PyQt6 and PySide6.", "",
129
+ "## Rules", "", PROJECT_RULES, "",
130
+ "## Quick start", "", "```python",
131
+ "from fluent_blue import Button, Card, ThemeManager",
132
+ "from fluent_blue.compatibility.qt import QApplication, QVBoxLayout", "",
133
+ "app = QApplication([])", 'ThemeManager.set_theme("light")', "card = Card()", "layout = QVBoxLayout(card)",
134
+ 'layout.addWidget(Button("Get Started", variant="primary"))', "card.show()", "app.exec()", "```", "",
135
+ "## Component briefs", "",
136
+ "Read the brief for a component before you use or change it. Print one with `python -m fluent_blue.agent_prompts <Name>`.", "",
137
+ ]
138
+ grouped: dict[str, list[str]] = {}
139
+ for name in public_classes():
140
+ grouped.setdefault(group_of(name), []).append(name)
141
+ for group in (*catalog.GROUPS, "Uncatalogued"):
142
+ if group in grouped:
143
+ lines += [f"### {group}", ""]
144
+ import fluent_blue
145
+
146
+ for name in grouped[group]:
147
+ lines.append(f"- [`{name}`](docs/ai/components/{name}.md): {introspect.summary(getattr(fluent_blue, name))}")
148
+ lines.append("")
149
+ return "\n".join(lines)
150
+
151
+
152
+ def llms_txt() -> str:
153
+ """Return an index in the llms.txt format."""
154
+ import fluent_blue
155
+
156
+ lines = ["# Fluent Blue", "", "> A design system for Python desktop applications on PyQt6 and PySide6.", "", "## Components", ""]
157
+ lines += [f"- [{n}](docs/ai/components/{n}.md): {introspect.summary(getattr(fluent_blue, n))}" for n in public_classes()]
158
+ return "\n".join(lines) + "\n"
159
+
160
+
161
+ def export(root: Path) -> int:
162
+ """Write ``AGENTS.md``, ``llms.txt`` and ``docs/ai/components/*.md``. Returns the brief count."""
163
+ folder = root / "docs" / "ai" / "components"
164
+ folder.mkdir(parents=True, exist_ok=True)
165
+ names = public_classes()
166
+ for stale in folder.glob("*.md"):
167
+ if stale.stem not in names:
168
+ stale.unlink()
169
+ for name in names:
170
+ (folder / f"{name}.md").write_text(component_prompt(name), encoding="utf-8")
171
+ (root / "AGENTS.md").write_text(library_prompt(), encoding="utf-8")
172
+ (root / "llms.txt").write_text(llms_txt(), encoding="utf-8")
173
+ return len(names)
174
+
175
+
176
+ def main(argv=None) -> int:
177
+ parser = argparse.ArgumentParser(description="Print or export Fluent Blue briefs for AI coding agents.")
178
+ parser.add_argument("component", nargs="?", help="Component name, such as Button.")
179
+ parser.add_argument("--list", action="store_true", help="List component names.")
180
+ parser.add_argument("--library", action="store_true", help="Print the whole-library brief.")
181
+ parser.add_argument("--export", type=Path, metavar="DIR", help="Write AGENTS.md, llms.txt and docs/ai/components/ under DIR.")
182
+ args = parser.parse_args(argv)
183
+ if args.export:
184
+ print(f"Wrote {export(args.export)} component briefs to {args.export}")
185
+ elif args.list:
186
+ print("\n".join(public_classes()))
187
+ elif args.library:
188
+ print(library_prompt())
189
+ elif args.component:
190
+ print(component_prompt(args.component))
191
+ else:
192
+ parser.print_help()
193
+ return 0
194
+
195
+
196
+ if __name__ == "__main__":
197
+ raise SystemExit(main())
@@ -0,0 +1,4 @@
1
+ """Qt binding compatibility layer."""
2
+ from .qt import BINDING, BINDING_VERSION, QT_VERSION
3
+
4
+ __all__ = ["BINDING", "BINDING_VERSION", "QT_VERSION"]
@@ -0,0 +1,108 @@
1
+ """Single import point for the active Qt binding.
2
+
3
+ Fluent Blue supports PyQt6 and PySide6 from the same source tree. Every module in
4
+ the package imports Qt names from here, so no other module knows which binding is
5
+ active. Selection order:
6
+
7
+ 1. A binding already imported by the host application.
8
+ 2. The ``FLUENT_BLUE_QT_BINDING`` environment variable (``PyQt6`` or ``PySide6``).
9
+ 3. PyQt6, then PySide6, whichever is installed first.
10
+
11
+ Loading both bindings in one process is unsafe, so that raises immediately.
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import importlib
16
+ import os
17
+ import sys
18
+
19
+ SUPPORTED_BINDINGS = ("PyQt6", "PySide6")
20
+
21
+
22
+ class BindingError(ImportError):
23
+ """Raised when no usable Qt binding exists or the selection is conflicting."""
24
+
25
+
26
+ def _select_binding() -> str:
27
+ loaded = [name for name in SUPPORTED_BINDINGS if name in sys.modules]
28
+ if len(loaded) > 1:
29
+ raise BindingError("PyQt6 and PySide6 are both loaded; use only one per process.")
30
+ forced = os.environ.get("FLUENT_BLUE_QT_BINDING")
31
+ if forced and forced not in SUPPORTED_BINDINGS:
32
+ raise BindingError(f"FLUENT_BLUE_QT_BINDING must be one of {SUPPORTED_BINDINGS}, got {forced!r}.")
33
+ if loaded:
34
+ if forced and forced != loaded[0]:
35
+ raise BindingError(f"FLUENT_BLUE_QT_BINDING={forced} but {loaded[0]} is already loaded.")
36
+ return loaded[0]
37
+ if forced:
38
+ return forced
39
+ for name in SUPPORTED_BINDINGS:
40
+ try:
41
+ importlib.import_module(f"{name}.QtCore")
42
+ except ImportError:
43
+ continue
44
+ return name
45
+ raise BindingError("Fluent Blue needs a Qt binding: pip install 'fluent-blue[pyqt6]' or 'fluent-blue[pyside6]'.")
46
+
47
+
48
+ BINDING = _select_binding()
49
+
50
+ # The Linux wheels of PySide6 6.9 to 6.12 corrupt the reference count of True/False whenever
51
+ # a Python-declared Signal is emitted (the macOS wheels do not). Python 3.12 makes those
52
+ # objects immortal, so the fault is harmless there; on 3.11 the interpreter aborts after a
53
+ # few hundred emits.
54
+ PYSIDE_MIN_PYTHON_ON_LINUX = (3, 12)
55
+ if BINDING == "PySide6" and sys.platform.startswith("linux") and sys.version_info < PYSIDE_MIN_PYTHON_ON_LINUX:
56
+ import warnings
57
+
58
+ warnings.warn(
59
+ "On Linux, Fluent Blue supports PySide6 on Python 3.12 or newer: the Linux wheels of PySide6 6.9 to 6.12 "
60
+ "corrupt reference counts when custom signals are emitted on Python 3.11, and the process can abort. "
61
+ "Use Python 3.12+ or PyQt6.",
62
+ RuntimeWarning, stacklevel=2,
63
+ )
64
+
65
+ QtCore = importlib.import_module(f"{BINDING}.QtCore")
66
+ QtGui = importlib.import_module(f"{BINDING}.QtGui")
67
+ QtWidgets = importlib.import_module(f"{BINDING}.QtWidgets")
68
+ QtSvg = importlib.import_module(f"{BINDING}.QtSvg")
69
+
70
+ if BINDING == "PyQt6":
71
+ Signal = QtCore.pyqtSignal
72
+ Slot = QtCore.pyqtSlot
73
+ Property = QtCore.pyqtProperty
74
+ BINDING_VERSION = QtCore.PYQT_VERSION_STR
75
+ else:
76
+ Signal = QtCore.Signal
77
+ Slot = QtCore.Slot
78
+ Property = QtCore.Property
79
+ BINDING_VERSION = importlib.import_module(BINDING).__version__
80
+
81
+ QT_VERSION = QtCore.qVersion()
82
+
83
+
84
+ def delete_now(obj) -> None:
85
+ """Destroy a QObject immediately, so app-wide restyling no longer has to visit it.
86
+
87
+ Deletion goes through Qt's deferred delete, which works identically on both bindings. Do
88
+ not disconnect Python slots first: ``disconnect`` of a bound method on PySide6 6.12 with
89
+ Python 3.11 corrupts the reference count of ``True``/``False`` and aborts the process
90
+ later, whereas destroying a connected receiver is clean.
91
+ """
92
+ if isinstance(obj, QtWidgets.QWidget):
93
+ obj.hide()
94
+ obj.setParent(None)
95
+ obj.deleteLater()
96
+ QtCore.QCoreApplication.sendPostedEvents(obj, QtCore.QEvent.Type.DeferredDelete.value)
97
+
98
+
99
+ SignalInstanceTypes = (QtCore.pyqtBoundSignal,) if BINDING == "PyQt6" else (QtCore.SignalInstance,)
100
+ SignalTypes = (QtCore.pyqtSignal,) if BINDING == "PyQt6" else (QtCore.Signal,)
101
+
102
+ # Re-export every Qt class so components can write
103
+ # ``from fluent_blue.compatibility.qt import QFrame, Qt, Signal``.
104
+ for _module in (QtCore, QtGui, QtWidgets, QtSvg):
105
+ for _name in dir(_module):
106
+ if _name.startswith("Q") and _name != "QT_VERSION":
107
+ globals()[_name] = getattr(_module, _name)
108
+ del _module, _name
@@ -0,0 +1,10 @@
1
+ """Fluent Blue component library."""
2
+ from .advanced import * # noqa: F403
3
+ from .buttons import * # noqa: F403
4
+ from .data import * # noqa: F403
5
+ from .display import * # noqa: F403
6
+ from .feedback import * # noqa: F403
7
+ from .inputs import * # noqa: F403
8
+ from .layout import * # noqa: F403
9
+ from .navigation import * # noqa: F403
10
+ from .selection import * # noqa: F403
@@ -0,0 +1,10 @@
1
+ """Advanced components."""
2
+ from .datetime_pickers import Calendar, DatePicker, TimePicker, TimePopup
3
+ from .editors import CodeEditor, LogViewer, RichTextArea, RichTextEditor, SyntaxHighlighter
4
+ from .pickers import ColorPicker, FilePicker
5
+ from .structure import FileTree, ImageViewer, Stepper, TreeView, Wizard
6
+
7
+ __all__ = [
8
+ "Calendar", "CodeEditor", "ColorPicker", "DatePicker", "FilePicker", "FileTree", "ImageViewer", "LogViewer",
9
+ "RichTextArea", "RichTextEditor", "Stepper", "SyntaxHighlighter", "TimePicker", "TimePopup", "TreeView", "Wizard",
10
+ ]