@alacris/ui 0.0.0 → 0.1.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.
Files changed (94) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -1
  3. package/package.json +75 -3
  4. package/src/components/base.js +46 -0
  5. package/src/components/ui-accordion-item.js +157 -0
  6. package/src/components/ui-accordion.js +58 -0
  7. package/src/components/ui-alert.js +168 -0
  8. package/src/components/ui-app-bar.js +119 -0
  9. package/src/components/ui-autocomplete.js +371 -0
  10. package/src/components/ui-avatar.js +104 -0
  11. package/src/components/ui-backdrop.js +66 -0
  12. package/src/components/ui-badge.js +95 -0
  13. package/src/components/ui-bottom-app-bar.js +78 -0
  14. package/src/components/ui-bottom-nav.js +83 -0
  15. package/src/components/ui-breadcrumbs.js +100 -0
  16. package/src/components/ui-button-group.js +49 -0
  17. package/src/components/ui-button.js +143 -0
  18. package/src/components/ui-card.js +86 -0
  19. package/src/components/ui-carousel-item.js +53 -0
  20. package/src/components/ui-carousel.js +301 -0
  21. package/src/components/ui-checkbox.js +165 -0
  22. package/src/components/ui-chip-set.js +90 -0
  23. package/src/components/ui-chip.js +226 -0
  24. package/src/components/ui-container.js +59 -0
  25. package/src/components/ui-date-picker.js +774 -0
  26. package/src/components/ui-dialog.js +179 -0
  27. package/src/components/ui-divider.js +58 -0
  28. package/src/components/ui-drawer.js +169 -0
  29. package/src/components/ui-fab-menu.js +122 -0
  30. package/src/components/ui-fab.js +117 -0
  31. package/src/components/ui-icon-button.js +112 -0
  32. package/src/components/ui-icon.js +64 -0
  33. package/src/components/ui-list-item.js +166 -0
  34. package/src/components/ui-list.js +38 -0
  35. package/src/components/ui-loading-indicator.js +74 -0
  36. package/src/components/ui-menu-item.js +117 -0
  37. package/src/components/ui-menu.js +192 -0
  38. package/src/components/ui-nav-item.js +138 -0
  39. package/src/components/ui-nav-rail.js +111 -0
  40. package/src/components/ui-option.js +85 -0
  41. package/src/components/ui-pagination.js +173 -0
  42. package/src/components/ui-progress.js +100 -0
  43. package/src/components/ui-radio-group.js +104 -0
  44. package/src/components/ui-radio.js +143 -0
  45. package/src/components/ui-rating.js +126 -0
  46. package/src/components/ui-search.js +316 -0
  47. package/src/components/ui-select.js +418 -0
  48. package/src/components/ui-sheet.js +205 -0
  49. package/src/components/ui-side-sheet.js +221 -0
  50. package/src/components/ui-skeleton.js +89 -0
  51. package/src/components/ui-slider.js +266 -0
  52. package/src/components/ui-snackbar.js +233 -0
  53. package/src/components/ui-spinner.js +101 -0
  54. package/src/components/ui-split-button.js +158 -0
  55. package/src/components/ui-stack.js +37 -0
  56. package/src/components/ui-step.js +91 -0
  57. package/src/components/ui-stepper.js +86 -0
  58. package/src/components/ui-surface.js +51 -0
  59. package/src/components/ui-switch.js +153 -0
  60. package/src/components/ui-tab-panel.js +54 -0
  61. package/src/components/ui-tab.js +116 -0
  62. package/src/components/ui-table-footer.js +141 -0
  63. package/src/components/ui-table-toolbar.js +219 -0
  64. package/src/components/ui-table.js +735 -0
  65. package/src/components/ui-tabs.js +178 -0
  66. package/src/components/ui-text-field.js +319 -0
  67. package/src/components/ui-text.js +36 -0
  68. package/src/components/ui-time-picker.js +753 -0
  69. package/src/components/ui-toggle-button.js +170 -0
  70. package/src/components/ui-toggle-group.js +111 -0
  71. package/src/components/ui-toolbar.js +64 -0
  72. package/src/components/ui-tooltip.js +148 -0
  73. package/src/index.js +121 -0
  74. package/src/motion/animate.js +145 -0
  75. package/src/motion/flip.js +46 -0
  76. package/src/motion/index.js +4 -0
  77. package/src/motion/presence.js +104 -0
  78. package/src/motion/ripple.js +108 -0
  79. package/src/theme/apply-theme.js +142 -0
  80. package/src/theme/create-theme.js +70 -0
  81. package/src/theme/index.js +5 -0
  82. package/src/tokens/color.js +237 -0
  83. package/src/tokens/index.js +14 -0
  84. package/src/tokens/sys.js +76 -0
  85. package/src/tokens/system.js +114 -0
  86. package/src/tokens/typography.js +189 -0
  87. package/src/util/focus.js +89 -0
  88. package/src/util/form.js +69 -0
  89. package/src/util/icons.js +161 -0
  90. package/src/util/keys.js +110 -0
  91. package/src/util/position.js +102 -0
  92. package/src/util/table.js +230 -0
  93. package/types/elements.d.ts +78 -0
  94. package/types/index.d.ts +168 -0
@@ -0,0 +1,170 @@
1
+ // <ui-toggle-button> — one Material segmented button, used inside
2
+ // <ui-toggle-group> (the group draws the outlined container and dividers;
3
+ // standalone the segment is a flat pill).
4
+ //
5
+ // Selecting animates a leading check icon in smoothly via width and scale transitions,
6
+ // adhering to Material Design 3. When an icon is already present, selecting smoothly
7
+ // crossfades and morphs between the custom icon and the checkmark in both directions.
8
+ // The button does not own its selection: it emits `ui-toggle` and the group
9
+ // (or any parent) sets `selected` back down.
10
+ //
11
+ // @prop {string} value='' — REQUIRED identity within the group
12
+ // @prop {boolean} selected=false — set by the owning group
13
+ // @prop {boolean} disabled=false
14
+ // @prop {string} icon='' — optional leading icon
15
+ // @event ui-toggle — pressed; detail: { value } (consumed by ui-toggle-group)
16
+ // @slot (default) — label
17
+ // @part control — the <button>
18
+ // @vars see `t` below (`themeVars.names`)
19
+
20
+ import { define, html, css, vars, computed } from '@alacris/core';
21
+ import { sys } from '../tokens/sys.js';
22
+ import { base, focusRingOn } from './base.js';
23
+ import { ripple } from '../motion/ripple.js';
24
+ import './ui-icon.js';
25
+
26
+ const t = vars('ui-toggle-button', {
27
+ height: '40px',
28
+ radius: sys.radius.full,
29
+ bg: sys.color.surface,
30
+ fg: sys.color.onSurface,
31
+ selectedBg: sys.color.secondaryContainer,
32
+ selectedFg: sys.color.onSecondaryContainer,
33
+ font: sys.type.labelLg,
34
+ tracking: sys.tracking.labelLg,
35
+ });
36
+
37
+ const styles = css`
38
+ :host { display: inline-flex; vertical-align: middle; flex: 1; }
39
+ .control {
40
+ position: relative;
41
+ isolation: isolate;
42
+ display: inline-flex;
43
+ align-items: center;
44
+ justify-content: center;
45
+ inline-size: 100%;
46
+ block-size: calc(${t.height} + var(--ui-density, 0) * 4px);
47
+ padding-inline: ${sys.space(3)};
48
+ border: none;
49
+ border-radius: ${t.radius};
50
+ background: ${t.bg};
51
+ color: ${t.fg};
52
+ font: ${t.font};
53
+ letter-spacing: ${t.tracking};
54
+ cursor: pointer;
55
+ user-select: none;
56
+ white-space: nowrap;
57
+ transition: background-color ${sys.duration.short4} ${sys.easing.standard},
58
+ color ${sys.duration.short4} ${sys.easing.standard};
59
+ --ui-icon-size: 1.125rem;
60
+ }
61
+ .lead {
62
+ position: relative;
63
+ display: inline-grid;
64
+ place-items: center;
65
+ inline-size: 0;
66
+ min-inline-size: 0;
67
+ block-size: 1.125rem;
68
+ overflow: hidden;
69
+ opacity: 0;
70
+ pointer-events: none;
71
+ transition: inline-size ${sys.duration.short4} ${sys.easing.emphasized},
72
+ margin-inline-end ${sys.duration.short4} ${sys.easing.emphasized},
73
+ opacity ${sys.duration.short2} ${sys.easing.standard};
74
+ }
75
+ .lead.on {
76
+ inline-size: 1.125rem;
77
+ margin-inline-end: ${sys.space(2)};
78
+ opacity: 1;
79
+ pointer-events: auto;
80
+ }
81
+ .lead ui-icon {
82
+ grid-area: 1 / 1;
83
+ display: inline-flex;
84
+ align-items: center;
85
+ justify-content: center;
86
+ transition: opacity ${sys.duration.short3} ${sys.easing.standard},
87
+ scale ${sys.duration.short3} ${sys.easing.emphasized},
88
+ transform ${sys.duration.short3} ${sys.easing.emphasized};
89
+ }
90
+ .lead .check-glyph {
91
+ opacity: 0;
92
+ scale: 0.5;
93
+ pointer-events: none;
94
+ }
95
+ .lead .check-glyph.on {
96
+ opacity: 1;
97
+ scale: 1;
98
+ pointer-events: auto;
99
+ }
100
+ .lead .custom-glyph {
101
+ opacity: 1;
102
+ scale: 1;
103
+ pointer-events: auto;
104
+ }
105
+ .lead .custom-glyph.off {
106
+ opacity: 0;
107
+ scale: 0.5;
108
+ pointer-events: none;
109
+ }
110
+
111
+ ${focusRingOn('.control')}
112
+ .layer {
113
+ position: absolute; inset: 0; z-index: -1;
114
+ border-radius: inherit;
115
+ background: currentColor;
116
+ opacity: 0;
117
+ transition: opacity ${sys.duration.short2} ${sys.easing.standard};
118
+ }
119
+ .control:hover .layer { opacity: ${sys.state.hover}; }
120
+ .control:focus-visible .layer { opacity: ${sys.state.focus}; }
121
+ .control:active .layer { opacity: ${sys.state.pressed}; }
122
+
123
+ .control[aria-pressed="true"] {
124
+ background: ${t.selectedBg};
125
+ color: ${t.selectedFg};
126
+ }
127
+
128
+ .control:disabled {
129
+ cursor: default;
130
+ pointer-events: none;
131
+ color: color-mix(in srgb, ${sys.color.onSurface} calc(${sys.state.disabledContent} * 100%), transparent);
132
+ }
133
+ .control:disabled[aria-pressed="true"] {
134
+ background: color-mix(in srgb, ${sys.color.onSurface} calc(${sys.state.disabledContainer} * 100%), transparent);
135
+ }
136
+ `;
137
+
138
+ define('ui-toggle-button', {
139
+ props: { value: '', selected: false, disabled: false, icon: '' },
140
+ styles: [base, styles],
141
+ setup({ value, selected, disabled, icon }, host) {
142
+ const onClick = () => {
143
+ if (disabled()) return;
144
+ host.emit('ui-toggle', { value: value() });
145
+ };
146
+
147
+ const isSelected = () => selected();
148
+ const hasIcon = () => !!icon();
149
+ const showLead = () => isSelected() || hasIcon();
150
+
151
+ return html`
152
+ <button part="control" class="control" type="button" ?disabled=${disabled}
153
+ aria-pressed=${() => String(selected())}
154
+ @click=${onClick} ref=${(el) => ripple(el, { disabled })}>
155
+ <span class="layer" aria-hidden="true"></span>
156
+ <span class=${() => `lead${showLead() ? ' on' : ''}`}>
157
+ <ui-icon class=${() => `check-glyph${isSelected() ? ' on' : ''}`}
158
+ name="check"></ui-icon>
159
+ ${() => (hasIcon()
160
+ ? html`<ui-icon class=${() => `custom-glyph${isSelected() ? ' off' : ''}`}
161
+ name=${icon}></ui-icon>`
162
+ : null)}
163
+ </span>
164
+ <slot></slot>
165
+ </button>`;
166
+ },
167
+ });
168
+
169
+ export const tag = 'ui-toggle-button';
170
+ export const themeVars = t;
@@ -0,0 +1,111 @@
1
+ // <ui-toggle-group> — Material segmented buttons: an outlined container that
2
+ // owns the selection of its slotted <ui-toggle-button>s.
3
+ //
4
+ // <ui-toggle-group value=${align} @change=${(e) => align.set(e.detail.value)}>
5
+ // <ui-toggle-button value="left">Left</ui-toggle-button>
6
+ // <ui-toggle-button value="right">Right</ui-toggle-button>
7
+ // </ui-toggle-group>
8
+ //
9
+ // Single-select by default (`value` is the selected string, '' for none;
10
+ // pressing the selected segment deselects it). With `multi`, `value` is an
11
+ // array (a JSON array string works as an attribute). Buttons are natural tab
12
+ // stops — no roving tabindex, per the toolbar-of-toggle-buttons pattern.
13
+ //
14
+ // @prop {string|array} value='' — selected value, or array when `multi`
15
+ // @prop {boolean} multi=false — multiple segments may be selected
16
+ // @prop {boolean} disabled=false — disables every segment
17
+ // @prop {string} label='' — accessible name for the group
18
+ // @event change — selection changed; detail: { value } (string, or array when multi)
19
+ // @slot (default) — the <ui-toggle-button> children
20
+ // @part group — the outlined clipping container
21
+ // @vars see `t` below (`themeVars.names`)
22
+
23
+ import { define, html, css, vars, effect, untrack } from '@alacris/core';
24
+ import { sys } from '../tokens/sys.js';
25
+ import { base } from './base.js';
26
+ import './ui-toggle-button.js';
27
+
28
+ const t = vars('ui-toggle-group', {
29
+ radius: sys.radius.full,
30
+ outlineColor: sys.color.outline,
31
+ });
32
+
33
+ const styles = css`
34
+ :host { display: inline-flex; vertical-align: middle; }
35
+ .group {
36
+ display: inline-flex;
37
+ align-items: stretch;
38
+ gap: 1px;
39
+ border: 1px solid ${t.outlineColor};
40
+ background: ${t.outlineColor};
41
+ border-radius: ${t.radius};
42
+ overflow: hidden;
43
+ }
44
+ ::slotted(ui-toggle-button) { --ui-toggle-button-radius: 0; flex: 1; }
45
+ `;
46
+
47
+ define('ui-toggle-group', {
48
+ props: { value: '', multi: false, disabled: false, label: '' },
49
+ styles: [base, styles],
50
+ setup({ value, multi, disabled, label }, host) {
51
+ const buttons = () => [...host.querySelectorAll('ui-toggle-button')];
52
+
53
+ /** Current selection, normalized to an array of values. */
54
+ const selection = () => {
55
+ const v = value();
56
+ if (Array.isArray(v)) return v;
57
+ if (typeof v === 'string' && v.trim().startsWith('[')) {
58
+ try { return JSON.parse(v); } catch { return []; }
59
+ }
60
+ return v == null || v === '' ? [] : [v];
61
+ };
62
+
63
+ // Reflect the selection down whenever value changes …
64
+ const sync = () => {
65
+ const sel = selection();
66
+ for (const b of buttons()) b.selected = sel.includes(b.value);
67
+ };
68
+ effect(sync);
69
+ // … and once after children have upgraded/distributed.
70
+ queueMicrotask(() => untrack(sync));
71
+
72
+ // Group-level disabling: remember which children we disabled so their own
73
+ // `disabled` survives the round trip.
74
+ let claimed = null;
75
+ effect(() => {
76
+ if (disabled()) {
77
+ if (claimed) return;
78
+ claimed = new Set();
79
+ for (const b of buttons()) if (!b.disabled) { b.disabled = true; claimed.add(b); }
80
+ } else if (claimed) {
81
+ for (const b of claimed) b.disabled = false;
82
+ claimed = null;
83
+ }
84
+ });
85
+
86
+ host.addEventListener('ui-toggle', (e) => {
87
+ e.stopPropagation();
88
+ if (disabled()) return;
89
+ const v = e.detail.value;
90
+ let next;
91
+ if (multi()) {
92
+ const sel = selection();
93
+ next = sel.includes(v) ? sel.filter((x) => x !== v) : [...sel, v];
94
+ } else {
95
+ next = selection().includes(v) ? '' : v;
96
+ }
97
+ value.set(next);
98
+ host.emit('change', { value: next });
99
+ });
100
+
101
+ return html`
102
+ <div class="group" part="group" role="group"
103
+ aria-label=${() => label() || null}
104
+ aria-disabled=${() => (disabled() ? 'true' : null)}>
105
+ <slot @slotchange=${() => untrack(sync)}></slot>
106
+ </div>`;
107
+ },
108
+ });
109
+
110
+ export const tag = 'ui-toggle-group';
111
+ export const themeVars = t;
@@ -0,0 +1,64 @@
1
+ // <ui-toolbar> — a Material contextual toolbar: a floating strip of icon
2
+ // actions, optionally with an attached FAB.
3
+ //
4
+ // <ui-toolbar label="Selection">
5
+ // <ui-icon-button icon="edit" label="Edit"></ui-icon-button>
6
+ // <ui-icon-button icon="delete" label="Delete"></ui-icon-button>
7
+ // <ui-fab slot="fab" icon="add" size="sm"></ui-fab>
8
+ // </ui-toolbar>
9
+ //
10
+ // @prop {string} label='' — accessible name for the toolbar
11
+ // @slot (default) — icon buttons and other actions
12
+ // @slot fab — optional <ui-fab> attached to the end
13
+ // @part bar, actions, fab
14
+ // @vars see `t` below (`themeVars.names`)
15
+
16
+ import { define, html, css, vars } from '@alacris/core';
17
+ import { sys } from '../tokens/sys.js';
18
+ import { base } from './base.js';
19
+
20
+ const t = vars('ui-toolbar', {
21
+ height: '64px',
22
+ bg: sys.color.surfaceContainer,
23
+ fg: sys.color.onSurface,
24
+ radius: sys.radius.full,
25
+ pad: sys.space(2),
26
+ elevation: sys.elevation[2],
27
+ });
28
+
29
+ const styles = css`
30
+ :host { display: inline-flex; vertical-align: middle; }
31
+ .bar {
32
+ display: inline-flex;
33
+ align-items: center;
34
+ gap: ${sys.space(1)};
35
+ min-block-size: ${t.height};
36
+ padding: ${t.pad};
37
+ background: ${t.bg};
38
+ color: ${t.fg};
39
+ border-radius: ${t.radius};
40
+ box-shadow: ${t.elevation};
41
+ }
42
+ .actions {
43
+ display: inline-flex;
44
+ align-items: center;
45
+ gap: ${sys.space(1)};
46
+ padding-inline: ${sys.space(1)};
47
+ }
48
+ .fab { display: inline-flex; align-items: center; }
49
+ `;
50
+
51
+ define('ui-toolbar', {
52
+ props: { label: '' },
53
+ styles: [base, styles],
54
+ setup({ label }) {
55
+ return html`
56
+ <div class="bar" part="bar" role="toolbar" aria-label=${() => label() || null}>
57
+ <div class="actions" part="actions"><slot></slot></div>
58
+ <div class="fab" part="fab"><slot name="fab"></slot></div>
59
+ </div>`;
60
+ },
61
+ });
62
+
63
+ export const tag = 'ui-toolbar';
64
+ export const themeVars = t;
@@ -0,0 +1,148 @@
1
+ // <ui-tooltip> — a plain (or rich) tooltip on hover/focus around its target.
2
+ //
3
+ // <ui-tooltip text="Save changes"><ui-button>Save</ui-button></ui-tooltip>
4
+ //
5
+ // Shows after `delay` ms on pointerenter (timer cancelled on leave) and
6
+ // immediately on focusin; hides on pointerleave, focusout, and Escape. The
7
+ // panel is position: fixed, anchored to the host with position()/autoUpdate,
8
+ // flipping to the opposite side when it would overflow the viewport.
9
+ //
10
+ // a11y: `aria-describedby` cannot point across shadow boundaries, so the
11
+ // association is not programmatic — the panel carries role="tooltip" and the
12
+ // target keeps its own accessible name. Give the target a matching
13
+ // label/aria-label when the tooltip is the only description.
14
+ //
15
+ // @prop {string} text='' — plain tooltip content
16
+ // @prop {string} position='top' — top | bottom | left | right
17
+ // @prop {number} delay=500 — hover show delay (ms); focus shows instantly
18
+ // @prop {boolean} rich=false — renders the `content` slot in a surface
19
+ // panel instead of the text pill
20
+ // @slot (default) — the target
21
+ // @slot content — rich tooltip content (title/body/actions) when `rich`
22
+ // @part panel — the tooltip surface
23
+ // @vars see `t` below
24
+
25
+ import { define, html, css, vars, effect, onCleanup, signal } from '@alacris/core';
26
+ import { sys } from '../tokens/sys.js';
27
+ import { base } from './base.js';
28
+ import { presence } from '../motion/presence.js';
29
+ import { fx } from '../motion/animate.js';
30
+ import { autoUpdate } from '../util/position.js';
31
+
32
+ const t = vars('ui-tooltip', {
33
+ bg: sys.color.inverseSurface,
34
+ fg: sys.color.inverseOnSurface,
35
+ font: sys.type.labelSm,
36
+ radius: sys.radius.xs,
37
+ maxWidth: '200px',
38
+ richBg: sys.color.surfaceContainer,
39
+ richFg: sys.color.onSurfaceVariant,
40
+ richRadius: sys.radius.md,
41
+ richMaxWidth: '320px',
42
+ });
43
+
44
+ const styles = css`
45
+ :host { display: inline-block; }
46
+ .panel {
47
+ position: fixed;
48
+ inset-inline-start: 0;
49
+ inset-block-start: 0;
50
+ z-index: ${sys.z.tooltip};
51
+ inline-size: max-content;
52
+ }
53
+ .plain {
54
+ background: ${t.bg};
55
+ color: ${t.fg};
56
+ font: ${t.font};
57
+ letter-spacing: ${sys.tracking.labelSm};
58
+ border-radius: ${t.radius};
59
+ padding: ${sys.space(1)} ${sys.space(2)};
60
+ max-inline-size: ${t.maxWidth};
61
+ pointer-events: none;
62
+ }
63
+ .rich {
64
+ background: ${t.richBg};
65
+ color: ${t.richFg};
66
+ font: ${sys.type.bodyMd};
67
+ letter-spacing: ${sys.tracking.bodyMd};
68
+ border-radius: ${t.richRadius};
69
+ box-shadow: ${sys.elevation[2]};
70
+ padding: ${sys.space(3)};
71
+ max-inline-size: ${t.richMaxWidth};
72
+ }
73
+ `;
74
+
75
+ define('ui-tooltip', {
76
+ props: { text: '', position: 'top', delay: 500, rich: false },
77
+ styles: [base, styles],
78
+ setup({ text, position: pos, delay, rich }, host) {
79
+ const open = signal(false);
80
+ let timer = 0;
81
+ let stopAuto = null;
82
+
83
+ const show = () => open.set(true);
84
+ const hide = () => {
85
+ clearTimeout(timer);
86
+ timer = 0;
87
+ open.set(false);
88
+ };
89
+
90
+ host.addEventListener('pointerenter', () => {
91
+ clearTimeout(timer);
92
+ const d = Math.max(0, delay());
93
+ if (d) timer = setTimeout(show, d);
94
+ else show();
95
+ });
96
+ host.addEventListener('pointerleave', hide);
97
+ host.addEventListener('focusin', show); // no delay on keyboard focus
98
+ host.addEventListener('focusout', hide);
99
+
100
+ // Escape hides even while focus is elsewhere on the page.
101
+ effect(() => {
102
+ if (!open()) return;
103
+ const onKey = (e) => { if (e.key === 'Escape') hide(); };
104
+ document.addEventListener('keydown', onKey, true);
105
+ return () => document.removeEventListener('keydown', onKey, true);
106
+ });
107
+
108
+ // Anchor tracking lives exactly as long as the panel does.
109
+ effect(() => {
110
+ if (!open()) {
111
+ stopAuto?.();
112
+ stopAuto = null;
113
+ }
114
+ });
115
+ onCleanup(() => {
116
+ clearTimeout(timer);
117
+ stopAuto?.();
118
+ stopAuto = null;
119
+ });
120
+
121
+ const anchor = (el) => {
122
+ stopAuto?.();
123
+ stopAuto = autoUpdate(el, host, {
124
+ placement: `${pos()}-center`,
125
+ offset: 8,
126
+ });
127
+ };
128
+
129
+ const view = () => html`
130
+ <div part="panel" role="tooltip"
131
+ class=${() => `panel ${rich() ? 'rich' : 'plain'}`}
132
+ ref=${anchor}>
133
+ ${() => (rich() ? html`<slot name="content"></slot>` : html`${text}`)}
134
+ </div>`;
135
+
136
+ return html`
137
+ <slot></slot>
138
+ ${presence(open, view, {
139
+ enter: fx.fadeIn,
140
+ exit: fx.fadeOut,
141
+ enterDuration: 'short2',
142
+ exitDuration: 'short2',
143
+ })}`;
144
+ },
145
+ });
146
+
147
+ export const tag = 'ui-tooltip';
148
+ export const themeVars = t;
package/src/index.js ADDED
@@ -0,0 +1,121 @@
1
+ // Alacris UI — public surface (`@alacris/ui` on npm).
2
+ //
3
+ // Importing this module registers every component and re-exports the theme,
4
+ // motion, token, and utility APIs. Tree-shaking-friendly alternative: import
5
+ // only the component files and helpers you use — each component module is
6
+ // self-contained. Do not bundle a second copy of `@alacris/core`; these modules
7
+ // import it by specifier so the app and the design system share one graph.
8
+
9
+ // Theme
10
+ export {
11
+ createTheme, applyTheme, themeCss, activeTheme, loadThemeFonts,
12
+ scheme, schemePreference, setScheme, toggleScheme,
13
+ } from './theme/index.js';
14
+
15
+ // Tokens
16
+ export { sys, typeRule } from './tokens/sys.js';
17
+ export {
18
+ FONT_PRESETS, FONT_STACKS, DEFAULT_FONT_PRESET, TYPE_ROLES,
19
+ resolveTypography, googleFontsHref,
20
+ } from './tokens/typography.js';
21
+
22
+ // Motion
23
+ export { animate, settled, duration, easing, fx, prefersReducedMotion } from './motion/animate.js';
24
+ export { presence } from './motion/presence.js';
25
+ export { withFlip } from './motion/flip.js';
26
+ export { ripple } from './motion/ripple.js';
27
+
28
+ // Utilities
29
+ export { position, autoUpdate } from './util/position.js';
30
+ export { focusTrap, focusables, scrollLock } from './util/focus.js';
31
+ export { rovingTabindex } from './util/keys.js';
32
+ export { formBind } from './util/form.js';
33
+ export { registerIcons, iconPath, iconNames } from './util/icons.js';
34
+ export {
35
+ processTable, filterRows, sortRows, groupRows, paginate,
36
+ aggregateRow, toCsv, downloadText, inferColumns, visibleColumns,
37
+ } from './util/table.js';
38
+
39
+ // Components — importing registers the custom element.
40
+ import './components/ui-icon.js';
41
+ import './components/ui-text.js';
42
+
43
+ // Actions
44
+ import './components/ui-button.js';
45
+ import './components/ui-icon-button.js';
46
+ import './components/ui-fab.js';
47
+ import './components/ui-fab-menu.js';
48
+ import './components/ui-button-group.js';
49
+ import './components/ui-split-button.js';
50
+ import './components/ui-toggle-button.js';
51
+ import './components/ui-toggle-group.js';
52
+
53
+ // Inputs
54
+ import './components/ui-checkbox.js';
55
+ import './components/ui-radio.js';
56
+ import './components/ui-radio-group.js';
57
+ import './components/ui-switch.js';
58
+ import './components/ui-slider.js';
59
+ import './components/ui-rating.js';
60
+ import './components/ui-text-field.js';
61
+ import './components/ui-select.js';
62
+ import './components/ui-option.js';
63
+ import './components/ui-autocomplete.js';
64
+ import './components/ui-chip.js';
65
+ import './components/ui-chip-set.js';
66
+ import './components/ui-date-picker.js';
67
+ import './components/ui-time-picker.js';
68
+ import './components/ui-search.js';
69
+
70
+ // Data display
71
+ import './components/ui-avatar.js';
72
+ import './components/ui-badge.js';
73
+ import './components/ui-divider.js';
74
+ import './components/ui-list.js';
75
+ import './components/ui-list-item.js';
76
+ import './components/ui-table.js';
77
+ import './components/ui-table-toolbar.js';
78
+ import './components/ui-table-footer.js';
79
+ import './components/ui-tooltip.js';
80
+ import './components/ui-carousel.js';
81
+ import './components/ui-carousel-item.js';
82
+
83
+ // Feedback
84
+ import './components/ui-alert.js';
85
+ import './components/ui-progress.js';
86
+ import './components/ui-spinner.js';
87
+ import './components/ui-loading-indicator.js';
88
+ import './components/ui-skeleton.js';
89
+ import './components/ui-snackbar.js';
90
+ import './components/ui-backdrop.js';
91
+ import './components/ui-sheet.js';
92
+ import './components/ui-side-sheet.js';
93
+
94
+ export { showSnackbar } from './components/ui-snackbar.js';
95
+
96
+ // Surfaces & navigation
97
+ import './components/ui-card.js';
98
+ import './components/ui-dialog.js';
99
+ import './components/ui-tabs.js';
100
+ import './components/ui-tab.js';
101
+ import './components/ui-tab-panel.js';
102
+ import './components/ui-menu.js';
103
+ import './components/ui-menu-item.js';
104
+ import './components/ui-drawer.js';
105
+ import './components/ui-app-bar.js';
106
+ import './components/ui-bottom-app-bar.js';
107
+ import './components/ui-toolbar.js';
108
+ import './components/ui-accordion.js';
109
+ import './components/ui-accordion-item.js';
110
+ import './components/ui-breadcrumbs.js';
111
+ import './components/ui-pagination.js';
112
+ import './components/ui-stepper.js';
113
+ import './components/ui-step.js';
114
+ import './components/ui-bottom-nav.js';
115
+ import './components/ui-nav-item.js';
116
+ import './components/ui-nav-rail.js';
117
+
118
+ // Layout
119
+ import './components/ui-stack.js';
120
+ import './components/ui-container.js';
121
+ import './components/ui-surface.js';