@threadlabs/looma 0.1.3 → 0.1.4

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 (88) hide show
  1. package/dist/{chunk-UDP2LUZ2.js → chunk-3PASQ7DE.js} +26 -26
  2. package/dist/cjs/ui-dialog.cjs.entry.js +1 -1
  3. package/dist/cjs/ui-floating-action-button.cjs.entry.js +1 -1
  4. package/dist/cjs/ui-menu.cjs.entry.js +1 -1
  5. package/dist/cjs/ui-popover.cjs.entry.js +1 -1
  6. package/dist/cjs/ui-search-shell.cjs.entry.js +1 -1
  7. package/dist/cjs/ui-tabs.cjs.entry.js +1 -1
  8. package/dist/cjs/ui-toast-region.cjs.entry.js +1 -1
  9. package/dist/cjs/ui-top-bar.cjs.entry.js +1 -1
  10. package/dist/collection/components/ui-dialog/ui-dialog.css +10 -4
  11. package/dist/collection/components/ui-floating-action-button/ui-floating-action-button.css +4 -1
  12. package/dist/collection/components/ui-menu/ui-menu.css +4 -1
  13. package/dist/collection/components/ui-popover/ui-popover.css +7 -1
  14. package/dist/collection/components/ui-search-shell/ui-search-shell.css +3 -1
  15. package/dist/collection/components/ui-tabs/ui-tabs.css +3 -0
  16. package/dist/collection/components/ui-toast-region/ui-toast-region.css +3 -2
  17. package/dist/collection/components/ui-top-bar/ui-top-bar.css +10 -2
  18. package/dist/components/p-gHC_Ei92.js +1 -0
  19. package/dist/components/ui-context-menu.js +1 -1
  20. package/dist/components/ui-dialog.js +1 -1
  21. package/dist/components/ui-floating-action-button.js +1 -1
  22. package/dist/components/ui-menu.js +1 -1
  23. package/dist/components/ui-popover.js +1 -1
  24. package/dist/components/ui-search-shell.js +1 -1
  25. package/dist/components/ui-tabs.js +1 -1
  26. package/dist/components/ui-toast-region.js +1 -1
  27. package/dist/components/ui-top-bar.js +1 -1
  28. package/dist/esm/ui-dialog.entry.js +1 -1
  29. package/dist/esm/ui-floating-action-button.entry.js +1 -1
  30. package/dist/esm/ui-menu.entry.js +1 -1
  31. package/dist/esm/ui-popover.entry.js +1 -1
  32. package/dist/esm/ui-search-shell.entry.js +1 -1
  33. package/dist/esm/ui-tabs.entry.js +1 -1
  34. package/dist/esm/ui-toast-region.entry.js +1 -1
  35. package/dist/esm/ui-top-bar.entry.js +1 -1
  36. package/dist/index.cjs +8 -8
  37. package/dist/index.js +1 -1
  38. package/dist/looma/looma.esm.js +1 -1
  39. package/dist/looma/p-01425a37.entry.js +1 -0
  40. package/dist/looma/p-07167650.entry.js +1 -0
  41. package/dist/looma/{p-341ba64a.entry.js → p-3ecd7120.entry.js} +1 -1
  42. package/dist/looma/p-940a931a.entry.js +1 -0
  43. package/dist/looma/p-941221ad.entry.js +1 -0
  44. package/dist/looma/p-a7be33fd.entry.js +1 -0
  45. package/dist/looma/{p-4742e6b4.entry.js → p-cb15e8e3.entry.js} +1 -1
  46. package/dist/looma/p-d39905f9.entry.js +1 -0
  47. package/dist/{ui-avatar-group.entry-VDMJ7TD3.js → ui-avatar-group.entry-DBVLQ4KB.js} +1 -1
  48. package/dist/{ui-avatar.entry-OV25NM66.js → ui-avatar.entry-2WTBM2EC.js} +1 -1
  49. package/dist/{ui-badge.entry-MX66BWUJ.js → ui-badge.entry-XKIGBK5V.js} +1 -1
  50. package/dist/{ui-button.entry-UCVR22M7.js → ui-button.entry-PWT56MPD.js} +1 -1
  51. package/dist/{ui-checkbox.entry-KL47EXSZ.js → ui-checkbox.entry-QT5S7EEL.js} +1 -1
  52. package/dist/{ui-context-menu.entry-677NGG3Q.js → ui-context-menu.entry-NGWR3LOZ.js} +1 -1
  53. package/dist/{ui-dialog.entry-WZIIRD4O.js → ui-dialog.entry-PEDDIALQ.js} +2 -2
  54. package/dist/{ui-disclosure.entry-Z7LSLWFL.js → ui-disclosure.entry-UKO7MAZM.js} +1 -1
  55. package/dist/ui-floating-action-button.entry-SSGHRMCO.js +23 -0
  56. package/dist/{ui-form-field.entry-DZSNUUXG.js → ui-form-field.entry-6TZCWPYL.js} +1 -1
  57. package/dist/{ui-icon-button.entry-QKEQNOKJ.js → ui-icon-button.entry-WMCYMK2H.js} +1 -1
  58. package/dist/{ui-input.entry-BI74QOJP.js → ui-input.entry-AZ5BGQNA.js} +1 -1
  59. package/dist/{ui-menu-item.entry-GB462MWK.js → ui-menu-item.entry-L4NJDBKF.js} +1 -1
  60. package/dist/{ui-menu.entry-RUJ5XZ7Y.js → ui-menu.entry-DGUYAE3Q.js} +2 -2
  61. package/dist/{ui-popover.entry-QW26NSSB.js → ui-popover.entry-A54EKVZG.js} +2 -2
  62. package/dist/{ui-radio-group.entry-LC2BSS35.js → ui-radio-group.entry-6YP4LY4N.js} +1 -1
  63. package/dist/{ui-radio.entry-2RQD4K5L.js → ui-radio.entry-CGYNK7PN.js} +1 -1
  64. package/dist/{ui-search-result-row.entry-BAHYKCAZ.js → ui-search-result-row.entry-DGKSI2QM.js} +1 -1
  65. package/dist/{ui-search-shell.entry-PW2AF6HX.js → ui-search-shell.entry-3F5ASGTW.js} +2 -2
  66. package/dist/{ui-select.entry-NHWCGJQH.js → ui-select.entry-SXSZPVXA.js} +1 -1
  67. package/dist/{ui-switch.entry-76KOUHCH.js → ui-switch.entry-AD4EVUWM.js} +1 -1
  68. package/dist/{ui-tabs.entry-5PZGTNKM.js → ui-tabs.entry-WLKO5G5N.js} +2 -2
  69. package/dist/{ui-textarea.entry-IQHQHO3L.js → ui-textarea.entry-IHPC7Q4R.js} +1 -1
  70. package/dist/{ui-toast-region.entry-2LT2RTPJ.js → ui-toast-region.entry-GCW2LJAC.js} +2 -2
  71. package/dist/{ui-tooltip.entry-42V5BSUT.js → ui-tooltip.entry-EU2G6BH5.js} +1 -1
  72. package/dist/{ui-top-bar.entry-UZTSRNFZ.js → ui-top-bar.entry-NMAFXVET.js} +2 -2
  73. package/layout/index.cjs +82 -0
  74. package/layout/index.css +165 -8
  75. package/layout/index.js +82 -0
  76. package/layout.css +113 -9
  77. package/package.json +1 -1
  78. package/styles.css +5 -4
  79. package/vue/index.d.ts +13 -1
  80. package/vue/index.js +9 -0
  81. package/dist/components/p-WvL4iAhX.js +0 -1
  82. package/dist/looma/p-52c537fa.entry.js +0 -1
  83. package/dist/looma/p-649dad92.entry.js +0 -1
  84. package/dist/looma/p-ab4151d5.entry.js +0 -1
  85. package/dist/looma/p-dff144bd.entry.js +0 -1
  86. package/dist/looma/p-ebb74106.entry.js +0 -1
  87. package/dist/looma/p-ecb5739b.entry.js +0 -1
  88. package/dist/ui-floating-action-button.entry-ZDMXBJVC.js +0 -23
@@ -7,10 +7,10 @@ import {
7
7
  getElement,
8
8
  h,
9
9
  registerInstance
10
- } from "./chunk-UDP2LUZ2.js";
10
+ } from "./chunk-3PASQ7DE.js";
11
11
 
12
12
  // dist/esm/ui-toast-region.entry.js
13
- var uiToastRegionCss = () => `:host{position:fixed;top:var(--ui-space-4);left:50%;transform:translateX(-50%);z-index:9999;display:grid;gap:var(--ui-space-2);max-width:min(24rem, 90vw);pointer-events:none}:host>*{pointer-events:auto}::slotted([data-ui-toast]){display:grid;grid-template-columns:1fr auto;gap:var(--ui-space-2);align-items:start;border:1px solid var(--ui-border-default);border-radius:var(--ui-radius-3);padding:var(--ui-space-3) var(--ui-space-4);background:var(--ui-surface-elevated);color:var(--ui-text-primary);box-shadow:var(--ui-shadow-lg);animation:ui-toast-enter 0.25s var(--ui-motion-ease) forwards}@keyframes ui-toast-enter{from{opacity:0;transform:translateY(-0.5rem)}to{opacity:1;transform:translateY(0)}}::slotted([data-ui-toast][aria-hidden='true']){display:none}::slotted([data-ui-toast-dismiss]){border:0;background:transparent;color:var(--ui-text-secondary);cursor:pointer;font:inherit}`;
13
+ var uiToastRegionCss = () => `:host{position:fixed;top:calc(var(--ui-space-4) + env(safe-area-inset-top));left:50%;transform:translateX(-50%);z-index:9999;display:grid;gap:var(--ui-space-2);inline-size:min(24rem, calc(100vw - (var(--ui-space-4) * 2)));max-inline-size:100%;pointer-events:none}:host>*{pointer-events:auto}::slotted([data-ui-toast]){display:grid;grid-template-columns:1fr auto;gap:var(--ui-space-2);align-items:start;border:1px solid var(--ui-border-default);border-radius:var(--ui-radius-3);padding:var(--ui-space-3) var(--ui-space-4);background:var(--ui-surface-elevated);color:var(--ui-text-primary);box-shadow:var(--ui-shadow-lg);animation:ui-toast-enter 0.25s var(--ui-motion-ease) forwards}@keyframes ui-toast-enter{from{opacity:0;transform:translateY(-0.5rem)}to{opacity:1;transform:translateY(0)}}::slotted([data-ui-toast][aria-hidden='true']){display:none}::slotted([data-ui-toast-dismiss]){border:0;background:transparent;color:var(--ui-text-secondary);cursor:pointer;font:inherit}`;
14
14
  var UIToastRegion = class {
15
15
  constructor(hostRef) {
16
16
  registerInstance(this, hostRef);
@@ -11,7 +11,7 @@ import {
11
11
  getElement,
12
12
  h,
13
13
  registerInstance
14
- } from "./chunk-UDP2LUZ2.js";
14
+ } from "./chunk-3PASQ7DE.js";
15
15
 
16
16
  // dist/esm/ui-tooltip.entry.js
17
17
  var uiTooltipCss = () => `:host{display:inline-block;border:1px solid var(--ui-border-default);border-radius:var(--ui-radius-2);background:var(--ui-surface-elevated);color:var(--ui-text-primary);padding:var(--ui-space-2) var(--ui-space-3);font-size:var(--ui-font-size-sm);box-shadow:var(--ui-shadow-md)}:host([hidden]){display:none !important}`;
@@ -3,10 +3,10 @@ import {
3
3
  getElement,
4
4
  h,
5
5
  registerInstance
6
- } from "./chunk-UDP2LUZ2.js";
6
+ } from "./chunk-3PASQ7DE.js";
7
7
 
8
8
  // dist/esm/ui-top-bar.entry.js
9
- var uiTopBarCss = () => `:host{position:sticky;inset-block-start:0;z-index:var(--ui-top-bar-z-index, 100);display:block}.top-bar{min-block-size:var(--ui-top-bar-height, 56px);display:flex;align-items:center;gap:var(--ui-top-bar-gap, var(--ui-space-3, 0.75rem));padding-inline:var(--ui-top-bar-padding-inline, var(--ui-space-4, 1rem));background:var(--ui-top-bar-bg, var(--ui-surface, #ffffff));border-block-end:1px solid var(--ui-top-bar-border, var(--ui-border, #e5e7eb))}.top-bar__leading,.top-bar__search,.top-bar__actions{display:flex;align-items:center;flex-shrink:0}.top-bar__actions{gap:var(--ui-top-bar-actions-gap, var(--ui-space-1, 0.25rem))}.top-bar__title{min-inline-size:0;flex:1}[hidden]{display:none}@media (min-width: 768px){:host{display:none}}`;
9
+ var uiTopBarCss = () => `:host{position:sticky;inset-block-start:0;z-index:var(--ui-top-bar-z-index, 100);display:block}.top-bar{min-block-size:calc(var(--ui-top-bar-height, 56px) + env(safe-area-inset-top));display:flex;align-items:center;gap:var(--ui-top-bar-gap, var(--ui-space-3, 0.75rem));padding-block-start:env(safe-area-inset-top);padding-inline-start:max( var(--ui-top-bar-padding-inline, var(--ui-space-4, 1rem)), env(safe-area-inset-left) );padding-inline-end:max( var(--ui-top-bar-padding-inline, var(--ui-space-4, 1rem)), env(safe-area-inset-right) );background:var(--ui-top-bar-bg, var(--ui-surface, #ffffff));border-block-end:1px solid var(--ui-top-bar-border, var(--ui-border, #e5e7eb))}.top-bar__leading,.top-bar__search,.top-bar__actions{display:flex;align-items:center;flex-shrink:0}.top-bar__actions{gap:var(--ui-top-bar-actions-gap, var(--ui-space-1, 0.25rem))}.top-bar__title{min-inline-size:0;flex:1}[hidden]{display:none}@media (min-width: 768px){:host{display:none}}`;
10
10
  function slotHasContent(slot) {
11
11
  if (!slot) {
12
12
  return false;
package/layout/index.cjs CHANGED
@@ -151,6 +151,85 @@ if (typeof HTMLElement !== "undefined") {
151
151
  this.setPrimitiveAttribute("gutters", value);
152
152
  }
153
153
  }
154
+ class UISwitcherElement extends UILayoutElement {
155
+ static get observedAttributes() {
156
+ return ["gap", "threshold", "align"];
157
+ }
158
+ get gap() {
159
+ return this.getPrimitiveAttribute("gap");
160
+ }
161
+ set gap(value) {
162
+ this.setPrimitiveAttribute("gap", value);
163
+ }
164
+ get threshold() {
165
+ return this.getPrimitiveAttribute("threshold");
166
+ }
167
+ set threshold(value) {
168
+ this.setPrimitiveAttribute("threshold", value);
169
+ }
170
+ get align() {
171
+ return this.getPrimitiveAttribute("align");
172
+ }
173
+ set align(value) {
174
+ this.setPrimitiveAttribute("align", value);
175
+ }
176
+ }
177
+ class UISidebarElement extends UILayoutElement {
178
+ static get observedAttributes() {
179
+ return ["gap", "side", "width", "align"];
180
+ }
181
+ get gap() {
182
+ return this.getPrimitiveAttribute("gap");
183
+ }
184
+ set gap(value) {
185
+ this.setPrimitiveAttribute("gap", value);
186
+ }
187
+ get side() {
188
+ return this.getPrimitiveAttribute("side");
189
+ }
190
+ set side(value) {
191
+ this.setPrimitiveAttribute("side", value);
192
+ }
193
+ get width() {
194
+ return this.getPrimitiveAttribute("width");
195
+ }
196
+ set width(value) {
197
+ this.setPrimitiveAttribute("width", value);
198
+ }
199
+ get align() {
200
+ return this.getPrimitiveAttribute("align");
201
+ }
202
+ set align(value) {
203
+ this.setPrimitiveAttribute("align", value);
204
+ }
205
+ }
206
+ class UIReelElement extends UILayoutElement {
207
+ static get observedAttributes() {
208
+ return ["gap", "item-width", "snap"];
209
+ }
210
+ connectedCallback() {
211
+ if (!this.hasAttribute("role")) this.setAttribute("role", "region");
212
+ if (!this.hasAttribute("tabindex")) this.setAttribute("tabindex", "0");
213
+ }
214
+ get gap() {
215
+ return this.getPrimitiveAttribute("gap");
216
+ }
217
+ set gap(value) {
218
+ this.setPrimitiveAttribute("gap", value);
219
+ }
220
+ get itemWidth() {
221
+ return this.getPrimitiveAttribute("item-width");
222
+ }
223
+ set itemWidth(value) {
224
+ this.setPrimitiveAttribute("item-width", value);
225
+ }
226
+ get snap() {
227
+ return this.getPrimitiveAttribute("snap");
228
+ }
229
+ set snap(value) {
230
+ this.setPrimitiveAttribute("snap", value);
231
+ }
232
+ }
154
233
  class UISeparatorElement extends UILayoutElement {
155
234
  static get observedAttributes() {
156
235
  return ["orientation", "role"];
@@ -191,6 +270,9 @@ if (typeof HTMLElement !== "undefined") {
191
270
  ["ui-cluster", UIClusterElement],
192
271
  ["ui-grid", UIGridElement],
193
272
  ["ui-center", UICenterElement],
273
+ ["ui-switcher", UISwitcherElement],
274
+ ["ui-sidebar", UISidebarElement],
275
+ ["ui-reel", UIReelElement],
194
276
  ["ui-separator", UISeparatorElement]
195
277
  ];
196
278
  for (const [tag, constructor] of definitions) {
package/layout/index.css CHANGED
@@ -1,12 +1,12 @@
1
1
  /* src/layout.css */
2
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator),
3
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator) *,
4
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator) *::before,
5
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator) *::after {
2
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator),
3
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator) *,
4
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator) *::before,
5
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator) *::after {
6
6
  box-sizing: border-box;
7
7
  }
8
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator) {
9
- all: revert;
8
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator) {
9
+ all: revert-layer;
10
10
  box-sizing: border-box;
11
11
  margin: 0;
12
12
  font-family: var(--ui-font-family-sans);
@@ -14,7 +14,7 @@
14
14
  line-height: var(--ui-line-height-md);
15
15
  color: var(--ui-text-primary);
16
16
  }
17
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator)[data-ui-inherit-typography] {
17
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator)[data-ui-inherit-typography] {
18
18
  font-family: inherit;
19
19
  font-size: inherit;
20
20
  line-height: inherit;
@@ -28,6 +28,10 @@
28
28
  font-variation-settings: inherit;
29
29
  }
30
30
  @layer components {
31
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator) {
32
+ min-inline-size: 0;
33
+ max-inline-size: 100%;
34
+ }
31
35
  ui-stack {
32
36
  --ui-layout-gap: var(--ui-space-4, 1rem);
33
37
  --ui-layout-align: stretch;
@@ -102,7 +106,7 @@
102
106
  --ui-grid-min: 16rem;
103
107
  display: grid;
104
108
  gap: var(--ui-grid-gap);
105
- grid-template-columns: repeat(auto-fit, minmax(var(--ui-grid-min), 1fr));
109
+ grid-template-columns: repeat(auto-fit, minmax(min(var(--ui-grid-min), 100%), 1fr));
106
110
  }
107
111
  ui-grid[gap=xs] {
108
112
  --ui-grid-gap: var(--ui-space-2, 0.5rem);
@@ -129,6 +133,7 @@
129
133
  --ui-center-measure: 65ch;
130
134
  --ui-center-gutters: var(--ui-space-4, 1rem);
131
135
  display: block;
136
+ inline-size: 100%;
132
137
  max-inline-size: var(--ui-center-measure);
133
138
  margin-inline: auto;
134
139
  padding-inline: var(--ui-center-gutters);
@@ -148,6 +153,158 @@
148
153
  ui-center[gutters=l] {
149
154
  --ui-center-gutters: var(--ui-space-5, 1.5rem);
150
155
  }
156
+ ui-switcher {
157
+ --ui-switcher-gap: var(--ui-space-4, 1rem);
158
+ --ui-switcher-threshold: 30rem;
159
+ --ui-switcher-align: stretch;
160
+ display: flex;
161
+ flex-wrap: wrap;
162
+ gap: var(--ui-switcher-gap);
163
+ align-items: var(--ui-switcher-align);
164
+ }
165
+ ui-switcher > * {
166
+ min-inline-size: 0;
167
+ flex-grow: 1;
168
+ flex-basis: calc((var(--ui-switcher-threshold) - 100%) * 999);
169
+ }
170
+ ui-switcher[gap=xs] {
171
+ --ui-switcher-gap: var(--ui-space-2, 0.5rem);
172
+ }
173
+ ui-switcher[gap=s] {
174
+ --ui-switcher-gap: var(--ui-space-3, 0.75rem);
175
+ }
176
+ ui-switcher[gap=m] {
177
+ --ui-switcher-gap: var(--ui-space-4, 1rem);
178
+ }
179
+ ui-switcher[gap=l] {
180
+ --ui-switcher-gap: var(--ui-space-5, 1.5rem);
181
+ }
182
+ ui-switcher[threshold=xs] {
183
+ --ui-switcher-threshold: 20rem;
184
+ }
185
+ ui-switcher[threshold=sm] {
186
+ --ui-switcher-threshold: 30rem;
187
+ }
188
+ ui-switcher[threshold=md] {
189
+ --ui-switcher-threshold: 45rem;
190
+ }
191
+ ui-switcher[threshold=lg] {
192
+ --ui-switcher-threshold: 60rem;
193
+ }
194
+ ui-switcher[align=start] {
195
+ --ui-switcher-align: flex-start;
196
+ }
197
+ ui-switcher[align=center] {
198
+ --ui-switcher-align: center;
199
+ }
200
+ ui-switcher[align=end] {
201
+ --ui-switcher-align: flex-end;
202
+ }
203
+ ui-sidebar {
204
+ --ui-sidebar-gap: var(--ui-space-4, 1rem);
205
+ --ui-sidebar-width: 18rem;
206
+ --ui-sidebar-content-min: 50%;
207
+ --ui-sidebar-align: stretch;
208
+ display: flex;
209
+ flex-wrap: wrap;
210
+ gap: var(--ui-sidebar-gap);
211
+ align-items: var(--ui-sidebar-align);
212
+ }
213
+ ui-sidebar > * {
214
+ min-inline-size: 0;
215
+ }
216
+ ui-sidebar > :first-child {
217
+ flex-basis: var(--ui-sidebar-width);
218
+ flex-grow: 1;
219
+ }
220
+ ui-sidebar > :last-child {
221
+ flex-basis: 0;
222
+ flex-grow: 999;
223
+ min-inline-size: min(var(--ui-sidebar-content-min), 100%);
224
+ }
225
+ ui-sidebar[side=end] > :first-child {
226
+ flex-basis: 0;
227
+ flex-grow: 999;
228
+ min-inline-size: min(var(--ui-sidebar-content-min), 100%);
229
+ }
230
+ ui-sidebar[side=end] > :last-child {
231
+ flex-basis: var(--ui-sidebar-width);
232
+ flex-grow: 1;
233
+ min-inline-size: 0;
234
+ }
235
+ ui-sidebar[gap=xs] {
236
+ --ui-sidebar-gap: var(--ui-space-2, 0.5rem);
237
+ }
238
+ ui-sidebar[gap=s] {
239
+ --ui-sidebar-gap: var(--ui-space-3, 0.75rem);
240
+ }
241
+ ui-sidebar[gap=m] {
242
+ --ui-sidebar-gap: var(--ui-space-4, 1rem);
243
+ }
244
+ ui-sidebar[gap=l] {
245
+ --ui-sidebar-gap: var(--ui-space-5, 1.5rem);
246
+ }
247
+ ui-sidebar[width=narrow] {
248
+ --ui-sidebar-width: 14rem;
249
+ }
250
+ ui-sidebar[width=wide] {
251
+ --ui-sidebar-width: 24rem;
252
+ }
253
+ ui-sidebar[align=start] {
254
+ --ui-sidebar-align: flex-start;
255
+ }
256
+ ui-sidebar[align=center] {
257
+ --ui-sidebar-align: center;
258
+ }
259
+ ui-sidebar[align=end] {
260
+ --ui-sidebar-align: flex-end;
261
+ }
262
+ ui-reel {
263
+ --ui-reel-gap: var(--ui-space-4, 1rem);
264
+ --ui-reel-item-width: auto;
265
+ display: flex;
266
+ inline-size: 100%;
267
+ gap: var(--ui-reel-gap);
268
+ overflow-x: auto;
269
+ overflow-y: hidden;
270
+ overscroll-behavior-inline: contain;
271
+ -webkit-overflow-scrolling: touch;
272
+ }
273
+ ui-reel > * {
274
+ min-inline-size: 0;
275
+ flex: 0 0 var(--ui-reel-item-width);
276
+ }
277
+ ui-reel[gap=xs] {
278
+ --ui-reel-gap: var(--ui-space-2, 0.5rem);
279
+ }
280
+ ui-reel[gap=s] {
281
+ --ui-reel-gap: var(--ui-space-3, 0.75rem);
282
+ }
283
+ ui-reel[gap=m] {
284
+ --ui-reel-gap: var(--ui-space-4, 1rem);
285
+ }
286
+ ui-reel[gap=l] {
287
+ --ui-reel-gap: var(--ui-space-5, 1.5rem);
288
+ }
289
+ ui-reel[item-width=sm] {
290
+ --ui-reel-item-width: 12rem;
291
+ }
292
+ ui-reel[item-width=md] {
293
+ --ui-reel-item-width: 16rem;
294
+ }
295
+ ui-reel[item-width=lg] {
296
+ --ui-reel-item-width: 20rem;
297
+ }
298
+ ui-reel[snap=start],
299
+ ui-reel[snap=center] {
300
+ scroll-snap-type: inline mandatory;
301
+ }
302
+ ui-reel[snap=start] > * {
303
+ scroll-snap-align: start;
304
+ }
305
+ ui-reel[snap=center] > * {
306
+ scroll-snap-align: center;
307
+ }
151
308
  ui-separator {
152
309
  --ui-separator-color: var(--ui-border-default, #d0d5dd);
153
310
  --ui-separator-space: var(--ui-space-4, 1rem);
package/layout/index.js CHANGED
@@ -127,6 +127,85 @@ if (typeof HTMLElement !== "undefined") {
127
127
  this.setPrimitiveAttribute("gutters", value);
128
128
  }
129
129
  }
130
+ class UISwitcherElement extends UILayoutElement {
131
+ static get observedAttributes() {
132
+ return ["gap", "threshold", "align"];
133
+ }
134
+ get gap() {
135
+ return this.getPrimitiveAttribute("gap");
136
+ }
137
+ set gap(value) {
138
+ this.setPrimitiveAttribute("gap", value);
139
+ }
140
+ get threshold() {
141
+ return this.getPrimitiveAttribute("threshold");
142
+ }
143
+ set threshold(value) {
144
+ this.setPrimitiveAttribute("threshold", value);
145
+ }
146
+ get align() {
147
+ return this.getPrimitiveAttribute("align");
148
+ }
149
+ set align(value) {
150
+ this.setPrimitiveAttribute("align", value);
151
+ }
152
+ }
153
+ class UISidebarElement extends UILayoutElement {
154
+ static get observedAttributes() {
155
+ return ["gap", "side", "width", "align"];
156
+ }
157
+ get gap() {
158
+ return this.getPrimitiveAttribute("gap");
159
+ }
160
+ set gap(value) {
161
+ this.setPrimitiveAttribute("gap", value);
162
+ }
163
+ get side() {
164
+ return this.getPrimitiveAttribute("side");
165
+ }
166
+ set side(value) {
167
+ this.setPrimitiveAttribute("side", value);
168
+ }
169
+ get width() {
170
+ return this.getPrimitiveAttribute("width");
171
+ }
172
+ set width(value) {
173
+ this.setPrimitiveAttribute("width", value);
174
+ }
175
+ get align() {
176
+ return this.getPrimitiveAttribute("align");
177
+ }
178
+ set align(value) {
179
+ this.setPrimitiveAttribute("align", value);
180
+ }
181
+ }
182
+ class UIReelElement extends UILayoutElement {
183
+ static get observedAttributes() {
184
+ return ["gap", "item-width", "snap"];
185
+ }
186
+ connectedCallback() {
187
+ if (!this.hasAttribute("role")) this.setAttribute("role", "region");
188
+ if (!this.hasAttribute("tabindex")) this.setAttribute("tabindex", "0");
189
+ }
190
+ get gap() {
191
+ return this.getPrimitiveAttribute("gap");
192
+ }
193
+ set gap(value) {
194
+ this.setPrimitiveAttribute("gap", value);
195
+ }
196
+ get itemWidth() {
197
+ return this.getPrimitiveAttribute("item-width");
198
+ }
199
+ set itemWidth(value) {
200
+ this.setPrimitiveAttribute("item-width", value);
201
+ }
202
+ get snap() {
203
+ return this.getPrimitiveAttribute("snap");
204
+ }
205
+ set snap(value) {
206
+ this.setPrimitiveAttribute("snap", value);
207
+ }
208
+ }
130
209
  class UISeparatorElement extends UILayoutElement {
131
210
  static get observedAttributes() {
132
211
  return ["orientation", "role"];
@@ -167,6 +246,9 @@ if (typeof HTMLElement !== "undefined") {
167
246
  ["ui-cluster", UIClusterElement],
168
247
  ["ui-grid", UIGridElement],
169
248
  ["ui-center", UICenterElement],
249
+ ["ui-switcher", UISwitcherElement],
250
+ ["ui-sidebar", UISidebarElement],
251
+ ["ui-reel", UIReelElement],
170
252
  ["ui-separator", UISeparatorElement]
171
253
  ];
172
254
  for (const [tag, constructor] of definitions) {
package/layout.css CHANGED
@@ -1,13 +1,14 @@
1
- /* Unlayered: isolation contract (hard guarantees). */
2
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator),
3
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator) *,
4
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator) *::before,
5
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator) *::after {
1
+ /* Unlayered: box-model guarantees that remain safe for host composition. */
2
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator),
3
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator) *,
4
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator) *::before,
5
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator) *::after {
6
6
  box-sizing: border-box;
7
7
  }
8
8
 
9
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator) {
10
- all: revert;
9
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator) {
10
+ /* Reveal Looma's component layer instead of reverting past it. */
11
+ all: revert-layer;
11
12
  box-sizing: border-box;
12
13
  margin: 0;
13
14
  font-family: var(--ui-font-family-sans);
@@ -16,7 +17,7 @@
16
17
  color: var(--ui-text-primary);
17
18
  }
18
19
 
19
- :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-separator)[data-ui-inherit-typography] {
20
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator)[data-ui-inherit-typography] {
20
21
  font-family: inherit;
21
22
  font-size: inherit;
22
23
  line-height: inherit;
@@ -31,6 +32,11 @@
31
32
  }
32
33
 
33
34
  @layer components {
35
+ :where(ui-stack, ui-inline, ui-cluster, ui-grid, ui-center, ui-switcher, ui-sidebar, ui-reel, ui-separator) {
36
+ min-inline-size: 0;
37
+ max-inline-size: 100%;
38
+ }
39
+
34
40
  ui-stack {
35
41
  --ui-layout-gap: var(--ui-space-4, 1rem);
36
42
  --ui-layout-align: stretch;
@@ -79,7 +85,7 @@
79
85
  --ui-grid-min: 16rem;
80
86
  display: grid;
81
87
  gap: var(--ui-grid-gap);
82
- grid-template-columns: repeat(auto-fit, minmax(var(--ui-grid-min), 1fr));
88
+ grid-template-columns: repeat(auto-fit, minmax(min(var(--ui-grid-min), 100%), 1fr));
83
89
  }
84
90
 
85
91
  ui-grid[gap="xs"] { --ui-grid-gap: var(--ui-space-2, 0.5rem); }
@@ -94,6 +100,7 @@
94
100
  --ui-center-measure: 65ch;
95
101
  --ui-center-gutters: var(--ui-space-4, 1rem);
96
102
  display: block;
103
+ inline-size: 100%;
97
104
  max-inline-size: var(--ui-center-measure);
98
105
  margin-inline: auto;
99
106
  padding-inline: var(--ui-center-gutters);
@@ -105,6 +112,103 @@
105
112
  ui-center[gutters="m"] { --ui-center-gutters: var(--ui-space-4, 1rem); }
106
113
  ui-center[gutters="l"] { --ui-center-gutters: var(--ui-space-5, 1.5rem); }
107
114
 
115
+ ui-switcher {
116
+ --ui-switcher-gap: var(--ui-space-4, 1rem);
117
+ --ui-switcher-threshold: 30rem;
118
+ --ui-switcher-align: stretch;
119
+ display: flex;
120
+ flex-wrap: wrap;
121
+ gap: var(--ui-switcher-gap);
122
+ align-items: var(--ui-switcher-align);
123
+ }
124
+
125
+ ui-switcher > * {
126
+ min-inline-size: 0;
127
+ flex-grow: 1;
128
+ flex-basis: calc((var(--ui-switcher-threshold) - 100%) * 999);
129
+ }
130
+
131
+ ui-switcher[gap="xs"] { --ui-switcher-gap: var(--ui-space-2, 0.5rem); }
132
+ ui-switcher[gap="s"] { --ui-switcher-gap: var(--ui-space-3, 0.75rem); }
133
+ ui-switcher[gap="m"] { --ui-switcher-gap: var(--ui-space-4, 1rem); }
134
+ ui-switcher[gap="l"] { --ui-switcher-gap: var(--ui-space-5, 1.5rem); }
135
+ ui-switcher[threshold="xs"] { --ui-switcher-threshold: 20rem; }
136
+ ui-switcher[threshold="sm"] { --ui-switcher-threshold: 30rem; }
137
+ ui-switcher[threshold="md"] { --ui-switcher-threshold: 45rem; }
138
+ ui-switcher[threshold="lg"] { --ui-switcher-threshold: 60rem; }
139
+ ui-switcher[align="start"] { --ui-switcher-align: flex-start; }
140
+ ui-switcher[align="center"] { --ui-switcher-align: center; }
141
+ ui-switcher[align="end"] { --ui-switcher-align: flex-end; }
142
+
143
+ ui-sidebar {
144
+ --ui-sidebar-gap: var(--ui-space-4, 1rem);
145
+ --ui-sidebar-width: 18rem;
146
+ --ui-sidebar-content-min: 50%;
147
+ --ui-sidebar-align: stretch;
148
+ display: flex;
149
+ flex-wrap: wrap;
150
+ gap: var(--ui-sidebar-gap);
151
+ align-items: var(--ui-sidebar-align);
152
+ }
153
+
154
+ ui-sidebar > * { min-inline-size: 0; }
155
+ ui-sidebar > :first-child {
156
+ flex-basis: var(--ui-sidebar-width);
157
+ flex-grow: 1;
158
+ }
159
+ ui-sidebar > :last-child {
160
+ flex-basis: 0;
161
+ flex-grow: 999;
162
+ min-inline-size: min(var(--ui-sidebar-content-min), 100%);
163
+ }
164
+ ui-sidebar[side="end"] > :first-child {
165
+ flex-basis: 0;
166
+ flex-grow: 999;
167
+ min-inline-size: min(var(--ui-sidebar-content-min), 100%);
168
+ }
169
+ ui-sidebar[side="end"] > :last-child {
170
+ flex-basis: var(--ui-sidebar-width);
171
+ flex-grow: 1;
172
+ min-inline-size: 0;
173
+ }
174
+ ui-sidebar[gap="xs"] { --ui-sidebar-gap: var(--ui-space-2, 0.5rem); }
175
+ ui-sidebar[gap="s"] { --ui-sidebar-gap: var(--ui-space-3, 0.75rem); }
176
+ ui-sidebar[gap="m"] { --ui-sidebar-gap: var(--ui-space-4, 1rem); }
177
+ ui-sidebar[gap="l"] { --ui-sidebar-gap: var(--ui-space-5, 1.5rem); }
178
+ ui-sidebar[width="narrow"] { --ui-sidebar-width: 14rem; }
179
+ ui-sidebar[width="wide"] { --ui-sidebar-width: 24rem; }
180
+ ui-sidebar[align="start"] { --ui-sidebar-align: flex-start; }
181
+ ui-sidebar[align="center"] { --ui-sidebar-align: center; }
182
+ ui-sidebar[align="end"] { --ui-sidebar-align: flex-end; }
183
+
184
+ ui-reel {
185
+ --ui-reel-gap: var(--ui-space-4, 1rem);
186
+ --ui-reel-item-width: auto;
187
+ display: flex;
188
+ inline-size: 100%;
189
+ gap: var(--ui-reel-gap);
190
+ overflow-x: auto;
191
+ overflow-y: hidden;
192
+ overscroll-behavior-inline: contain;
193
+ -webkit-overflow-scrolling: touch;
194
+ }
195
+
196
+ ui-reel > * {
197
+ min-inline-size: 0;
198
+ flex: 0 0 var(--ui-reel-item-width);
199
+ }
200
+ ui-reel[gap="xs"] { --ui-reel-gap: var(--ui-space-2, 0.5rem); }
201
+ ui-reel[gap="s"] { --ui-reel-gap: var(--ui-space-3, 0.75rem); }
202
+ ui-reel[gap="m"] { --ui-reel-gap: var(--ui-space-4, 1rem); }
203
+ ui-reel[gap="l"] { --ui-reel-gap: var(--ui-space-5, 1.5rem); }
204
+ ui-reel[item-width="sm"] { --ui-reel-item-width: 12rem; }
205
+ ui-reel[item-width="md"] { --ui-reel-item-width: 16rem; }
206
+ ui-reel[item-width="lg"] { --ui-reel-item-width: 20rem; }
207
+ ui-reel[snap="start"],
208
+ ui-reel[snap="center"] { scroll-snap-type: inline mandatory; }
209
+ ui-reel[snap="start"] > * { scroll-snap-align: start; }
210
+ ui-reel[snap="center"] > * { scroll-snap-align: center; }
211
+
108
212
  ui-separator {
109
213
  --ui-separator-color: var(--ui-border-default, #d0d5dd);
110
214
  --ui-separator-space: var(--ui-space-4, 1rem);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@threadlabs/looma",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "type": "module",
5
5
  "description": "Looma web components, layout primitives, editor UI, and supported Vue adapters.",
6
6
  "license": "MIT",
package/styles.css CHANGED
@@ -1,4 +1,4 @@
1
- /* Unlayered: isolation contract (hard guarantees). Layered rules lose to unlayered page CSS. */
1
+ /* Unlayered: box-model guarantees. Later page CSS can still compose component hosts. */
2
2
  :where(
3
3
  ui-button,
4
4
  ui-input,
@@ -107,7 +107,8 @@
107
107
  ui-avatar,
108
108
  ui-avatar-group
109
109
  ) {
110
- all: revert;
110
+ /* Reveal Looma's component layer instead of reverting past it. */
111
+ all: revert-layer;
111
112
  box-sizing: border-box;
112
113
  margin: 0;
113
114
  font-family: var(--ui-font-family-sans);
@@ -513,11 +514,11 @@
513
514
  }
514
515
 
515
516
  /* Dialog: hidden when closed so multiple instances don’t stack in layout */
516
- ui-dialog:not([open]) {
517
+ ui-dialog:not([data-open]) {
517
518
  display: none;
518
519
  }
519
520
 
520
- ui-dialog[open] {
521
+ ui-dialog[data-open] {
521
522
  display: block;
522
523
  }
523
524
 
package/vue/index.d.ts CHANGED
@@ -47,6 +47,15 @@ declare const Grid: vue.DefineComponent<{}, () => vue.VNode<vue.RendererNode, vu
47
47
  declare const Center: vue.DefineComponent<{}, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
48
48
  [key: string]: any;
49
49
  }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
50
+ declare const Switcher: vue.DefineComponent<{}, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
51
+ [key: string]: any;
52
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
53
+ declare const Sidebar: vue.DefineComponent<{}, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
54
+ [key: string]: any;
55
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
56
+ declare const Reel: vue.DefineComponent<{}, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
57
+ [key: string]: any;
58
+ }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
50
59
  declare const Separator: vue.DefineComponent<{}, () => vue.VNode<vue.RendererNode, vue.RendererElement, {
51
60
  [key: string]: any;
52
61
  }>, {}, {}, {}, vue.ComponentOptionsMixin, vue.ComponentOptionsMixin, {}, string, vue.PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, vue.ComponentProvideOptions, true, {}, any>;
@@ -134,6 +143,9 @@ declare const ADAPTER_COMPONENT_TAG_MAP: {
134
143
  readonly Cluster: "ui-cluster";
135
144
  readonly Grid: "ui-grid";
136
145
  readonly Center: "ui-center";
146
+ readonly Switcher: "ui-switcher";
147
+ readonly Sidebar: "ui-sidebar";
148
+ readonly Reel: "ui-reel";
137
149
  readonly Separator: "ui-separator";
138
150
  readonly Disclosure: "ui-disclosure";
139
151
  readonly Tabs: "ui-tabs";
@@ -164,4 +176,4 @@ declare const ADAPTER_COMPONENT_TAG_MAP: {
164
176
  };
165
177
  declare const VUE_ADAPTER_NOTE = "Thin adapter only: attrs and slots pass through to custom elements and DOM events map to typed callbacks.";
166
178
 
167
- export { ADAPTER_COMPONENT_TAG_MAP, Avatar, AvatarGroup, Badge, Button, Center, Checkbox, Cluster, ContextMenu, Dialog, Disclosure, FloatingActionButton, FormField, Grid, IconButton, Inline, Input, Menu, MenuItem, Popover, Radio, RadioGroup, SearchResultRow, SearchShell, Select, Separator, Stack, Switch, Tabs, Textarea, ToastRegion, Tooltip, TopBar, VUE_ADAPTER_NOTE, type VueAdapterEventMap };
179
+ export { ADAPTER_COMPONENT_TAG_MAP, Avatar, AvatarGroup, Badge, Button, Center, Checkbox, Cluster, ContextMenu, Dialog, Disclosure, FloatingActionButton, FormField, Grid, IconButton, Inline, Input, Menu, MenuItem, Popover, Radio, RadioGroup, Reel, SearchResultRow, SearchShell, Select, Separator, Sidebar, Stack, Switch, Switcher, Tabs, Textarea, ToastRegion, Tooltip, TopBar, VUE_ADAPTER_NOTE, type VueAdapterEventMap };