@primitiv-ui/web 0.0.0-stage → 0.1.43

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Simon Revill
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,92 @@
1
- # Temporary Holding Version
1
+ # @primitiv-ui/web
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Primitiv's headless components as **standard custom elements**: light DOM, no
4
+ framework and no runtime dependencies beyond
5
+ [`@primitiv-ui/core`](../core/README.md). They work in a plain HTML page, any
6
+ server-rendered stack (HTMX, Rails, Django, Laravel, Spring …), and inside
7
+ React, Vue, Angular or any other framework.
8
+
9
+ > **Status: publish-ready, first release pending.** Tabs is the first
10
+ > component. See [RFC 0033](../../docs/rfcs/0033-web-components.md) for the
11
+ > design.
12
+
13
+ ## Use it
14
+
15
+ **No build step** — one script tag per component defines that component's
16
+ elements and nothing else:
17
+
18
+ ```html
19
+ <script type="module" src="https://cdn.jsdelivr.net/npm/@primitiv-ui/web@<version>/dist/cdn/tabs.js"></script>
20
+
21
+ <primitiv-tabs value="overview">
22
+ <primitiv-tabs-list label="Account sections">
23
+ <primitiv-tabs-trigger value="overview"><button type="button">Overview</button></primitiv-tabs-trigger>
24
+ <primitiv-tabs-trigger value="billing"><button type="button">Billing</button></primitiv-tabs-trigger>
25
+ </primitiv-tabs-list>
26
+ <primitiv-tabs-content value="overview">…</primitiv-tabs-content>
27
+ <primitiv-tabs-content value="billing" hidden>…</primitiv-tabs-content>
28
+ </primitiv-tabs>
29
+ ```
30
+
31
+ **With a bundler** — import a `define` entry once, anywhere:
32
+
33
+ ```ts
34
+ import "@primitiv-ui/web/define/tabs"; // one component's elements
35
+ import "@primitiv-ui/web/define"; // or every element
36
+ ```
37
+
38
+ Each `dist/cdn/<component>.js` imports the code components share from
39
+ `dist/cdn/chunks/` by a relative URL, so a page that loads two components
40
+ downloads it once. `dist/primitiv-web.js` is the alternative: every element in
41
+ one file. Per-component files ship from 0.1.43.
42
+
43
+ The main entry (`@primitiv-ui/web`, `/tabs`) exports the classes and
44
+ `defineTabs(registry?)` with **no side effects**.
45
+
46
+ **Render `hidden` on inactive panels yourself.** Until the module loads, CSS
47
+ cannot tell which panel is active, so markup that omits it shows every panel.
48
+
49
+ **Listen with `primitiv-tabs-change`** (bubbles, cancelable, `detail: { value,
50
+ index }`) — call `preventDefault()` to veto a change — and `primitiv-tabs-show`
51
+ on a panel as it becomes active, for lazy loading.
52
+
53
+ **TypeScript** — opt into the tag map so DOM queries return the element classes:
54
+ `import type {} from "@primitiv-ui/web/tags"` (npm only).
55
+
56
+ **React 19 JSX** — `import type {} from "@primitiv-ui/web/react"` types the
57
+ tags, their attributes and the raw `onprimitiv-tabs-change` handler (npm only).
58
+ React 19 passes a custom element's event prop to `addEventListener` exactly as
59
+ written, which is why the prop reads that way; most React projects want
60
+ `@primitiv-ui/react`, whose `onValueChange` is the idiomatic name.
61
+
62
+ **Vue 3 templates** — `import type {} from "@primitiv-ui/web/vue"` lets
63
+ `vue-tsc` check each tag's attributes and its `@primitiv-tabs-change` handler
64
+ (npm only). Also tell Vue's compiler the tags are custom elements:
65
+ `compilerOptions.isCustomElement: (tag) => tag.startsWith("primitiv-")`.
66
+
67
+ **Svelte 5 templates** — `import type {} from "@primitiv-ui/web/svelte"` lets
68
+ `svelte-check` check each tag's attributes and its `onprimitiv-tabs-change`
69
+ handler (npm only). Svelte needs no other setup: it renders unknown tags as
70
+ custom elements already.
71
+
72
+ **Angular** — add `CUSTOM_ELEMENTS_SCHEMA` to the component's `schemas`, bind
73
+ the value as a property (`[value]="value()"`), the other options as attributes
74
+ (`[attr.activation-mode]="mode"`), and listen with
75
+ `(primitiv-tabs-change)="onChange($event)"`. There is no typing entry: Angular
76
+ types a custom element's `$event` as `Event`, so cast it to
77
+ `CustomEvent<{ value: string; index: number }>` in the handler.
78
+
79
+ **Tooling** — `dist/custom-elements.json` is a Custom Elements Manifest, listed
80
+ as `customElements` in `package.json`, for editor completion and Storybook.
81
+
82
+ The elements write no `class` and no `style`. For the registry look, apply the
83
+ `primitiv-tabs*` classes from the registry stylesheet to your markup.
84
+
85
+ ## Layers
86
+
87
+ - **Controllers** (`TabsController`) hold a component's DOM behaviour —
88
+ listeners, focus, the ordered collection of parts — and attach to whatever
89
+ elements register with them. They never own state; their host does.
90
+ - **Element hosts** (`<primitiv-tabs>` …) are the public face: they keep state
91
+ in reflected attributes and write the ARIA. The React adapter in
92
+ `@primitiv-ui/react` is a second host over the same controllers.
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The single-file browser bundle (`dist/primitiv-web.js`, core inlined) for
3
+ * pages with no build step:
4
+ *
5
+ * ```html
6
+ * <script type="module" src="https://cdn.jsdelivr.net/npm/@primitiv-ui/web@<version>/dist/primitiv-web.js"></script>
7
+ * ```
8
+ *
9
+ * Loading it defines every element and exports every class. To load one
10
+ * component only, use its `dist/cdn/<component>.js` (scripts/build-cdn.mjs).
11
+ */
12
+ export * from "./index.js";
13
+ import "./define/index.js";
package/dist/bundle.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The single-file browser bundle (`dist/primitiv-web.js`, core inlined) for
3
+ * pages with no build step:
4
+ *
5
+ * ```html
6
+ * <script type="module" src="https://cdn.jsdelivr.net/npm/@primitiv-ui/web@<version>/dist/primitiv-web.js"></script>
7
+ * ```
8
+ *
9
+ * Loading it defines every element and exports every class. To load one
10
+ * component only, use its `dist/cdn/<component>.js` (scripts/build-cdn.mjs).
11
+ */
12
+ export * from "./index.js";
13
+ import "./define/index.js";
@@ -0,0 +1 @@
1
+ function b(i,t,e){return`${i}-${t}-${e}`}function O({orientation:i,dir:t,homeEnd:e=!1,activate:r=!1}){let o={};if(i==="horizontal"||i==="both"){let l=t==="rtl"?"ArrowLeft":"ArrowRight",d=t==="rtl"?"ArrowRight":"ArrowLeft";o[l]="next",o[d]="prev"}return(i==="vertical"||i==="both")&&(o.ArrowDown="next",o.ArrowUp="prev"),e&&(o.Home="first",o.End="last"),r&&(o.Enter="activate",o[" "]="activate"),o}function K({action:i,navigable:t,currentKey:e}){let r=t.length;if(r===0)return null;switch(i){case"activate":return{target:e};case"first":return{target:t[0]};case"last":return{target:t[r-1]};case void 0:return null;case"next":case"prev":{let o=t.indexOf(e);if(o===-1)return null;let l=i==="next"?1:r-1;return{target:t[(o+l)%r]}}}}function h(i){return i.active??i.values[0]}function g(i,t){return i.disabled.has(t)||i.active===t?null:t}function T(i,t,e){let r=O({orientation:i.orientation,dir:i.dir,homeEnd:!0,activate:!0})[e],o=K({action:r,navigable:i.values,currentKey:t});if(!o)return null;let l=o.target,d=i.activationMode==="automatic"||r==="activate";return{focus:l,activate:d?g(i,l):null}}var p=class{#o;#i;#t=new Map;#e=null;constructor(t,e){this.#o=t,this.#i=e}registerTrigger(t,e,r={}){this.#t.set(e,{value:t,disabled:r.disabled??!1})}setTriggers(t){this.#t.clear();for(let{value:e,element:r,disabled:o}of t)this.registerTrigger(e,r,{disabled:o})}unregisterTrigger(t){this.#t.delete(t)}connect(){if(this.#e)return;this.#e=new AbortController;let{signal:t}=this.#e;this.#o.addEventListener("click",e=>this.#l(e),{signal:t}),this.#o.addEventListener("keydown",e=>this.#s(e),{signal:t})}disconnect(){this.#e?.abort(),this.#e=null}#r(){return[...this.#t].sort(([t],[e])=>t.compareDocumentPosition(e)&Node.DOCUMENT_POSITION_FOLLOWING?-1:1)}#a(){let t=new Set;for(let e of this.#t.values())e.disabled&&t.add(e.value);return t}#l(t){let e=this.#n(t.target);if(!e)return;let{active:r}=this.#i.state(),o=g({disabled:this.#a(),active:r},e.value);if(o!==null){let l=this.#r().map(([,d])=>d.value);this.#i.activate(o,l.indexOf(o))}}#s(t){let e=this.#n(t.target);if(!e)return;let{active:r,orientation:o,dir:l,activationMode:d}=this.#i.state(),v=this.#r(),a=v.map(([,c])=>c.value),n=T({values:a,disabled:this.#a(),active:r,orientation:o,dir:l,activationMode:d},e.value,t.key);n&&(t.preventDefault(),n.activate!==null&&this.#i.activate(n.activate,a.indexOf(n.activate)),v[a.indexOf(n.focus)][0].focus())}#n(t){for(let[e,r]of this.#t)if(e.contains(t))return r}};var f=globalThis.HTMLElement??class{},m="primitiv-tabs",H="primitiv-tabs-list",E="primitiv-tabs-trigger",C="primitiv-tabs-content",S=0,L=new WeakSet;function I(i){let t=i.getAttribute("value");return i.childElementCount===1&&t!==null?{tab:i.firstElementChild,value:t}:(L.has(i)||(L.add(i),console.error(`<${E}> needs a value and exactly one element child (a <button>, an <a href> or a router link) to decorate.`,i)),null)}function s(i,t,e){i.getAttribute(t)!==e&&(e===null?i.removeAttribute(t):i.setAttribute(t,e))}var y=class extends f{#o;#i;#t=!1;#e=new p(this,this.#a());#r=new MutationObserver(()=>this.#c());connectedCallback(){this.#e.connect(),this.#r.observe(this,{subtree:!0,childList:!0,attributes:!0,attributeFilter:["value","disabled","label","orientation"]}),this.#c()}disconnectedCallback(){this.#e.disconnect(),this.#r.disconnect()}get value(){return this.getAttribute("value")??void 0}set value(t){this.setAttribute("value",t)}#a(){return{state:()=>({active:this.value,orientation:this.#s(),dir:this.matches(":dir(rtl)")?"rtl":"ltr",activationMode:this.#l()}),activate:(t,e)=>{let r=new CustomEvent("primitiv-tabs-change",{bubbles:!0,cancelable:!0,detail:{value:t,index:e}});this.dispatchEvent(r)&&(this.value=t)}}}#l(){let t=this.getAttribute("activation-mode");return t==="manual"?t:"automatic"}#s(){return this.getAttribute("orientation")==="vertical"?"vertical":"horizontal"}#n(t){return[...this.querySelectorAll(t)].filter(e=>e.closest(m)===this)}#d(){return this.id||(this.#o??=`${m}-${++S}`)}#c(){let t=this.#s(),e=this.value,r=this.#d();s(this,"data-orientation",t);for(let a of this.#n(H)){s(a,"role","tablist"),s(a,"aria-orientation",t),s(a,"data-orientation",t);let n=a.getAttribute("label");n!==null&&s(a,"aria-label",n)}let o=new Map;for(let a of this.#n(C)){let n=a.getAttribute("value");n!==null&&o.set(n,a)}let l=this.#n(E).flatMap(a=>{let n=I(a);return n?[{trigger:a,...n}]:[]}),d=h({values:l.map(a=>a.value),active:e});this.#e.setTriggers(l.map(({trigger:a,tab:n,value:c})=>({value:c,element:n,disabled:a.hasAttribute("disabled")})));for(let{trigger:a,tab:n,value:c}of l){let u=o.get(c),R=c===e,w=a.hasAttribute("disabled");n.id||(n.id=b(r,"trigger",c)),u&&!u.id&&(u.id=b(r,"panel",c)),s(n,"role","tab"),s(n,"aria-selected",String(R)),s(n,"aria-controls",u?u.id:null),s(n,"tabindex",c===d?"0":"-1"),s(n,"aria-disabled",w?"true":null),s(n,"data-disabled",w?"":null),s(n,"data-state",R?"active":"inactive"),s(n,"data-orientation",t),u&&s(u,"aria-labelledby",n.id)}for(let[a,n]of o){let c=a===e;s(n,"role","tabpanel"),s(n,"tabindex","0"),s(n,"hidden",c?null:""),s(n,"data-state",c?"active":"inactive"),s(n,"data-orientation",t)}let v=o.get(e);this.#t&&e!==this.#i&&v&&v.dispatchEvent(new CustomEvent("primitiv-tabs-show",{bubbles:!0})),this.#i=e,this.#t=!0}},x=class extends f{},A=class extends f{},M=class extends f{};function k(i=globalThis.customElements){if(!i)return;let t=[[m,y],[H,x],[E,A],[C,M]];for(let[e,r]of t)i.get(e)||i.define(e,r)}k();
@@ -0,0 +1,314 @@
1
+ {
2
+ "schemaVersion": "1.0.0",
3
+ "readme": "",
4
+ "modules": [
5
+ {
6
+ "kind": "javascript-module",
7
+ "path": "src/tabs/elements.ts",
8
+ "declarations": [
9
+ {
10
+ "kind": "class",
11
+ "description": "`<primitiv-tabs>` — the state owner of a WAI-ARIA tab set.\n\nThe root finds its own parts, scoped with `closest()` so a tab set nested in a\npanel keeps its own, and reconciles their ARIA from its reflected state. It\nnever caches the parts, so markup that arrives later is picked up on the next\nreconcile. One `MutationObserver` is the only trigger after connect: it sees\nparts arriving and leaving, and every attribute the root reads, including the\nroot's own `value` and `orientation`, and it already delivers a task's changes\nas one callback, so no further batching is needed. `activation-mode` is read\nlive at each key press, so a change to it needs no reconcile.",
12
+ "name": "PrimitivTabsElement",
13
+ "members": [
14
+ {
15
+ "kind": "field",
16
+ "name": "#generatedId",
17
+ "privacy": "private",
18
+ "type": {
19
+ "text": "string | undefined"
20
+ }
21
+ },
22
+ {
23
+ "kind": "field",
24
+ "name": "#shown",
25
+ "privacy": "private",
26
+ "type": {
27
+ "text": "string | undefined"
28
+ },
29
+ "description": "The value of the panel last shown, so a change fires primitiv-tabs-show."
30
+ },
31
+ {
32
+ "kind": "field",
33
+ "name": "#rendered",
34
+ "privacy": "private",
35
+ "type": {
36
+ "text": "boolean"
37
+ },
38
+ "default": "false"
39
+ },
40
+ {
41
+ "kind": "field",
42
+ "name": "#controller",
43
+ "privacy": "private",
44
+ "readonly": true,
45
+ "default": "new TabsController(this, this.#host())"
46
+ },
47
+ {
48
+ "kind": "field",
49
+ "name": "#observer",
50
+ "privacy": "private",
51
+ "readonly": true,
52
+ "default": "new MutationObserver(() => this.#reconcile())",
53
+ "description": "Watches the subtree for parts arriving, leaving, or changing the attributes\nthe root reads. The root's own writes (role, aria-*, ids, data-*) are not in\nthe filter, so reconciling never re-triggers itself."
54
+ },
55
+ {
56
+ "kind": "field",
57
+ "name": "value",
58
+ "type": {
59
+ "text": "string | undefined"
60
+ },
61
+ "description": "The active tab's value, reflected as the `value` attribute."
62
+ },
63
+ {
64
+ "kind": "method",
65
+ "name": "#host",
66
+ "privacy": "private",
67
+ "return": {
68
+ "type": {
69
+ "text": "TabsControllerHost"
70
+ }
71
+ },
72
+ "description": "The controller's view of this element. State lives in reflected attributes;\nan activation is announced first, as a cancelable event, so a listener can\nveto it — the elements' equivalent of React's controlled mode (D7)."
73
+ },
74
+ {
75
+ "kind": "method",
76
+ "name": "#activationMode",
77
+ "privacy": "private",
78
+ "return": {
79
+ "type": {
80
+ "text": "TabsActivationMode"
81
+ }
82
+ }
83
+ },
84
+ {
85
+ "kind": "method",
86
+ "name": "#orientation",
87
+ "privacy": "private",
88
+ "return": {
89
+ "type": {
90
+ "text": "TabsOrientation"
91
+ }
92
+ }
93
+ },
94
+ {
95
+ "kind": "method",
96
+ "name": "#parts",
97
+ "privacy": "private",
98
+ "return": {
99
+ "type": {
100
+ "text": "HTMLElement[]"
101
+ }
102
+ },
103
+ "parameters": [
104
+ {
105
+ "name": "selector",
106
+ "type": {
107
+ "text": "string"
108
+ }
109
+ }
110
+ ],
111
+ "description": "Parts of this tab set only, never those of a nested one."
112
+ },
113
+ {
114
+ "kind": "method",
115
+ "name": "#rootId",
116
+ "privacy": "private",
117
+ "return": {
118
+ "type": {
119
+ "text": "string"
120
+ }
121
+ }
122
+ },
123
+ {
124
+ "kind": "method",
125
+ "name": "#reconcile",
126
+ "privacy": "private",
127
+ "return": {
128
+ "type": {
129
+ "text": "void"
130
+ }
131
+ }
132
+ }
133
+ ],
134
+ "events": [
135
+ {
136
+ "type": {
137
+ "text": "CustomEvent<{ value: string; index: number }>"
138
+ },
139
+ "description": "Bubbles, cancelable, fired before a user-driven change is applied. Call `preventDefault()` to veto it.",
140
+ "name": "primitiv-tabs-change"
141
+ }
142
+ ],
143
+ "attributes": [
144
+ {
145
+ "type": {
146
+ "text": "string"
147
+ },
148
+ "description": "The active tab's value. Reflected: it moves as the user switches tabs, so a server re-render or a history snapshot sees the live selection.",
149
+ "name": "value"
150
+ },
151
+ {
152
+ "type": {
153
+ "text": "\"horizontal\" | \"vertical\""
154
+ },
155
+ "description": "Layout axis, which picks the arrow-key pair. Defaults to `horizontal`.",
156
+ "name": "orientation"
157
+ },
158
+ {
159
+ "type": {
160
+ "text": "\"automatic\" | \"manual\""
161
+ },
162
+ "description": "`automatic` activates a tab as focus arrives; `manual` waits for Enter or Space. Defaults to `automatic`.",
163
+ "name": "activation-mode"
164
+ }
165
+ ],
166
+ "superclass": {
167
+ "name": "ElementBase",
168
+ "module": "src/tabs/elements.ts"
169
+ },
170
+ "tagName": "primitiv-tabs",
171
+ "customElement": true,
172
+ "summary": "The state owner of a WAI-ARIA tab set."
173
+ },
174
+ {
175
+ "kind": "class",
176
+ "description": "`<primitiv-tabs-list>` — the tablist. Structural: the root writes its ARIA.",
177
+ "name": "PrimitivTabsListElement",
178
+ "attributes": [
179
+ {
180
+ "type": {
181
+ "text": "string"
182
+ },
183
+ "description": "The tablist's accessible name. Give this or `aria-labelledby`.",
184
+ "name": "label"
185
+ }
186
+ ],
187
+ "superclass": {
188
+ "name": "ElementBase",
189
+ "module": "src/tabs/elements.ts"
190
+ },
191
+ "tagName": "primitiv-tabs-list",
192
+ "customElement": true
193
+ },
194
+ {
195
+ "kind": "class",
196
+ "description": "`<primitiv-tabs-trigger>` — an interactive part. It decorates exactly one\nchild the consumer writes (a `<button>`, an `<a href>`, a router link), which\nreceives the tab role, so the rendered DOM matches React's `<button role=\"tab\">`\n(RFC 0033 D24).",
197
+ "name": "PrimitivTabsTriggerElement",
198
+ "attributes": [
199
+ {
200
+ "type": {
201
+ "text": "string"
202
+ },
203
+ "description": "The tab's value, pairing it with the panel of the same value.",
204
+ "name": "value"
205
+ },
206
+ {
207
+ "type": {
208
+ "text": "boolean"
209
+ },
210
+ "description": "Marks the tab disabled: arrow keys still land on it, but it never activates.",
211
+ "name": "disabled"
212
+ }
213
+ ],
214
+ "superclass": {
215
+ "name": "ElementBase",
216
+ "module": "src/tabs/elements.ts"
217
+ },
218
+ "tagName": "primitiv-tabs-trigger",
219
+ "customElement": true
220
+ },
221
+ {
222
+ "kind": "class",
223
+ "description": "`<primitiv-tabs-content>` — a tab panel. Structural: the root writes its ARIA.",
224
+ "name": "PrimitivTabsContentElement",
225
+ "events": [
226
+ {
227
+ "type": {
228
+ "text": "CustomEvent"
229
+ },
230
+ "description": "Bubbles from the panel as it becomes active (not on first render), so a lazy panel can fetch its content.",
231
+ "name": "primitiv-tabs-show"
232
+ }
233
+ ],
234
+ "attributes": [
235
+ {
236
+ "type": {
237
+ "text": "string"
238
+ },
239
+ "description": "The panel's value, pairing it with the tab of the same value.",
240
+ "name": "value"
241
+ }
242
+ ],
243
+ "superclass": {
244
+ "name": "ElementBase",
245
+ "module": "src/tabs/elements.ts"
246
+ },
247
+ "tagName": "primitiv-tabs-content",
248
+ "customElement": true
249
+ },
250
+ {
251
+ "kind": "function",
252
+ "name": "defineTabs",
253
+ "return": {
254
+ "type": {
255
+ "text": "void"
256
+ }
257
+ },
258
+ "parameters": [
259
+ {
260
+ "name": "registry",
261
+ "default": "globalThis.customElements",
262
+ "type": {
263
+ "text": "ElementRegistry | undefined"
264
+ }
265
+ }
266
+ ],
267
+ "description": "Define the four Tabs elements on `registry` (the global `customElements` by\ndefault, so a scoped registry can be passed when browsers support one). Safe\nto call more than once, and a no-op where there is no registry (a server\nrender)."
268
+ }
269
+ ],
270
+ "exports": [
271
+ {
272
+ "kind": "js",
273
+ "name": "PrimitivTabsElement",
274
+ "declaration": {
275
+ "name": "PrimitivTabsElement",
276
+ "module": "src/tabs/elements.ts"
277
+ }
278
+ },
279
+ {
280
+ "kind": "js",
281
+ "name": "PrimitivTabsListElement",
282
+ "declaration": {
283
+ "name": "PrimitivTabsListElement",
284
+ "module": "src/tabs/elements.ts"
285
+ }
286
+ },
287
+ {
288
+ "kind": "js",
289
+ "name": "PrimitivTabsTriggerElement",
290
+ "declaration": {
291
+ "name": "PrimitivTabsTriggerElement",
292
+ "module": "src/tabs/elements.ts"
293
+ }
294
+ },
295
+ {
296
+ "kind": "js",
297
+ "name": "PrimitivTabsContentElement",
298
+ "declaration": {
299
+ "name": "PrimitivTabsContentElement",
300
+ "module": "src/tabs/elements.ts"
301
+ }
302
+ },
303
+ {
304
+ "kind": "js",
305
+ "name": "defineTabs",
306
+ "declaration": {
307
+ "name": "defineTabs",
308
+ "module": "src/tabs/elements.ts"
309
+ }
310
+ }
311
+ ]
312
+ }
313
+ ]
314
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Side-effect entry: importing this module defines every Primitiv element.
3
+ * Import `@primitiv-ui/web/define/<component>` instead to define only one.
4
+ */
5
+ import "./tabs.js";
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Side-effect entry: importing this module defines every Primitiv element.
3
+ * Import `@primitiv-ui/web/define/<component>` instead to define only one.
4
+ */
5
+ import "./tabs.js";
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Side-effect entry: importing this module defines the four Tabs elements
3
+ * (`<primitiv-tabs>`, `-list`, `-trigger`, `-content`) on the global
4
+ * `customElements` registry.
5
+ *
6
+ * ```html
7
+ * <script type="module">import "@primitiv-ui/web/define/tabs";</script>
8
+ * ```
9
+ */
10
+ import { defineTabs } from "../tabs/elements.js";
11
+ defineTabs();
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The elements' event types, for the framework typing entries to share. It
3
+ * imports no framework, so each entry pulls in only its own.
4
+ */
5
+ /** The `primitiv-tabs-change` event: bubbles, cancelable, fired before the change applies. */
6
+ export type PrimitivTabsChangeEvent = CustomEvent<{
7
+ value: string;
8
+ index: number;
9
+ }>;
@@ -0,0 +1,5 @@
1
+ /**
2
+ * The elements' event types, for the framework typing entries to share. It
3
+ * imports no framework, so each entry pulls in only its own.
4
+ */
5
+ export {};
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Opt-in React 19 JSX typings for the raw elements, for a React project that
3
+ * uses `@primitiv-ui/web` directly rather than `@primitiv-ui/react`:
4
+ *
5
+ * ```tsx
6
+ * import type {} from "@primitiv-ui/web/react";
7
+ *
8
+ * <primitiv-tabs value={value} onprimitiv-tabs-change={(e) => setValue(e.detail.value)}>
9
+ * ```
10
+ *
11
+ * React 19 passes a custom element's `on…` prop to `addEventListener` with the
12
+ * name exactly as written, so the change event's prop is
13
+ * `onprimitiv-tabs-change` (RFC 0033 §5.6.3, D29). Most React projects want
14
+ * `@primitiv-ui/react` instead, whose `onValueChange` / `onChange` are the
15
+ * idiomatic names.
16
+ *
17
+ * npm-only, like `@primitiv-ui/web/tags`: it augments the `react` module,
18
+ * which JSR does not allow a published module to do.
19
+ */
20
+ import type { DetailedHTMLProps, HTMLAttributes } from "react";
21
+ import type { PrimitivTabsContentElement, PrimitivTabsElement, PrimitivTabsListElement, PrimitivTabsTriggerElement } from "../tabs/elements.js";
22
+ import type { PrimitivTabsChangeEvent } from "./events.js";
23
+ /** React's own props for an element, plus `class`, which React 19 passes to custom elements. */
24
+ type ElementProps<E extends HTMLElement> = DetailedHTMLProps<HTMLAttributes<E>, E> & {
25
+ class?: string;
26
+ };
27
+ export type { PrimitivTabsChangeEvent };
28
+ declare module "react" {
29
+ namespace JSX {
30
+ interface IntrinsicElements {
31
+ "primitiv-tabs": ElementProps<PrimitivTabsElement> & {
32
+ value?: string;
33
+ orientation?: "horizontal" | "vertical";
34
+ "activation-mode"?: "automatic" | "manual";
35
+ "onprimitiv-tabs-change"?: (event: PrimitivTabsChangeEvent) => void;
36
+ };
37
+ "primitiv-tabs-list": ElementProps<PrimitivTabsListElement> & {
38
+ label?: string;
39
+ };
40
+ "primitiv-tabs-trigger": ElementProps<PrimitivTabsTriggerElement> & {
41
+ value: string;
42
+ disabled?: boolean;
43
+ };
44
+ "primitiv-tabs-content": ElementProps<PrimitivTabsContentElement> & {
45
+ value: string;
46
+ "onprimitiv-tabs-show"?: (event: CustomEvent) => void;
47
+ };
48
+ }
49
+ }
50
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Opt-in Svelte 5 template typings for the elements. With this in scope,
3
+ * `svelte-check` checks each tag's attributes and its events:
4
+ *
5
+ * ```svelte
6
+ * <script lang="ts">
7
+ * import type {} from "@primitiv-ui/web/svelte";
8
+ * </script>
9
+ * <primitiv-tabs {value} onprimitiv-tabs-change={(e) => (value = e.detail.value)}>…</primitiv-tabs>
10
+ * ```
11
+ *
12
+ * Svelte 5 treats an `on…` attribute as a listener for the event named by the
13
+ * rest of it, so the change event's attribute is `onprimitiv-tabs-change`, the
14
+ * same as React 19's (RFC 0033 §5.6.3).
15
+ *
16
+ * npm-only, like `@primitiv-ui/web/tags`: it augments `svelte/elements`, which
17
+ * JSR does not allow a published module to do.
18
+ */
19
+ import type { HTMLAttributes } from "svelte/elements";
20
+ import type { PrimitivTabsContentElement, PrimitivTabsElement, PrimitivTabsListElement, PrimitivTabsTriggerElement } from "../tabs/elements.js";
21
+ import type { PrimitivTabsChangeEvent } from "./events.js";
22
+ /** Svelte's own attributes and events for an element. */
23
+ type Attributes<E extends HTMLElement> = HTMLAttributes<E>;
24
+ declare module "svelte/elements" {
25
+ interface SvelteHTMLElements {
26
+ "primitiv-tabs": Attributes<PrimitivTabsElement> & {
27
+ value?: string;
28
+ orientation?: "horizontal" | "vertical";
29
+ "activation-mode"?: "automatic" | "manual";
30
+ "onprimitiv-tabs-change"?: (event: PrimitivTabsChangeEvent) => void;
31
+ };
32
+ "primitiv-tabs-list": Attributes<PrimitivTabsListElement> & {
33
+ label?: string;
34
+ };
35
+ "primitiv-tabs-trigger": Attributes<PrimitivTabsTriggerElement> & {
36
+ value: string;
37
+ disabled?: boolean;
38
+ };
39
+ "primitiv-tabs-content": Attributes<PrimitivTabsContentElement> & {
40
+ value: string;
41
+ "onprimitiv-tabs-show"?: (event: CustomEvent) => void;
42
+ };
43
+ }
44
+ }
45
+ export {};
@@ -0,0 +1 @@
1
+ export {};