@threadlabs/looma 0.33.1 → 0.34.0
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/components/shared/overlay.js +8 -2
- package/components/shared/surface-material.js +21 -0
- package/components/ui-button/ui-button.html +63 -47
- package/components/ui-card/ui-card.html +44 -2
- package/components/ui-curve-editor/curve.js +10 -0
- package/components/ui-curve-editor/ui-curve-editor.html +181 -0
- package/components/ui-curve-editor/ui-curve-editor.js +51 -0
- package/components/ui-dialog/ui-dialog.html +62 -1
- package/components/ui-dialog/ui-dialog.js +9 -1
- package/components/ui-icon-button/ui-icon-button.html +75 -23
- package/components/ui-menu/ui-menu.html +60 -0
- package/components/ui-menu/ui-menu.js +1 -1
- package/components/ui-number-input/arithmetic.js +47 -0
- package/components/ui-number-input/ui-number-input.html +62 -0
- package/components/ui-number-input/ui-number-input.js +44 -0
- package/components/ui-popover/ui-popover.html +64 -1
- package/components/ui-popover/ui-popover.js +1 -1
- package/components/ui-slider/ui-slider.html +84 -0
- package/components/ui-slider/ui-slider.js +29 -0
- package/components/ui-tabs/ui-tabs.html +6 -1
- package/components/ui-text/ui-text.html +31 -6
- package/components/ui-tooltip/ui-tooltip.html +60 -0
- package/components/ui-tooltip/ui-tooltip.js +1 -1
- package/dist/index.js +46 -43
- package/docs/README.md +34 -4
- package/docs/card.html +16 -2
- package/docs/card.js +17 -2
- package/docs/catalog.json +1154 -144
- package/docs/customizer-render.mjs +35 -9
- package/docs/customizer.js +83 -20
- package/docs/documentation.css +9 -1
- package/docs/index.d.ts +4 -2
- package/docs/index.mjs +1 -1
- package/docs/preview.js +2 -0
- package/docs/render.mjs +15 -6
- package/docs/site.mjs +50 -9
- package/docs/theme-session.mjs +51 -0
- package/docs/theme.mjs +134 -15
- package/docs/value-editors.mjs +33 -0
- package/package.json +2 -2
- package/styles/ui-button.css +45 -45
- package/styles/ui-card.css +47 -0
- package/styles/ui-curve-editor.css +109 -0
- package/styles/ui-dialog.css +132 -0
- package/styles/ui-icon-button.css +63 -20
- package/styles/ui-menu.css +72 -0
- package/styles/ui-number-input.css +34 -0
- package/styles/ui-popover.css +74 -0
- package/styles/ui-slider.css +53 -0
- package/styles/ui-tabs.css +6 -1
- package/styles/ui-text.css +23 -1
- package/styles/ui-tooltip.css +72 -0
- package/theme-system.css +26 -10
- package/tokens.css +8 -2
- package/vanilla/UiButton.d.ts +1 -0
- package/vanilla/UiButton.js +195 -130
- package/vanilla/UiCard.d.ts +1 -1
- package/vanilla/UiCard.js +1 -1
- package/vanilla/UiCurveEditor.d.ts +28 -0
- package/vanilla/UiCurveEditor.js +134 -0
- package/vanilla/UiIconButton.d.ts +2 -1
- package/vanilla/UiIconButton.js +58 -31
- package/vanilla/UiNumberInput.d.ts +33 -0
- package/vanilla/UiNumberInput.js +79 -0
- package/vanilla/UiSlider.d.ts +33 -0
- package/vanilla/UiSlider.js +125 -0
- package/vanilla/UiText.d.ts +2 -2
- package/vanilla/UiText.js +45 -11
- package/vanilla/index.js +3 -0
- package/vue/UiButton.d.ts +6 -0
- package/vue/UiButton.vue +155 -56
- package/vue/UiCard.d.ts +2 -2
- package/vue/UiCard.vue +55 -5
- package/vue/UiCurveEditor.d.ts +53 -0
- package/vue/UiCurveEditor.js +2 -0
- package/vue/UiCurveEditor.vue +427 -0
- package/vue/UiDialog.vue +177 -1
- package/vue/UiIconButton.d.ts +8 -2
- package/vue/UiIconButton.vue +164 -34
- package/vue/UiMenu.vue +89 -0
- package/vue/UiNumberInput.d.ts +83 -0
- package/vue/UiNumberInput.js +2 -0
- package/vue/UiNumberInput.vue +370 -0
- package/vue/UiPopover.vue +92 -1
- package/vue/UiSlider.d.ts +83 -0
- package/vue/UiSlider.js +2 -0
- package/vue/UiSlider.vue +412 -0
- package/vue/UiTabs.vue +6 -1
- package/vue/UiText.d.ts +7 -5
- package/vue/UiText.vue +104 -22
- package/vue/UiTooltip.vue +89 -0
- package/vue/chunks/UiActionBar.js +1 -1
- package/vue/chunks/UiAffordanceScope.js +2 -2
- package/vue/chunks/UiAvatar.js +2 -2
- package/vue/chunks/UiAvatarGroup.js +2 -2
- package/vue/chunks/UiBadge.js +2 -2
- package/vue/chunks/UiBreadcrumbItem.js +2 -2
- package/vue/chunks/UiBreadcrumbs.js +2 -2
- package/vue/chunks/UiButton.js +94 -11
- package/vue/chunks/UiCallout.js +2 -2
- package/vue/chunks/UiCard.js +6 -5
- package/vue/chunks/UiCheckbox.js +2 -2
- package/vue/chunks/UiCluster.js +2 -2
- package/vue/chunks/UiColorPicker.js +2 -2
- package/vue/chunks/UiCombobox.js +2 -2
- package/vue/chunks/UiContainer.js +2 -2
- package/vue/chunks/UiContextMenu.js +2 -2
- package/vue/chunks/UiCover.js +2 -2
- package/vue/chunks/UiCurveEditor.js +413 -0
- package/vue/chunks/UiDescriptionItem.js +2 -2
- package/vue/chunks/UiDescriptionList.js +2 -2
- package/vue/chunks/UiDialog.js +4 -4
- package/vue/chunks/UiDisclosure.js +2 -2
- package/vue/chunks/UiEditable.js +2 -2
- package/vue/chunks/UiEditorBlockActions.js +2 -2
- package/vue/chunks/UiEditorChipEditor.js +2 -2
- package/vue/chunks/UiEditorCodeLanguage.js +2 -2
- package/vue/chunks/UiEditorFootnoteEditor.js +2 -2
- package/vue/chunks/UiEditorImageToolbar.js +3 -3
- package/vue/chunks/UiEditorInsertTableGrid.js +2 -2
- package/vue/chunks/UiEditorLinkCard.js +3 -3
- package/vue/chunks/UiEditorLinkForm.js +3 -3
- package/vue/chunks/UiEditorMentionMenu.js +2 -2
- package/vue/chunks/UiEditorMentionMenuItem.js +2 -2
- package/vue/chunks/UiEditorSlashMenu.js +2 -2
- package/vue/chunks/UiEditorSlashMenuGroup.js +2 -2
- package/vue/chunks/UiEditorSlashMenuItem.js +2 -2
- package/vue/chunks/UiEditorSurface.js +2 -2
- package/vue/chunks/UiEditorTableContextMenu.js +2 -2
- package/vue/chunks/UiEditorTableOverlay.js +2 -2
- package/vue/chunks/UiEditorTableToolbar.js +2 -2
- package/vue/chunks/UiEditorToolbar.js +2 -2
- package/vue/chunks/UiFloatingActionButton.js +2 -2
- package/vue/chunks/UiFormField.js +2 -2
- package/vue/chunks/UiGrid.js +2 -2
- package/vue/chunks/UiIcon.js +2 -2
- package/vue/chunks/UiIconButton.js +77 -11
- package/vue/chunks/UiImage.js +2 -2
- package/vue/chunks/UiInput.js +2 -2
- package/vue/chunks/UiInputGroup.js +2 -2
- package/vue/chunks/UiList.js +2 -2
- package/vue/chunks/UiListItem.js +2 -2
- package/vue/chunks/UiListbox.js +2 -2
- package/vue/chunks/UiMenu.js +3 -3
- package/vue/chunks/UiMenuGroup.js +2 -2
- package/vue/chunks/UiMenuItem.js +2 -2
- package/vue/chunks/UiMeter.js +2 -2
- package/vue/chunks/UiNavItem.js +2 -2
- package/vue/chunks/UiNumberInput.js +390 -0
- package/vue/chunks/UiPageHeader.js +2 -2
- package/vue/chunks/UiPopover.js +4 -4
- package/vue/chunks/UiRadio.js +2 -2
- package/vue/chunks/UiRadioGroup.js +2 -2
- package/vue/chunks/UiReel.js +2 -2
- package/vue/chunks/UiScrollArea.js +2 -2
- package/vue/chunks/UiSearchResultRow.js +2 -2
- package/vue/chunks/UiSearchShell.js +2 -2
- package/vue/chunks/UiSection.js +2 -2
- package/vue/chunks/UiSelect.js +2 -2
- package/vue/chunks/UiSeparator.js +2 -2
- package/vue/chunks/UiSidebar.js +2 -2
- package/vue/chunks/UiSlider.js +396 -0
- package/vue/chunks/UiSpinner.js +2 -2
- package/vue/chunks/UiStack.js +2 -2
- package/vue/chunks/UiStatusMessage.js +2 -2
- package/vue/chunks/UiSwatch.js +2 -2
- package/vue/chunks/UiSwitch.js +2 -2
- package/vue/chunks/UiSwitcher.js +2 -2
- package/vue/chunks/UiTable.js +2 -2
- package/vue/chunks/UiTabs.js +3 -3
- package/vue/chunks/UiText.js +53 -12
- package/vue/chunks/UiTextarea.js +2 -2
- package/vue/chunks/UiToast.js +2 -2
- package/vue/chunks/UiToastRegion.js +2 -2
- package/vue/chunks/UiTooltip.js +3 -3
- package/vue/chunks/UiTopBar.js +1 -1
- package/vue/chunks/UiTree.js +2 -2
- package/vue/chunks/UiTreeItem.js +2 -2
- package/vue/chunks/_plugin-vue_export-helper.js +68 -2
- package/vue/chunks/props.js +24 -1
- package/vue/components.css +2215 -1203
- package/vue/editor/index.js +623 -211
- package/vue/index.d.ts +3 -0
- package/vue/index.js +5 -2
package/docs/README.md
CHANGED
|
@@ -40,13 +40,43 @@ pnpm exec looma-docs preview
|
|
|
40
40
|
|
|
41
41
|
## Change the rule, keep the family consistent
|
|
42
42
|
|
|
43
|
-
The authoring model
|
|
43
|
+
The authoring model groups shared decisions as Colour, Type, Size & spacing, Material and Motion. The controls expose shared intent: a control size, spaciousness, corners, inner and outer depth, and response pace.
|
|
44
44
|
|
|
45
|
-
The generated values follow rules. Small and large control heights follow a ratio around the shared control size. Spacing follows an independent
|
|
45
|
+
The generated values follow rules. Small and large control heights follow a ratio around the shared control size. Spacing follows an independent curve: linear at 1, increasingly curved toward 2, with stable endpoints so the largest gaps do not grow without bound. Depth generates families of shadows; it does not add motion amplitude. Fields and buttons with the same size setting use the same box height, while content can still grow when it needs more room.
|
|
46
|
+
|
|
47
|
+
Choose a coordinated palette to change related paper, ink and action seeds together without changing geometry or motion. Palette seeds remain available for precise edits; the light/dark range previews and resolved values explain readability adjustments.
|
|
48
|
+
|
|
49
|
+
Number controls accept arithmetic such as `42px / 1.2` or `150ms * 2`, calculate on entry and show the result. Unit changes preserve the quantity. Sliders include exact entry, and curve handles support dragging and arrow keys alongside numeric coordinates.
|
|
46
50
|
|
|
47
51
|
Lengths retain their CSS units, such as `rem`; times retain `ms` or `s`. The downloaded CSS includes the canonical shared recipe as well as your inputs. Import a downloaded JSON recipe to continue editing it. Keep hand-written CSS in a separate overrides file so regenerating the theme does not replace it.
|
|
48
52
|
|
|
49
|
-
Changes remain
|
|
53
|
+
Changes apply throughout the documentation and remain in this browser across navigation and reload until reset. Repository files change only when you save locally. Starting points update the shell and all selected cards. Reset returns to the repository baseline. Invalid input keeps the last valid preview and explains which decision needs attention.
|
|
54
|
+
|
|
55
|
+
Text offers body, display, heading, label, caption, eyebrow and code roles. Choose a heading's document level with `as` independently from its visual role. Button and IconButton keep appearance and tone independent, with four optional shortcuts: primary (solid accent), standard (solid neutral), quiet (ghost neutral) and destructive (solid danger). A named preset takes precedence over the separate choices; `preset="none"` preserves their existing defaults.
|
|
56
|
+
|
|
57
|
+
Glassiness and surface separation govern floating surfaces and the Card glass variant. Popup purpose and measured size refine the shared treatment. Decorative material can transmit the scene; the content plane remains opaque and readable, with opaque fallbacks for reduced transparency and unsupported backdrop filtering.
|
|
58
|
+
|
|
59
|
+
## Use light, dark, or both
|
|
60
|
+
|
|
61
|
+
Every generated theme includes a coordinated light/dark pair. The type, geometry and motion decisions stay shared. Both palettes derive readable text, outlines, focus and action states from the same identity; the generator may adjust requested color seeds to maintain contrast.
|
|
62
|
+
|
|
63
|
+
Load the generated CSS after Looma's tokens and palette. Choose how it runs:
|
|
64
|
+
|
|
65
|
+
- **System preference:** leave `data-theme` off the document root. The CSS follows the operating system automatically.
|
|
66
|
+
- **Light only:** set `<html data-theme="light">`.
|
|
67
|
+
- **Dark only:** set `<html data-theme="dark">`.
|
|
68
|
+
- **User switch:** set the root attribute to `light` or `dark`, and remove it to return to system preference. Persist that choice in your application if desired.
|
|
69
|
+
|
|
70
|
+
Fixed-mode applications still receive both palettes. A mode boundary applies to its descendants, so a dark panel can contain a light subsection without changing the page or its siblings:
|
|
71
|
+
|
|
72
|
+
```html
|
|
73
|
+
<section data-theme="dark">
|
|
74
|
+
<h2>After-hours Fellowship office</h2>
|
|
75
|
+
<div data-theme="light">Sam's daylight reading area</div>
|
|
76
|
+
</section>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Use the public semantic color properties inside those regions. A floating surface moved elsewhere in the DOM must retain its originating mode boundary; Looma's isolated documentation previews receive their card's mode automatically.
|
|
50
80
|
|
|
51
81
|
## Add your components
|
|
52
82
|
|
|
@@ -64,7 +94,7 @@ Opt into source directories in `looma.docs.json`:
|
|
|
64
94
|
}
|
|
65
95
|
```
|
|
66
96
|
|
|
67
|
-
`content` and `overrides` are optional. Create files you configure before building. Markdown guidance supplements the generated reference; it cannot replace an API page. Relative component and asset dependencies keep their original project locations, and code examples remain literal.
|
|
97
|
+
`content` and `overrides` are optional. Create files you configure before building. Markdown guidance supplements the generated reference; it cannot replace an API page. Relative component and asset dependencies keep their original project locations, and code examples remain literal. Local web fonts referenced by override CSS are embedded in the documentation's theme stylesheet so isolated examples render the same fonts on static hosts. Load your chosen web fonts in the consuming application; downloaded theme CSS selects their font families.
|
|
68
98
|
|
|
69
99
|
A resource can use any valid HTML Next component tag:
|
|
70
100
|
|
package/docs/card.html
CHANGED
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
<prop name="title" type="string" default="Example">The documented component name.</prop>
|
|
8
8
|
<prop name="description" type="string" default="">The component's authored description.</prop>
|
|
9
9
|
<prop name="exampleTitle" type="string" default="">The selected authored example.</prop>
|
|
10
|
+
<prop name="reference" type="boolean" default="false">Use the spacious full-reference example presentation.</prop>
|
|
10
11
|
<prop name="src" type="string" default="">The compiled isolated example page.</prop>
|
|
11
12
|
<prop name="resizable" type="boolean" default="false">Expose a width control for responsive examples.</prop>
|
|
12
13
|
<prop name="category" type="string" default="forms">The shared category identity.</prop>
|
|
@@ -18,14 +19,17 @@
|
|
|
18
19
|
<prop name="loading" type="keyword" values="lazy, eager" default="lazy">Load visible catalog cards lazily; selected customizer cards eagerly.</prop>
|
|
19
20
|
</defs>
|
|
20
21
|
<article from:data-example-card="$identity" from:data-component-card="$tag" from:data-category="$category">
|
|
22
|
+
<header $if="$reference" class="example-heading"><slot name="heading"><h3>{$exampleTitle}</h3><p>{$description}</p></slot></header>
|
|
21
23
|
<div class="preview"><iframe $ref="frame" from:title="$title" from:src="$src" sandbox="allow-scripts" from:loading="$loading" width="100%" height="208"></iframe></div>
|
|
22
|
-
<
|
|
24
|
+
<section $if="$reference" class="example-code"><h4>Code</h4><slot name="code"></slot></section>
|
|
25
|
+
<div $if="$resizable" class="preview-width"> <ui-form-field><label slot="label">Preview width</label><span slot="help">Explore the example at a narrower width.</span><ui-input $ref="width" type="number" min="240" max="1600" value="720" aria-label="Preview width in pixels" size="sm"></ui-input></ui-form-field></div>
|
|
26
|
+
<div $if="not $reference" class="body">
|
|
23
27
|
<div class="meta"><span>{$category}</span><code>{$nativeRoot}</code></div>
|
|
24
28
|
<h3><a from:href="$href">{$title}</a></h3>
|
|
25
29
|
<p class="description">{$description}</p>
|
|
26
30
|
<p class="owner" $if="$packageName">{$packageName}</p>
|
|
27
31
|
<p class="example-caption" $if="$exampleTitle">{$exampleTitle}</p>
|
|
28
|
-
|
|
32
|
+
|
|
29
33
|
<footer><ui-button $if="$href" as="a" from:href="$href" variant="link" size="sm">View component</ui-button><ui-button $if="$removable" $ref="remove" variant="ghost" size="sm">Remove</ui-button><slot name="actions"></slot></footer>
|
|
30
34
|
</div>
|
|
31
35
|
</article>
|
|
@@ -46,10 +50,20 @@
|
|
|
46
50
|
:host([category="layout"]) { --_card-accent: var(--ui-info); }
|
|
47
51
|
:host([category="editor"]) { --_card-accent: var(--ui-warning); }
|
|
48
52
|
:host:hover { border-color: color-mix(in srgb, var(--_card-accent) 45%, var(--ui-border)); box-shadow: var(--ui-shadow-md); transform: translateY(-2px); }
|
|
53
|
+
:host([reference]):hover { transform: none; border-color: var(--ui-border); box-shadow: var(--ui-shadow-sm); }
|
|
54
|
+
.example-heading { padding: var(--ui-space-5) !important; border-block-end: var(--ui-border-width) solid var(--ui-border); }
|
|
55
|
+
.example-code { padding: var(--ui-space-5) !important; border-block-start: var(--ui-border-width) solid var(--ui-border); }
|
|
56
|
+
.example-code h4 { margin: 0 0 var(--ui-space-3) !important; font-size: var(--ui-font-size-md); }
|
|
57
|
+
.example-heading p { margin: var(--ui-space-2) 0 0 !important; color: var(--ui-text-secondary); font-size: var(--ui-font-size-sm); }
|
|
58
|
+
:host([reference]) .preview { min-block-size: 11rem; display: grid !important; align-items: center !important; border-block-end: 0; }
|
|
59
|
+
:host([reference]) iframe { min-block-size: 11rem; }
|
|
60
|
+
:host([reference][category="overlay"]) iframe { min-block-size: 26rem; }
|
|
61
|
+
:host([reference]) .preview::before { display: none; }
|
|
49
62
|
.preview { position: relative; min-block-size: 13rem; overflow: hidden; border-block-end: var(--ui-border-width) solid var(--ui-border); background: color-mix(in srgb, var(--_card-accent) 5%, var(--ui-surface)); }
|
|
50
63
|
.preview::before { position: absolute; inset-block-start: 0; inset-inline-start: 0; inline-size: 3.5rem; block-size: 3px; background: var(--_card-accent); content: ""; z-index: 1; }
|
|
51
64
|
iframe { display: block !important; max-inline-size: 100%; border: 0; }
|
|
52
65
|
footer { display: flex !important; align-items: center !important; justify-content: space-between !important; gap: var(--ui-space-2) !important; }
|
|
66
|
+
.preview-width { padding: var(--ui-space-4) !important; }
|
|
53
67
|
.body { padding: var(--ui-space-5) !important; }
|
|
54
68
|
.meta { display: flex !important; align-items: center !important; justify-content: space-between !important; gap: var(--ui-space-2) !important; margin-block-end: var(--ui-space-2) !important; color: var(--ui-text-secondary); font-size: var(--ui-font-size-xs); font-weight: var(--ui-font-bold); letter-spacing: .09em; text-transform: uppercase; }
|
|
55
69
|
.meta code { padding: 0 !important; background: transparent; color: inherit; text-transform: none; }
|
package/docs/card.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { documentationTheme, themeEvent } from './theme-session.mjs';
|
|
1
2
|
/** Only theme data and measured height cross the opaque preview boundary. */
|
|
2
3
|
export function connect(host) {
|
|
3
4
|
const frame = host.refs.frame;
|
|
@@ -5,8 +6,17 @@ export function connect(host) {
|
|
|
5
6
|
const remove = host.refs.remove;
|
|
6
7
|
const removeCard = () => host.element.dispatchEvent(new CustomEvent("looma-example-remove", { bubbles: true, detail: { id: host.props.identity.value } }));
|
|
7
8
|
const view = frame.ownerDocument.defaultView;
|
|
8
|
-
let theme = '';
|
|
9
|
-
const
|
|
9
|
+
let theme = documentationTheme(view)?.css ?? '';
|
|
10
|
+
const documentTheme = () => { theme = documentationTheme(view)?.css ?? ''; send(); };
|
|
11
|
+
const preference = view.matchMedia('(prefers-color-scheme: dark)');
|
|
12
|
+
const send = () => {
|
|
13
|
+
const scheme = view.getComputedStyle(host.element).colorScheme;
|
|
14
|
+
const mode = scheme === 'dark' || (scheme.includes('dark') && scheme.includes('light') && preference.matches) ? 'dark' : 'light';
|
|
15
|
+
frame.contentWindow?.postMessage({ type: 'looma-theme', css: theme, mode, reference: Boolean(host.props.reference.value) }, '*');
|
|
16
|
+
};
|
|
17
|
+
// Observe only this card's ancestors: an opposite-mode boundary belongs to its own subtree.
|
|
18
|
+
const modes = new view.MutationObserver(send);
|
|
19
|
+
for (let ancestor = host.element; ancestor; ancestor = ancestor.parentElement) modes.observe(ancestor, { attributes: true, attributeFilter: ['data-theme', 'style', 'class'] });
|
|
10
20
|
const message = event => {
|
|
11
21
|
if (event.source !== frame.contentWindow) return;
|
|
12
22
|
if (event.data?.type === 'looma-preview-ready') send();
|
|
@@ -21,12 +31,17 @@ export function connect(host) {
|
|
|
21
31
|
width?.addEventListener('input', resize);
|
|
22
32
|
remove?.addEventListener('click', removeCard);
|
|
23
33
|
view.addEventListener('message', message);
|
|
34
|
+
view.addEventListener(themeEvent, documentTheme);
|
|
24
35
|
frame.addEventListener('load', send);
|
|
36
|
+
preference.addEventListener('change', send);
|
|
25
37
|
return () => {
|
|
26
38
|
host.element.removeEventListener('looma-theme-preview', update);
|
|
27
39
|
width?.removeEventListener('input', resize);
|
|
28
40
|
remove?.removeEventListener('click', removeCard);
|
|
29
41
|
view.removeEventListener('message', message);
|
|
42
|
+
view.removeEventListener(themeEvent, documentTheme);
|
|
30
43
|
frame.removeEventListener('load', send);
|
|
44
|
+
preference.removeEventListener('change', send);
|
|
45
|
+
modes.disconnect();
|
|
31
46
|
};
|
|
32
47
|
}
|