Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 21 additions & 5 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,16 +44,23 @@ the React components. Use `pixi run build-js` when you have only changed React
or CSS under `src/`.

Do not hand-edit anything under `dash_loading_components/` except
`loading.py`, `registry.py` and the family `__init__.py` files; the rest is
`loading.py`, `registry.py`, the package `__init__.py` (which imports each
family namespace) and the family `__init__.py` files; the rest is
generated by `dash-generate-components` from `src/lib/components/`.

## Adding a family

1. Add the upstream package to `package.json` and to `docs/UPSTREAM-INVENTORY.md`,
including its SPDX license and declared React peer range.
2. Add wrappers under `src/lib/components/<family>/`, one React file per
component, prefixed with the family name.
3. Export short names from `dash_loading_components/<family>/__init__.py`.
component, prefixed with the family name, and export them from
`src/lib/index.js`. If the upstream ships untranspiled ES modules, add it to
the `exclude` pattern in `webpack.config.js`. Import what you render by name:
a bare side-effect `import` can be tree-shaken out of the production bundle,
so check in a browser test that the component really paints.
3. Export short names from `dash_loading_components/<family>/__init__.py` and
import the namespace in `dash_loading_components/__init__.py` (both the
`from . import` line and `__all__`).
4. Register the family in `dash_loading_components/registry.py`, including its
native tempo prop and each spinner's normal tempo if it has one.
5. Add the family to `NOTICE`.
Expand All @@ -63,5 +70,14 @@ generated by `dash-generate-components` from `src/lib/components/`.
and `UPSTREAM_DEFAULTS` where a spinner's own default differs.
7. Add `assets/icons/<family>.svg` and its `.dlc-icon-<family>` rule in
`assets/gallery.css`, then a row in the README's family table.
8. If the family draws on a canvas, add it to `UNINSPECTABLE_FAMILIES` in
`tests/test_gallery_controls.py`: there is no DOM state to compare.
8. Update the counts: the family-count and component-count sentence at the top
of the README, and `test_every_source_was_parsed` in
`tests/test_packaging_metadata.py`.
9. If the family draws on a canvas, add it to `UNINSPECTABLE_FAMILIES` in
`tests/test_gallery_controls.py` (there is no DOM state to compare; give it a
paused-frame pixel check like `test_every_thinking_orbs_control_changes_the_canvas`
so each control the page offers is shown to act) and to `NO_CSS_TEMPO` in
`tests/test_contract.py`. Keep its loaders out of the always-animating header
mark through `MARK_SKIP` in `gallery.py`. Header search rows clone a loader from
that mark, so a canvas family needs a case in `preview()` in `assets/gallery.js`
to show anything but its family icon.
4 changes: 4 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ Notable upstream projects (non-exhaustive; see inventory for pins and status):
canvas renderer with Dot/OrbLine/OrbRect/OrbArc primitives, while
thinking-orbs is a React-only 3D dotted-sphere renderer. The shared names
describe common AI/agent activity verbs. No code or assets are copied.
- thinking-orbs (Jakubantalik/Libraries.dev) -- MIT. Nine dotted-sphere canvas
orbs for AI and agent status, wrapped as dlc.thinking_orbs.Orb. Not to be
confused with the unrelated @yogesharc/thinking-orbs package, which is not
wrapped.

Hard skips (not wrapped): css-spinners (GPL-3.0), react18-loaders (MPL-2.0).

Expand Down
43 changes: 40 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# dash-loading-components (`dlc`)

Loading indicators for [Plotly Dash](https://dash.plotly.com), wrapping twelve
React spinner libraries as one install. 461 components under stable namespaces,
Loading indicators for [Plotly Dash](https://dash.plotly.com), wrapping thirteen
React spinner libraries as one install. 470 components under stable namespaces,
with a common factory over the top so you can switch families without
relearning each one's props.

Expand Down Expand Up @@ -44,7 +44,7 @@ dcc.Loading(children, custom_spinner=dlc.ldrs.Ring(size=48))
Discover what is available at runtime:

```python
dlc.list_libraries() # ['loading_dev', 'ldrs', 'spinners', ..., 'gridora', 'loadersz']
dlc.list_libraries() # ['loading_dev', 'ldrs', 'spinners', ..., 'gridora', 'loadersz', 'thinking_orbs']
dlc.list_spinners("ldrs") # ['Ring', 'Helix', 'DotPulse', ...]
dlc.list_spinners("loadersz") # ['working', 'searching', 'connecting', ...]
```
Expand Down Expand Up @@ -75,6 +75,7 @@ resolve it; it will accept the final 4.5 release once published.
| `flicker` | [flicker-dot](https://www.npmjs.com/package/flicker-dot) | 61 |
| `gridora` | [gridora](https://www.npmjs.com/package/gridora) | 133 |
| `loadersz` | [loadersz](https://www.npmjs.com/package/loadersz) | 160 |
| `thinking_orbs` | [thinking-orbs](https://www.npmjs.com/package/thinking-orbs) | 9 |

## Flip-dot presets

Expand Down Expand Up @@ -145,6 +146,42 @@ off to get loadersz's own palette (grey, or a loader's own tones), tinted by
`hue` (0 to 360) and drawn for a light or dark page by `theme` (`"auto"`
follows the operating system, not the page).

## Agent status orbs

thinking-orbs draws nine states an AI or agent can be in as dotted spheres on a
plain 2D canvas: `working`, `searching`, `solving`, `listening`, `connecting`,
`weaving`, `composing`, `breathing` and `shaping`. `dlc.thinking_orbs.Orb`
renders any of them; the state is a prop, so there is no
`dlc.thinking_orbs.working`.

```python
dlc.thinking_orbs.Orb(state="searching")
dlc.thinking_orbs.Orb(state="solving", size=20, color="#f97316", rate=1.5)
```

- **`size` is any pixel size, drawn from one of three designs.** Upstream hand-tunes
the orb at 64 (chat avatar), 32 and 20 (inline text) with separate dot counts,
dot sizes and speeds, and fails on any other size. `dlc` draws the nearest design
(by ratio) and scales the canvas to `size`: 48 is the 64 design a little smaller,
24 the 20 design a little larger. Sizes above 64 upscale the 64 design and soften.
Upstream documents 64 and 20; its 32 is interpolated from them and has had no tuning
pass of its own. `size` defaults to 64.
- **`color` tints the ink; leave it off for monochrome.** Upstream's stock ink is
grey, light on dark pages and dark on light ones. `color` takes `#rgb`, `#rrggbb`
or `rgb(r, g, b)` only (any other CSS color syntax is ignored, so `"orange"`
keeps the grey) and keeps the orb's depth shading on the tint.
- **`theme="auto"` follows the page.** Upstream resolves auto from an ancestor
`data-theme` attribute or `dark` / `light` class, else the operating system.
Mantine sets neither, so `dlc` mirrors `data-mantine-color-scheme` from `<html>`
onto the orb while that attribute is present: in a `dash-mantine-components` app
the orbs follow its color scheme toggle live. Pin `theme="dark"` or `"light"` for
a fixed ink.
- `dots` and `dot_size` are upstream's density and dot radius multipliers (1 is the
tuned look). `rate` is upstream's `speed`, a multiplier on each state's own tempo,
and `playing=False` freezes the frame (upstream `paused`). The orb pauses by itself
while offscreen or in a hidden tab and draws one still frame under
`prefers-reduced-motion`.

Every component is also exported prefixed at the top level
(`dlc.LoadingDevArc`, `dlc.LdrsRing`) for Dash callbacks that want a flat name.

Expand Down
1 change: 1 addition & 0 deletions assets/gallery.css
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ p { text-wrap: pretty; }
.dlc-icon-flicker { --dlc-icon: url(icons/flicker.svg); }
.dlc-icon-gridora { --dlc-icon: url(icons/gridora.svg); }
.dlc-icon-loadersz { --dlc-icon: url(icons/loadersz.svg); }
.dlc-icon-thinking_orbs { --dlc-icon: url(icons/thinking_orbs.svg); }
.dlc-icon-overview { --dlc-icon: url(icons/overview.svg); }
.dlc-icon-credits { --dlc-icon: url(icons/credits.svg); }
.dlc-icon-request { --dlc-icon: url(icons/request.svg); }
Expand Down
5 changes: 3 additions & 2 deletions assets/gallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,9 @@
// A small live preview beside each result. Almost every loader is already in
// the page, hidden, as a brand-mark slot: clone that. loadersz is not (its
// canvases never stop animating), so it is made on the spot. What has
// neither (m3 draws from React, a few loaders overflow the slot) gets its
// family icon, which is also what library and page rows show.
// neither (m3 and thinking_orbs draw from React, so there is no element to
// create here; a few loaders overflow the slot) gets its family icon, which
// is also what library and page rows show.
const iconFor = (href) => {
const family = href.match(/^\/(?:c\/([^/]+)\/.*|#family-(.+))$/);
return (family && (family[1] || family[2])) || (href === '/credits' ? 'credits' : 'overview');
Expand Down
1 change: 1 addition & 0 deletions assets/icons/thinking_orbs.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
122 changes: 122 additions & 0 deletions dash_loading_components/ThinkingOrbsOrb.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# AUTO GENERATED FILE - DO NOT EDIT

import typing # noqa: F401
from typing_extensions import TypedDict, NotRequired, Literal # noqa: F401
from dash.development.base_component import Component, _explicitize_args
try:
from dash.types import NumberType # noqa: F401
except ImportError:
# Backwards compatibility for dash<=4.1.0
if typing.TYPE_CHECKING:
raise
NumberType = typing.Union[ # noqa: F401
typing.SupportsFloat, typing.SupportsInt, typing.SupportsComplex
]

ComponentSingleType = typing.Union[str, int, float, Component, None]
ComponentType = typing.Union[
ComponentSingleType,
typing.Sequence[ComponentSingleType],
]


class ThinkingOrbsOrb(Component):
"""A ThinkingOrbsOrb component.


Keyword arguments:

- id (string; optional):
The ID used to identify this component in Dash callbacks.

- aria_label (string; optional):
Accessible label on the canvas. Defaults to a per-state label such
as \"Searching...\".

- className (string; optional):
CSS class applied to the outer wrapper.

- color (string; optional):
Optional ink tint as \"#rgb\", \"#rrggbb\" or \"rgb(r, g, b)\";
any other CSS colour syntax is ignored by upstream. The orb's
depth shading is kept on the tint. Leave unset for the stock
monochrome ink.

- dot_size (number; optional):
Dot-radius multiplier. 1 (default) is the tuned look; 0.7 reads
finer, 1.5 bolder. Upstream floors it at 0.1.

- dots (number; optional):
Dot-count multiplier, applied while keeping the state's balance. 1
(default) is the tuned look; upstream floors it at 0.1.

- paused (boolean; optional):
Upstream pause flag. When `playing` is set and `paused` is not,
paused = !playing. An explicit `paused` wins.

- playing (boolean; optional):
Set to False to freeze the animation on its current frame.

- rate (number; optional):
Relative tempo: 1.0 is the state's own tempo, 2.0 twice as fast.
Mapped to upstream speed = rate. Leave unset to keep the default.

- size (number; optional):
Square canvas side in CSS pixels. Upstream has three designs, at
64 (chat avatar), 32 and 20 (inline text); the nearest one is
drawn and scaled to this size. Sizes above 64 upscale the 64
design, so they soften. Default 64.

- speed (number; optional):
Upstream tempo multiplier on the state's own speed. 1 = normal.
Prefer `rate` for the common contract; an explicit `speed` wins
over `rate`.

- state (a value equal to: 'working', 'searching', 'solving', 'listening', 'connecting', 'weaving', 'composing', 'breathing', 'shaping'; optional):
Which orb animation to show: \"working\", \"searching\",
\"solving\", \"listening\", \"connecting\", \"weaving\",
\"composing\", \"breathing\" or \"shaping\". Defaults to
\"working\".

- theme (a value equal to: 'auto', 'dark', 'light'; optional):
Ink for the dots: \"auto\", \"dark\" or \"light\". Dark is light
ink for dark backgrounds; light is dark ink for light ones.
\"auto\" follows an ancestor data-theme attribute or dark/light
class, the Mantine colour scheme, or else the operating system.
Default \"auto\"."""
_children_props: typing.List[str] = []
_base_nodes = ['children']
_namespace = 'dash_loading_components'
_type = 'ThinkingOrbsOrb'


def __init__(
self,
id: typing.Optional[typing.Union[str, dict]] = None,
className: typing.Optional[str] = None,
style: typing.Optional[typing.Any] = None,
state: typing.Optional[Literal["working", "searching", "solving", "listening", "connecting", "weaving", "composing", "breathing", "shaping"]] = None,
size: typing.Optional[NumberType] = None,
theme: typing.Optional[Literal["auto", "dark", "light"]] = None,
speed: typing.Optional[NumberType] = None,
paused: typing.Optional[bool] = None,
color: typing.Optional[str] = None,
dots: typing.Optional[NumberType] = None,
dot_size: typing.Optional[NumberType] = None,
aria_label: typing.Optional[str] = None,
rate: typing.Optional[NumberType] = None,
playing: typing.Optional[bool] = None,
**kwargs
):
self._prop_names = ['id', 'aria_label', 'className', 'color', 'dot_size', 'dots', 'paused', 'playing', 'rate', 'size', 'speed', 'state', 'style', 'theme']
self._valid_wildcard_attributes = []
self.available_properties = ['id', 'aria_label', 'className', 'color', 'dot_size', 'dots', 'paused', 'playing', 'rate', 'size', 'speed', 'state', 'style', 'theme']
self.available_wildcard_properties = []
_explicit_args = kwargs.pop('_explicit_args')
_locals = locals()
_locals.update(kwargs) # For wildcard attrs and excess named props
args = {k: _locals[k] for k in _explicit_args}

super(ThinkingOrbsOrb, self).__init__(**args)

setattr(ThinkingOrbsOrb, "__init__", _explicitize_args(ThinkingOrbsOrb.__init__))
3 changes: 2 additions & 1 deletion dash_loading_components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@


# Family namespaces (short names): dlc.loading_dev.Arc, dlc.spinners.ClipLoader, …
from . import loading_dev, ldrs, spinners, spinners_react, loader_spinner, premium, indicators, m3, epic, flicker, gridora, loadersz
from . import loading_dev, ldrs, spinners, spinners_react, loader_spinner, premium, indicators, m3, epic, flicker, gridora, loadersz, thinking_orbs

from .registry import list_libraries, list_spinners

Expand All @@ -105,6 +105,7 @@
"flicker",
"gridora",
"loadersz",
"thinking_orbs",
"list_libraries",
"list_spinners",
]
4 changes: 3 additions & 1 deletion dash_loading_components/_imports_.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,7 @@
from .SpinnersReactSpinnerRound import SpinnersReactSpinnerRound
from .SpinnersReactSpinnerRoundFilled import SpinnersReactSpinnerRoundFilled
from .SpinnersReactSpinnerRoundOutlined import SpinnersReactSpinnerRoundOutlined
from .ThinkingOrbsOrb import ThinkingOrbsOrb

__all__ = [
"EpicAtomSpinner",
Expand Down Expand Up @@ -221,5 +222,6 @@
"SpinnersReactSpinnerInfinity",
"SpinnersReactSpinnerRound",
"SpinnersReactSpinnerRoundFilled",
"SpinnersReactSpinnerRoundOutlined"
"SpinnersReactSpinnerRoundOutlined",
"ThinkingOrbsOrb"
]
40 changes: 20 additions & 20 deletions dash_loading_components/dash_loading_components.min.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dash_loading_components/dash_loading_components.min.js.map

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dash_loading_components/metadata.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion dash_loading_components/package-info.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,8 @@
"react-loading-indicators": "^1.0.1",
"react-spinners": "^0.17.1",
"spinners-react": "^1.0.11",
"styled-components": "^6.5.3"
"styled-components": "^6.5.3",
"thinking-orbs": "^0.3.2"
},
"devDependencies": {
"@babel/core": "^7.22.1",
Expand Down
7 changes: 7 additions & 0 deletions dash_loading_components/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
premium,
spinners,
spinners_react,
thinking_orbs,
)

FAMILIES: list[tuple[str, str, list[tuple[str, Callable]]]] = [
Expand Down Expand Up @@ -201,6 +202,12 @@
[(s, lambda state=s, **kw: loadersz.Loader(state=state, **kw))
for s in loadersz.LOADER_STATES],
),
(
"thinking_orbs",
"thinking-orbs",
[(s, lambda state=s, **kw: thinking_orbs.Orb(state=state, **kw))
for s in thinking_orbs.ORB_STATES],
),
]

FAMILY_LOOKUP = {key: (label, items) for key, label, items in FAMILIES}
Expand Down
24 changes: 24 additions & 0 deletions dash_loading_components/thinking_orbs/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Namespace for dlc.thinking_orbs -- dotted canvas orbs from thinking-orbs.

``Orb`` renders one of nine named states an AI or agent can be in, as a
dotted sphere on a plain 2D canvas: ``working``, ``searching``, ``solving``,
``listening``, ``connecting``, ``weaving``, ``composing``, ``breathing`` and
``shaping``. The ink is monochrome by default (light on dark pages, dark on
light ones); ``color`` tints it.

Usage::

import dash_loading_components as dlc

dlc.thinking_orbs.Orb(state="searching", size=64)
dlc.thinking_orbs.Orb(state="solving", size=20, color="#f97316", rate=1.5)
"""

from ..ThinkingOrbsOrb import ThinkingOrbsOrb as Orb

ORB_STATES = [
"working", "searching", "solving", "listening", "connecting",
"weaving", "composing", "breathing", "shaping",
]

__all__ = ["Orb", "ORB_STATES"]
1 change: 1 addition & 0 deletions docs/UPSTREAM-INVENTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Update this table when a family is added, version-pinned, or wrap status changes
| `flicker` | [flicker-dot](https://www.npmjs.com/package/flicker-dot) **0.1.4** | MIT | [flicker.laurie.fyi](https://flicker.laurie.fyi) · [laurieesc/flicker-dot](https://github.com/laurieesc/flicker-dot) | ≥18 | `wrapped` | Player only; the 61 presets are PhylaTech originals (MIT, this repo). The flicker.laurie.fyi gallery patterns are not open source and are not redistributed |
| `gridora` | [gridora](https://www.npmjs.com/package/gridora) **0.3.0** | MIT | [gridora.gabrielayer.com](https://gridora.gabrielayer.com) · [0x65dgerunner/gridora](https://github.com/0x65dgerunner/gridora) | ≥18 | `wrapped` | 133 motion variants + bitmap-font text. The studio site patterns are not redistributed; user-pasted `sequence=` inputs are their own |
| `loadersz` | [loadersz](https://www.npmjs.com/package/loadersz) **0.9.0** | MIT | [loadersz.vercel.app](https://loadersz.vercel.app) · [lumberjacque/loadersz-core](https://github.com/lumberjacque/loadersz-core) | ≥18 | `wrapped` | 160 canvas-based loaders via a native Web Component. Includes a chart-shaped group (heatmap, sankey, treemap, candlestick, bar chart). The first nine state names overlap with thinking-orbs (independently implemented; see NOTICE) |
| `thinking_orbs` | [thinking-orbs](https://www.npmjs.com/package/thinking-orbs) **0.3.2** | MIT | [libraries.dev/orbs](https://libraries.dev/orbs) · [Jakubantalik/Libraries.dev](https://github.com/Jakubantalik/Libraries.dev/tree/main/packages/thinking-orbs) | ≥18 | `wrapped` | One `Orb` component, nine states, plain 2D canvas, monochrome until `color` tints it. Upstream draws at 64, 32 and 20 only; `dlc` snaps any `size` to the nearest and CSS-scales. Not the newer, unrelated `@yogesharc/thinking-orbs` |

## Hard skips (license: do not wrap)

Expand Down
Loading
Loading