@ziyarago/ui 0.5.0 → 0.6.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/CHANGELOG.md CHANGED
@@ -1,3 +1,9 @@
1
+ ## [0.6.0](https://github.com/ziyarago/ui/compare/v0.5.0...v0.6.0) (2026-10-21)
2
+
3
+ ### Features
4
+
5
+ * SocialAuth component with Google and Apple buttons ([398b36d](https://github.com/ziyarago/ui/commit/398b36dcc808e8f4656c09e8c12acf2e21c6084d))
6
+
1
7
  ## [0.5.0](https://github.com/ziyarago/ui/compare/v0.4.0...v0.5.0) (2026-10-21)
2
8
 
3
9
  ### Features
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  <p align="center"><a href="https://ziyara.vip"><img src="https://raw.githubusercontent.com/ziyarago/ui/main/docs/images/hero-dark.png" alt="ziyarago/ui: glass design system for Vue, Nuxt and React" width="100%"></a></p>
6
6
 
7
- Glass design system for Vue 3, Nuxt and React: 183 components, 17 page templates, OKLCH tokens, dark and light, RTL and Arabic, 16 interface languages. One framework-neutral core with thin adapters. Built for Umrah and Hajj products, usable anywhere.
7
+ Glass design system for Vue 3, Nuxt and React: 184 components, 17 page templates, OKLCH tokens, dark and light, RTL and Arabic, 16 interface languages. One framework-neutral core with thin adapters. Built for Umrah and Hajj products, usable anywhere.
8
8
 
9
9
  <table>
10
10
  <tr>
@@ -12,7 +12,7 @@ Glass design system for Vue 3, Nuxt and React: 183 components, 17 page templates
12
12
  <td width="50%"><img src="https://raw.githubusercontent.com/ziyarago/ui/main/docs/images/hero-rtl.png" alt="Arabic RTL"><br><sub>Arabic, RTL mirrored</sub></td>
13
13
  </tr>
14
14
  <tr>
15
- <td><img src="https://raw.githubusercontent.com/ziyarago/ui/main/docs/images/components.png" alt="Component catalog"><br><sub>183 components with props and live examples</sub></td>
15
+ <td><img src="https://raw.githubusercontent.com/ziyarago/ui/main/docs/images/components.png" alt="Component catalog"><br><sub>184 components with props and live examples</sub></td>
16
16
  <td><img src="https://raw.githubusercontent.com/ziyarago/ui/main/docs/images/templates.png" alt="Page templates"><br><sub>17 page templates</sub></td>
17
17
  </tr>
18
18
  <tr>
@@ -24,7 +24,7 @@ Glass design system for Vue 3, Nuxt and React: 183 components, 17 page templates
24
24
  Files:
25
25
 
26
26
  ```
27
- src/core/ components*.js, pages.js: 183 components and 17 page templates as { state, slots, render(ctx) }; no framework imports
27
+ src/core/ components*.js, pages.js: 184 components and 17 page templates as { state, slots, render(ctx) }; no framework imports
28
28
  src/vue/ Vue 3 adapter (UiButton, UiAppShell … + install(app))
29
29
  src/react/ React adapter (same names)
30
30
  src/theme.js useUiTheme(): theme · palette · dir → <html> attributes, persisted
@@ -1,8 +1,8 @@
1
1
  # @ziyarago/ui
2
2
 
3
- > ZiyaraGo UI — glass design system for Umrah and Hajj products. OKLCH tokens, two palettes, dark and light, RTL, Thmanyah. One framework-neutral core with Vue 3, Nuxt and React adapters, 183 components and 17 page templates.
3
+ > ZiyaraGo UI — glass design system for Umrah and Hajj products. OKLCH tokens, two palettes, dark and light, RTL, Thmanyah. One framework-neutral core with Vue 3, Nuxt and React adapters, 184 components and 17 page templates.
4
4
 
5
- Version 0.5.0. Docs: https://ziyara.vip . Manifest (machine readable): https://ziyara.vip/manifest.json
5
+ Version 0.6.0. Docs: https://ziyara.vip . Manifest (machine readable): https://ziyara.vip/manifest.json
6
6
 
7
7
  ## Setup
8
8
  - import { UiButton } from '@ziyarago/ui/vue'
@@ -2131,6 +2131,20 @@ Slots:
2131
2131
  Notes:
2132
2132
  - logo, footer, image, people are props in both Vue and React. The media panel is hidden below the form on narrow screens (stacks under it).
2133
2133
 
2134
+ ## UiSocialAuth (domain)
2135
+ Continue with Google and Apple buttons with an "or" divider. Place it under the sign-in form.
2136
+ Props:
2137
+ - `providers`: ('google' | 'apple')[] = "['google', 'apple']". Which buttons to show, in order.
2138
+ - `variant`: 'stack' | 'icons' = "stack". 'stack': full-width buttons with a label, one per row. 'icons': a row of square icon buttons.
2139
+ - `divider`: boolean = "true". Show the "or" line above the buttons.
2140
+ - `labels`: { google?: string; apple?: string }. Provider names inserted into "Continue with {provider}".
2141
+ - `onSelect`: (provider: 'google' | 'apple') => void. Called with the clicked provider. Start your OAuth flow here.
2142
+ - `size`: 'xs' | 'sm' | 'md' | 'lg' | 'xl' = "md". Scales padding, text and avatars.
2143
+ Events:
2144
+ - select: A provider button was clicked; payload is "google" or "apple".
2145
+ Notes:
2146
+ - The kit only renders the buttons. The OAuth flow itself is yours.
2147
+
2134
2148
  ## UiPageDashboard (pages)
2135
2149
  Dashboard template: greeting hero, KPI tiles, occupancy chart, sales funnel, top list and activity feed.
2136
2150
  Props:
package/dist/llms.txt CHANGED
@@ -1,8 +1,8 @@
1
1
  # @ziyarago/ui
2
2
 
3
- > ZiyaraGo UI — glass design system for Umrah and Hajj products. OKLCH tokens, two palettes, dark and light, RTL, Thmanyah. One framework-neutral core with Vue 3, Nuxt and React adapters, 183 components and 17 page templates.
3
+ > ZiyaraGo UI — glass design system for Umrah and Hajj products. OKLCH tokens, two palettes, dark and light, RTL, Thmanyah. One framework-neutral core with Vue 3, Nuxt and React adapters, 184 components and 17 page templates.
4
4
 
5
- Version 0.5.0. Docs: https://ziyara.vip . Manifest (machine readable): https://ziyara.vip/manifest.json
5
+ Version 0.6.0. Docs: https://ziyara.vip . Manifest (machine readable): https://ziyara.vip/manifest.json
6
6
 
7
7
  ## Setup
8
8
  - import { UiButton } from '@ziyarago/ui/vue'
@@ -215,6 +215,7 @@ Umrah, Hajj, hotel and CRM blocks.
215
215
  - UiIncomingCall: Glass banner for an incoming call with Decline and Answer buttons.
216
216
  - UiAuthSplit: Two-column sign-in layout with a brand panel on the left and the form on the right.
217
217
  - UiAuthShowcase: Sign-in layout with a media panel: dark photo card with floating avatars, light gradient card with a social-proof pill, or a tinted panel with a glass caption. The default slot is the form.
218
+ - UiSocialAuth: Continue with Google and Apple buttons with an "or" divider. Place it under the sign-in form.
218
219
 
219
220
  ## Page templates
220
221
  Ready layouts with named slots.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ziyarago/ui",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "homepage": "https://ziyara.vip",
5
5
  "imports": {
6
6
  "vue": "import { UiButton } from '@ziyarago/ui/vue'",
@@ -252,7 +252,8 @@
252
252
  "CallCard",
253
253
  "IncomingCall",
254
254
  "AuthSplit",
255
- "AuthShowcase"
255
+ "AuthShowcase",
256
+ "SocialAuth"
256
257
  ]
257
258
  },
258
259
  {
@@ -10124,6 +10125,59 @@
10124
10125
  "logo, footer, image, people are props in both Vue and React. The media panel is hidden below the form on narrow screens (stacks under it)."
10125
10126
  ]
10126
10127
  },
10128
+ {
10129
+ "name": "SocialAuth",
10130
+ "tag": "UiSocialAuth",
10131
+ "group": "domain",
10132
+ "description": "Continue with Google and Apple buttons with an \"or\" divider. Place it under the sign-in form.",
10133
+ "props": {
10134
+ "providers": {
10135
+ "type": "('google' | 'apple')[]",
10136
+ "default": "['google', 'apple']",
10137
+ "description": "Which buttons to show, in order."
10138
+ },
10139
+ "variant": {
10140
+ "type": "'stack' | 'icons'",
10141
+ "values": [
10142
+ "stack",
10143
+ "icons"
10144
+ ],
10145
+ "default": "stack",
10146
+ "description": "'stack': full-width buttons with a label, one per row. 'icons': a row of square icon buttons."
10147
+ },
10148
+ "divider": {
10149
+ "type": "boolean",
10150
+ "default": "true",
10151
+ "description": "Show the \"or\" line above the buttons."
10152
+ },
10153
+ "labels": {
10154
+ "type": "{ google?: string; apple?: string }",
10155
+ "description": "Provider names inserted into \"Continue with {provider}\"."
10156
+ },
10157
+ "onSelect": {
10158
+ "type": "(provider: 'google' | 'apple') => void",
10159
+ "description": "Called with the clicked provider. Start your OAuth flow here."
10160
+ },
10161
+ "size": {
10162
+ "type": "'xs' | 'sm' | 'md' | 'lg' | 'xl'",
10163
+ "values": [
10164
+ "xs",
10165
+ "sm",
10166
+ "md",
10167
+ "lg",
10168
+ "xl"
10169
+ ],
10170
+ "default": "md",
10171
+ "description": "Scales padding, text and avatars."
10172
+ }
10173
+ },
10174
+ "events": {
10175
+ "select": "A provider button was clicked; payload is \"google\" or \"apple\"."
10176
+ },
10177
+ "notes": [
10178
+ "The kit only renders the buttons. The OAuth flow itself is yours."
10179
+ ]
10180
+ },
10127
10181
  {
10128
10182
  "name": "PageDashboard",
10129
10183
  "tag": "UiPageDashboard",
package/dist/style.css CHANGED
@@ -531,6 +531,11 @@
531
531
  .zg-ash__chips{display:flex;gap:10px;flex-wrap:wrap}
532
532
  .zg-ash__chip{flex:1;text-align:center;padding:14px 18px;border-radius:999px;box-shadow:inset 0 0 0 1px color-mix(in oklch,var(--zg-text-1) 40%,transparent)}
533
533
  @media(max-width:860px){.zg-ash--photo .zg-ash__frame,.zg-ash__grid{grid-template-columns:1fr}.zg-ash--photo .zg-ash__media{min-height:300px}.zg-ash__grid>.zg-ash__media{min-height:320px!important;order:2}}
534
+ /* SocialAuth */
535
+ .zg-social{display:flex;flex-direction:column;gap:14px}
536
+ .zg-social__or{display:flex;align-items:center;gap:12px;color:var(--zg-text-3);font-size:13px}.zg-social__or::before,.zg-social__or::after{content:"";flex:1;height:1px;background:var(--zg-stroke)}
537
+ .zg-social__row{display:flex;gap:10px}.zg-social--stack .zg-social__row{flex-direction:column}
538
+ .zg-social .zg-btn{gap:10px}.zg-social:not(.zg-social--stack) .zg-social__row{justify-content:center}
534
539
  /* default media art when no image is given */
535
540
  .zg-ash__media::after{content:"";position:absolute;inset:0;pointer-events:none;background:radial-gradient(circle at 78% 24%,color-mix(in oklch,#fff 55%,transparent) 0,transparent 30%),radial-gradient(circle at 18% 78%,color-mix(in oklch,var(--ash-acc) 70%,transparent) 0,transparent 38%),conic-gradient(from 210deg at 62% 48%,transparent 0 .08turn,color-mix(in oklch,#fff 22%,transparent) .1turn .18turn,transparent .2turn 1turn)}
536
541
  .zg-ash__media[style*="url("]::after{display:none}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ziyarago/ui",
3
- "version": "0.5.0",
4
- "description": "ZiyaraGo UI — glass design system for Umrah and Hajj products. OKLCH tokens, two palettes, dark and light, RTL, Thmanyah. One framework-neutral core with Vue 3, Nuxt and React adapters, 183 components and 17 page templates.",
3
+ "version": "0.6.0",
4
+ "description": "ZiyaraGo UI — glass design system for Umrah and Hajj products. OKLCH tokens, two palettes, dark and light, RTL, Thmanyah. One framework-neutral core with Vue 3, Nuxt and React adapters, 184 components and 17 page templates.",
5
5
  "keywords": [
6
6
  "ui",
7
7
  "design-system",
package/src/core/bools.js CHANGED
@@ -1,4 +1,4 @@
1
1
  // Names of props that are boolean in EVERY component that documents them. The Vue adapter turns the bare-attribute form (<UiButton block>, which Vue delivers as '') into true for these.
2
2
  // Names that are boolean somewhere and text elsewhere (modelValue, image, brand) are not listed: '' is a legitimate value there.
3
3
  // scripts/check-meta.mjs keeps this list in sync with src/meta.
4
- export const BOOL_PROPS = new Set(['addable', 'allowEmpty', 'autoResize', 'autofocus', 'banner', 'block', 'bold', 'checked', 'clearable', 'closable', 'closeOnBackdrop', 'closeOnEsc', 'collapsed', 'collapsible', 'disabled', 'dot', 'external', 'featured', 'frame', 'ghost', 'glass', 'hideArrows', 'hideIcon', 'highlightLast', 'iconOnly', 'indeterminate', 'interactive', 'labelLeft', 'last', 'loading', 'multi', 'multiple', 'open', 'pill', 'plain', 'readonly', 'required', 'resize', 'ring', 'sanitize', 'selectGroups', 'showCount', 'showForgot', 'showValue', 'spellcheck', 'ticks', 'truncate', 'vertical', 'vip', 'wrap']);
4
+ export const BOOL_PROPS = new Set(['addable', 'allowEmpty', 'autoResize', 'autofocus', 'banner', 'block', 'bold', 'checked', 'clearable', 'closable', 'closeOnBackdrop', 'closeOnEsc', 'collapsed', 'collapsible', 'disabled', 'divider', 'dot', 'external', 'featured', 'frame', 'ghost', 'glass', 'hideArrows', 'hideIcon', 'highlightLast', 'iconOnly', 'indeterminate', 'interactive', 'labelLeft', 'last', 'loading', 'multi', 'multiple', 'open', 'pill', 'plain', 'readonly', 'required', 'resize', 'ring', 'sanitize', 'selectGroups', 'showCount', 'showForgot', 'showValue', 'spellcheck', 'ticks', 'truncate', 'vertical', 'vip', 'wrap']);
@@ -30,6 +30,21 @@ export const more3 = {
30
30
  Snackbar: { render: ({ h, props: p, children }) => h('div', { class: cx('zg-snack', p.variant === 'tonal' && 'zg-snack--tonal', tc(p.tone)), role: 'status' }, h('span', { style: { flex: 1 } }, ...children), p.action ? h('button', { type: 'button', onClick: p.onAction, style: { color: p.tone === 'success' ? 'var(--zg-green)' : 'var(--zg-red)' } }, p.action) : null, p.onClose ? h('button', { type: 'button', onClick: p.onClose, 'aria-label': t('Snackbar', 'close') }, icon(h, 'x', 14)) : null) },
31
31
  TourPopover: { render: ({ C, h, props: p }) => h('div', { class: 'zg-tour' }, h('div', { style: { display: 'flex', alignItems: 'center', gap: '8px' } }, h('b', { style: { flex: 1, fontSize: '16px' } }, p.title), h('button', { type: 'button', 'aria-label': t('TourPopover', 'close'), class: 'zg-ibtn zg-ibtn--sm zg-ibtn--ghost', onClick: p.onClose }, icon(h, 'x', 14))), h('span', { style: { fontSize: '14px', lineHeight: 1.5 } }, p.text), h('div', { style: { display: 'flex', justifyContent: 'space-between', alignItems: 'center' } }, h('span', { class: 'zg-hint zg-mono' }, p.step || ''), h('div', { style: { display: 'flex', gap: '8px' } }, p.onBack ? h(C.Button, { size: 'sm', onClick: p.onBack }, t('TourPopover', 'back')) : null, h(C.Button, { size: 'sm', variant: 'primary', onClick: p.onNext }, p.last ? t('TourPopover', 'finish') : t('TourPopover', 'next'))))) },
32
32
  ProfileHeader: { render: ({ C, h, props: p, children }) => h('section', { class: 'zg-card zg-glass zg-prof' }, h('div', { class: 'zg-prof__cover', style: { backgroundImage: p.cover ? `url(${p.cover})` : undefined } }), h('div', { class: 'zg-prof__row' }, h('span', { class: 'zg-prof__av' }, h(C.Avatar, { name: p.name, src: p.src, size: 104 })), h('div', { style: { flex: 1, minWidth: '200px', display: 'flex', flexDirection: 'column', gap: '8px' } }, h('b', { style: { fontSize: '22px', fontWeight: 500 } }, p.name), h('div', { class: 'zg-chips', style: { color: 'var(--zg-text-3)', fontSize: '13px' } }, ...(p.meta || []).map(m => h('span', { key: m.label, style: { display: 'inline-flex', gap: '6px', alignItems: 'center' } }, icon(h, m.icon, 14), m.label)))), ...children)) },
33
+ SocialAuth: { render: ({ C, h, props: p }) => {
34
+ const list = (p.providers || ['google', 'apple']).filter(k => k === 'google' || k === 'apple');
35
+ const icon = k => k === 'apple'
36
+ ? h('svg', { viewBox: '0 0 24 24', width: 20, height: 20, 'aria-hidden': 'true', fill: 'currentColor' }, h('path', { d: 'M12.152 6.896c-.948 0-2.415-1.078-3.96-1.04-2.04.027-3.91 1.183-4.961 3.014-2.117 3.675-.546 9.103 1.519 12.09 1.013 1.454 2.208 3.09 3.792 3.039 1.52-.065 2.09-.987 3.935-.987 1.831 0 2.35.987 3.96.948 1.637-.026 2.676-1.48 3.676-2.948 1.156-1.688 1.636-3.325 1.662-3.415-.039-.013-3.182-1.221-3.22-4.857-.026-3.04 2.48-4.494 2.597-4.559-1.429-2.09-3.623-2.324-4.39-2.376-2-.156-3.675 1.09-4.61 1.09zM15.53 3.83c.843-1.012 1.4-2.427 1.245-3.83-1.207.052-2.662.805-3.532 1.818-.78.896-1.454 2.338-1.273 3.714 1.338.104 2.715-.688 3.559-1.701' }))
37
+ : h('svg', { viewBox: '0 0 24 24', width: 20, height: 20, 'aria-hidden': 'true' },
38
+ h('path', { fill: '#4285F4', d: 'M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z' }),
39
+ h('path', { fill: '#34A853', d: 'M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z' }),
40
+ h('path', { fill: '#FBBC05', d: 'M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z' }),
41
+ h('path', { fill: '#EA4335', d: 'M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z' }));
42
+ const name = k => (p.labels && p.labels[k]) || t('SocialAuth', k);
43
+ const stack = p.variant !== 'icons';
44
+ return h('div', { class: 'zg-social' + (stack ? ' zg-social--stack' : '') },
45
+ p.divider === false ? null : h('div', { class: 'zg-social__or', role: 'separator' }, h('span', null, t('SocialAuth', 'or'))),
46
+ h('div', { class: 'zg-social__row' }, ...list.map(k => h(C.Button, { key: k, variant: 'secondary', size: 'lg', block: stack, iconOnly: !stack, title: t('SocialAuth', 'continueWith', { provider: name(k) }), 'aria-label': t('SocialAuth', 'continueWith', { provider: name(k) }), onClick: () => p.onSelect && p.onSelect(k) }, icon(k), stack ? t('SocialAuth', 'continueWith', { provider: name(k) }) : null))));
47
+ } },
33
48
  AuthShowcase: { render: ({ C, h, props: p, children }) => {
34
49
  const v = p.variant === 'light' || p.variant === 'tint' ? p.variant : 'photo';
35
50
  const people = p.people || [];
@@ -0,0 +1,5 @@
1
+ export default {
2
+ en: { or: 'or', continueWith: 'Continue with {provider}', google: 'Google', apple: 'Apple' },
3
+ ar: { or: 'أو', continueWith: 'المتابعة باستخدام {provider}', google: 'Google', apple: 'Apple' },
4
+ ru: { or: 'или', continueWith: 'Продолжить с {provider}', google: 'Google', apple: 'Apple' },
5
+ };
@@ -53,6 +53,7 @@ import Screensaver from './Screensaver.js';
53
53
  import SearchInput from './SearchInput.js';
54
54
  import SideNav from './SideNav.js';
55
55
  import Snackbar from './Snackbar.js';
56
+ import SocialAuth from './SocialAuth.js';
56
57
  import Sortable from './Sortable.js';
57
58
  import Spinner from './Spinner.js';
58
59
  import StatusPage from './StatusPage.js';
@@ -120,6 +121,7 @@ defineMessages('Screensaver', Screensaver);
120
121
  defineMessages('SearchInput', SearchInput);
121
122
  defineMessages('SideNav', SideNav);
122
123
  defineMessages('Snackbar', Snackbar);
124
+ defineMessages('SocialAuth', SocialAuth);
123
125
  defineMessages('Sortable', Sortable);
124
126
  defineMessages('Spinner', Spinner);
125
127
  defineMessages('StatusPage', StatusPage);
@@ -198,6 +198,19 @@ export default {
198
198
  },
199
199
  events: { decline: 'Decline button clicked.', answer: 'Answer button clicked.' },
200
200
  },
201
+ SocialAuth: {
202
+ description: 'Continue with Google and Apple buttons with an "or" divider. Place it under the sign-in form.',
203
+ props: {
204
+ providers: { type: "('google' | 'apple')[]", default: "['google', 'apple']", description: 'Which buttons to show, in order.' },
205
+ variant: { type: "'stack' | 'icons'", values: ['stack', 'icons'], default: 'stack', description: "'stack': full-width buttons with a label, one per row. 'icons': a row of square icon buttons." },
206
+ divider: { type: 'boolean', default: 'true', description: 'Show the "or" line above the buttons.' },
207
+ labels: { type: '{ google?: string; apple?: string }', description: 'Provider names inserted into "Continue with {provider}".' },
208
+ onSelect: { type: "(provider: 'google' | 'apple') => void", description: 'Called with the clicked provider. Start your OAuth flow here.' },
209
+ size,
210
+ },
211
+ events: { select: 'A provider button was clicked; payload is "google" or "apple".' },
212
+ notes: ['The kit only renders the buttons. The OAuth flow itself is yours.'],
213
+ },
201
214
  AuthShowcase: {
202
215
  description: 'Sign-in layout with a media panel: dark photo card with floating avatars, light gradient card with a social-proof pill, or a tinted panel with a glass caption. The default slot is the form.',
203
216
  props: {
@@ -9,7 +9,7 @@ export const GROUPS = [
9
9
  { id: 'overlay', title: 'Overlay', blurb: 'Dialogs, sheets and popovers.', names: ['Modal', 'Drawer', 'ConfirmDialog', 'Popconfirm', 'StepDialog', 'FullscreenDialog', 'BottomSheet', 'Actionsheet', 'Popover', 'HoverCard', 'Tooltip', 'Dropdown', 'Menu', 'ContextMenu', 'CommandBar', 'CommandPalette', 'ImageViewer', 'Tour', 'TourPopover', 'Screensaver'] },
10
10
  { id: 'navigation', title: 'Navigation', blurb: 'Menus, tabs and paging.', names: ['TopNav', 'SideNav', 'SubNav', 'Tabs', 'PillTabs', 'Breadcrumbs', 'Pagination', 'Accordion'] },
11
11
  { id: 'media', title: 'Media and icons', blurb: 'Avatars, images, maps and icons.', names: ['Avatar', 'Icon', 'LazyImage', 'Gallery', 'Carousel', 'Map', 'ProfileHeader', 'ChatAi'] },
12
- { id: 'domain', title: 'Domain', blurb: 'Umrah, Hajj, hotel and CRM blocks.', names: ['HotelCard', 'TourCard', 'PrayerTimes', 'RamadanTracker', 'BookingCard', 'GuestCard', 'RoomGrid', 'RoomCalendar', 'LeadCard', 'DealCard', 'PipelineBoard', 'ContactPanel', 'KanbanColumn', 'KanbanCard', 'CallRow', 'CallCard', 'IncomingCall', 'AuthSplit', 'AuthShowcase'] },
12
+ { id: 'domain', title: 'Domain', blurb: 'Umrah, Hajj, hotel and CRM blocks.', names: ['HotelCard', 'TourCard', 'PrayerTimes', 'RamadanTracker', 'BookingCard', 'GuestCard', 'RoomGrid', 'RoomCalendar', 'LeadCard', 'DealCard', 'PipelineBoard', 'ContactPanel', 'KanbanColumn', 'KanbanCard', 'CallRow', 'CallCard', 'IncomingCall', 'AuthSplit', 'AuthShowcase', 'SocialAuth'] },
13
13
  { id: 'pages', title: 'Page templates', blurb: 'Ready layouts with named slots.', names: ['PageDashboard', 'PagePatterns', 'PageCrm', 'PageBookings', 'PageCatalog', 'PageDetail', 'PageSettings', 'PageUserList', 'PageProfile', 'PageForm', 'PageOrder', 'PageAccount', 'PagePricing', 'PageFaq', 'PageAuth', 'PageStatus'] },
14
14
  ];
15
15
 
@@ -172,6 +172,7 @@ export const UiTourPopover = C.TourPopover;
172
172
  export const UiProfileHeader = C.ProfileHeader;
173
173
  export const UiAuthSplit = C.AuthSplit;
174
174
  export const UiAuthShowcase = C.AuthShowcase;
175
+ export const UiSocialAuth = C.SocialAuth;
175
176
  export const UiStatusPage = C.StatusPage;
176
177
  export const UiValidatedField = C.ValidatedField;
177
178
  export const UiFooter = C.Footer;
@@ -82,6 +82,11 @@
82
82
  .zg-ash__chips{display:flex;gap:10px;flex-wrap:wrap}
83
83
  .zg-ash__chip{flex:1;text-align:center;padding:14px 18px;border-radius:999px;box-shadow:inset 0 0 0 1px color-mix(in oklch,var(--zg-text-1) 40%,transparent)}
84
84
  @media(max-width:860px){.zg-ash--photo .zg-ash__frame,.zg-ash__grid{grid-template-columns:1fr}.zg-ash--photo .zg-ash__media{min-height:300px}.zg-ash__grid>.zg-ash__media{min-height:320px!important;order:2}}
85
+ /* SocialAuth */
86
+ .zg-social{display:flex;flex-direction:column;gap:14px}
87
+ .zg-social__or{display:flex;align-items:center;gap:12px;color:var(--zg-text-3);font-size:13px}.zg-social__or::before,.zg-social__or::after{content:"";flex:1;height:1px;background:var(--zg-stroke)}
88
+ .zg-social__row{display:flex;gap:10px}.zg-social--stack .zg-social__row{flex-direction:column}
89
+ .zg-social .zg-btn{gap:10px}.zg-social:not(.zg-social--stack) .zg-social__row{justify-content:center}
85
90
  /* default media art when no image is given */
86
91
  .zg-ash__media::after{content:"";position:absolute;inset:0;pointer-events:none;background:radial-gradient(circle at 78% 24%,color-mix(in oklch,#fff 55%,transparent) 0,transparent 30%),radial-gradient(circle at 18% 78%,color-mix(in oklch,var(--ash-acc) 70%,transparent) 0,transparent 38%),conic-gradient(from 210deg at 62% 48%,transparent 0 .08turn,color-mix(in oklch,#fff 22%,transparent) .1turn .18turn,transparent .2turn 1turn)}
87
92
  .zg-ash__media[style*="url("]::after{display:none}
package/src/vue/index.js CHANGED
@@ -29,7 +29,7 @@ const wrap = (name, def) => defineComponent({
29
29
  });
30
30
  for (const [name, def] of Object.entries(components)) C[name] = wrap(name, def);
31
31
 
32
- export const { Button: UiButton, IconButton: UiIconButton, Badge: UiBadge, Avatar: UiAvatar, Switch: UiSwitch, Checkbox: UiCheckbox, SegmentedControl: UiSegmentedControl, Tabs: UiTabs, FilterChips: UiFilterChips, TextField: UiTextField, Select: UiSelect, CodeInput: UiCodeInput, Stepper: UiStepper, Card: UiCard, Modal: UiModal, Drawer: UiDrawer, Toast: UiToast, Breadcrumbs: UiBreadcrumbs, Pagination: UiPagination, Progress: UiProgress, Ring: UiRing, KpiTile: UiKpiTile, DataTable: UiDataTable, KanbanColumn: UiKanbanColumn, KanbanCard: UiKanbanCard, Timeline: UiTimeline, TopNav: UiTopNav, SideNav: UiSideNav, AppShell: UiAppShell, PageHeader: UiPageHeader, AuthLayout: UiAuthLayout, LeadCard: UiLeadCard, HotelCard: UiHotelCard, TourCard: UiTourCard, PrayerTimes: UiPrayerTimes, RamadanTracker: UiRamadanTracker, CallRow: UiCallRow, Alert: UiAlert, Banner: UiBanner, Accordion: UiAccordion, Skeleton: UiSkeleton, Spinner: UiSpinner, Divider: UiDivider, EmptyState: UiEmptyState, ErrorPage: UiErrorPage, DataState: UiDataState, LoadingOverlay: UiLoadingOverlay, ConfirmDialog: UiConfirmDialog, Popconfirm: UiPopconfirm, Carousel: UiCarousel, Gallery: UiGallery, Code: UiCode, PricingCard: UiPricingCard, IntegrationCard: UiIntegrationCard, IncomingCall: UiIncomingCall, CallCard: UiCallCard, Dropdown: UiDropdown, Menu: UiMenu, Tooltip: UiTooltip, HoverCard: UiHoverCard, Popover: UiPopover, CopyButton: UiCopyButton, CommandBar: UiCommandBar, CommandPalette: UiCommandPalette, NotificationBell: UiNotificationBell, ToggleGroup: UiToggleGroup, Fab: UiFab, Textarea: UiTextarea, NumberInput: UiNumberInput, PasswordInput: UiPasswordInput, SearchInput: UiSearchInput, RadioGroup: UiRadioGroup, Slider: UiSlider, Rating: UiRating, ChipInput: UiChipInput, InlineEdit: UiInlineEdit, ColorPicker: UiColorPicker, FileUpload: UiFileUpload, Combobox: UiCombobox, MultiSelect: UiMultiSelect, GroupedSelect: UiGroupedSelect, PhoneInput: UiPhoneInput, Calendar: UiCalendar, DatePicker: UiDatePicker, TimePicker: UiTimePicker, FormField: UiFormField, LoginForm: UiLoginForm, StepForm: UiStepForm, Tag: UiTag, Kbd: UiKbd, StatsCard: UiStatsCard, KpiInline: UiKpiInline, MiniChart: UiMiniChart, Descriptions: UiDescriptions, LazyImage: UiLazyImage, SystemStatus: UiSystemStatus, TreeView: UiTreeView, CalendarView: UiCalendarView, SubNav: UiSubNav, ActionRail: UiActionRail, SplitLayout: UiSplitLayout, SettingsSection: UiSettingsSection, ScrollArea: UiScrollArea, DealCard: UiDealCard, PipelineBoard: UiPipelineBoard, ContactPanel: UiContactPanel, SalesFunnel: UiSalesFunnel, BookingCard: UiBookingCard, GuestCard: UiGuestCard, RoomGrid: UiRoomGrid, RoomCalendar: UiRoomCalendar, OccupancyChart: UiOccupancyChart, Chip: UiChip, IconTile: UiIconTile, StatusIcon: UiStatusIcon, UserCell: UiUserCell, StatRow: UiStatRow, CountryRow: UiCountryRow, StatLine: UiStatLine, StatStrip: UiStatStrip, VersusBar: UiVersusBar, SegBar: UiSegBar, HeroBanner: UiHeroBanner, TabTiles: UiTabTiles, PillTabs: UiPillTabs, PillSelect: UiPillSelect, ChartCard: UiChartCard, ActionCard: UiActionCard, Snackbar: UiSnackbar, TourPopover: UiTourPopover, ProfileHeader: UiProfileHeader, AuthSplit: UiAuthSplit, AuthShowcase: UiAuthShowcase, StatusPage: UiStatusPage, ValidatedField: UiValidatedField, Footer: UiFooter, DataGroup: UiDataGroup, OptionCard: UiOptionCard, OptionCards: UiOptionCards, RichEditor: UiRichEditor, RangeSlider: UiRangeSlider, RangeCalendar: UiRangeCalendar, StepDialog: UiStepDialog, FullscreenDialog: UiFullscreenDialog, PageDashboard: UiPageDashboard, PagePatterns: UiPagePatterns, PageCrm: UiPageCrm, PageBookings: UiPageBookings, PageCatalog: UiPageCatalog, PageDetail: UiPageDetail, PageSettings: UiPageSettings, PageUserList: UiPageUserList, PageProfile: UiPageProfile, PageForm: UiPageForm, PageOrder: UiPageOrder, PageAccount: UiPageAccount, PagePricing: UiPagePricing, PageFaq: UiPageFaq, PageAuth: UiPageAuth, PageStatus: UiPageStatus, TreeSelect: UiTreeSelect, ContextMenu: UiContextMenu, Sortable: UiSortable, Map: UiMap, ImageUpload: UiImageUpload, Screensaver: UiScreensaver, Tour: UiTour, Heading: UiHeading, Text: UiText, Box: UiBox, Center: UiCenter, HStack: UiHStack, VStack: UiVStack, Grid: UiGrid, Link: UiLink, Pressable: UiPressable, Icon: UiIcon, Portal: UiPortal, LiquidGlass: UiLiquidGlass, BottomSheet: UiBottomSheet, Actionsheet: UiActionsheet, ImageViewer: UiImageViewer, ChatAi: UiChatAi } = C;
32
+ export const { Button: UiButton, IconButton: UiIconButton, Badge: UiBadge, Avatar: UiAvatar, Switch: UiSwitch, Checkbox: UiCheckbox, SegmentedControl: UiSegmentedControl, Tabs: UiTabs, FilterChips: UiFilterChips, TextField: UiTextField, Select: UiSelect, CodeInput: UiCodeInput, Stepper: UiStepper, Card: UiCard, Modal: UiModal, Drawer: UiDrawer, Toast: UiToast, Breadcrumbs: UiBreadcrumbs, Pagination: UiPagination, Progress: UiProgress, Ring: UiRing, KpiTile: UiKpiTile, DataTable: UiDataTable, KanbanColumn: UiKanbanColumn, KanbanCard: UiKanbanCard, Timeline: UiTimeline, TopNav: UiTopNav, SideNav: UiSideNav, AppShell: UiAppShell, PageHeader: UiPageHeader, AuthLayout: UiAuthLayout, LeadCard: UiLeadCard, HotelCard: UiHotelCard, TourCard: UiTourCard, PrayerTimes: UiPrayerTimes, RamadanTracker: UiRamadanTracker, CallRow: UiCallRow, Alert: UiAlert, Banner: UiBanner, Accordion: UiAccordion, Skeleton: UiSkeleton, Spinner: UiSpinner, Divider: UiDivider, EmptyState: UiEmptyState, ErrorPage: UiErrorPage, DataState: UiDataState, LoadingOverlay: UiLoadingOverlay, ConfirmDialog: UiConfirmDialog, Popconfirm: UiPopconfirm, Carousel: UiCarousel, Gallery: UiGallery, Code: UiCode, PricingCard: UiPricingCard, IntegrationCard: UiIntegrationCard, IncomingCall: UiIncomingCall, CallCard: UiCallCard, Dropdown: UiDropdown, Menu: UiMenu, Tooltip: UiTooltip, HoverCard: UiHoverCard, Popover: UiPopover, CopyButton: UiCopyButton, CommandBar: UiCommandBar, CommandPalette: UiCommandPalette, NotificationBell: UiNotificationBell, ToggleGroup: UiToggleGroup, Fab: UiFab, Textarea: UiTextarea, NumberInput: UiNumberInput, PasswordInput: UiPasswordInput, SearchInput: UiSearchInput, RadioGroup: UiRadioGroup, Slider: UiSlider, Rating: UiRating, ChipInput: UiChipInput, InlineEdit: UiInlineEdit, ColorPicker: UiColorPicker, FileUpload: UiFileUpload, Combobox: UiCombobox, MultiSelect: UiMultiSelect, GroupedSelect: UiGroupedSelect, PhoneInput: UiPhoneInput, Calendar: UiCalendar, DatePicker: UiDatePicker, TimePicker: UiTimePicker, FormField: UiFormField, LoginForm: UiLoginForm, StepForm: UiStepForm, Tag: UiTag, Kbd: UiKbd, StatsCard: UiStatsCard, KpiInline: UiKpiInline, MiniChart: UiMiniChart, Descriptions: UiDescriptions, LazyImage: UiLazyImage, SystemStatus: UiSystemStatus, TreeView: UiTreeView, CalendarView: UiCalendarView, SubNav: UiSubNav, ActionRail: UiActionRail, SplitLayout: UiSplitLayout, SettingsSection: UiSettingsSection, ScrollArea: UiScrollArea, DealCard: UiDealCard, PipelineBoard: UiPipelineBoard, ContactPanel: UiContactPanel, SalesFunnel: UiSalesFunnel, BookingCard: UiBookingCard, GuestCard: UiGuestCard, RoomGrid: UiRoomGrid, RoomCalendar: UiRoomCalendar, OccupancyChart: UiOccupancyChart, Chip: UiChip, IconTile: UiIconTile, StatusIcon: UiStatusIcon, UserCell: UiUserCell, StatRow: UiStatRow, CountryRow: UiCountryRow, StatLine: UiStatLine, StatStrip: UiStatStrip, VersusBar: UiVersusBar, SegBar: UiSegBar, HeroBanner: UiHeroBanner, TabTiles: UiTabTiles, PillTabs: UiPillTabs, PillSelect: UiPillSelect, ChartCard: UiChartCard, ActionCard: UiActionCard, Snackbar: UiSnackbar, TourPopover: UiTourPopover, ProfileHeader: UiProfileHeader, AuthSplit: UiAuthSplit, AuthShowcase: UiAuthShowcase, SocialAuth: UiSocialAuth, StatusPage: UiStatusPage, ValidatedField: UiValidatedField, Footer: UiFooter, DataGroup: UiDataGroup, OptionCard: UiOptionCard, OptionCards: UiOptionCards, RichEditor: UiRichEditor, RangeSlider: UiRangeSlider, RangeCalendar: UiRangeCalendar, StepDialog: UiStepDialog, FullscreenDialog: UiFullscreenDialog, PageDashboard: UiPageDashboard, PagePatterns: UiPagePatterns, PageCrm: UiPageCrm, PageBookings: UiPageBookings, PageCatalog: UiPageCatalog, PageDetail: UiPageDetail, PageSettings: UiPageSettings, PageUserList: UiPageUserList, PageProfile: UiPageProfile, PageForm: UiPageForm, PageOrder: UiPageOrder, PageAccount: UiPageAccount, PagePricing: UiPagePricing, PageFaq: UiPageFaq, PageAuth: UiPageAuth, PageStatus: UiPageStatus, TreeSelect: UiTreeSelect, ContextMenu: UiContextMenu, Sortable: UiSortable, Map: UiMap, ImageUpload: UiImageUpload, Screensaver: UiScreensaver, Tour: UiTour, Heading: UiHeading, Text: UiText, Box: UiBox, Center: UiCenter, HStack: UiHStack, VStack: UiVStack, Grid: UiGrid, Link: UiLink, Pressable: UiPressable, Icon: UiIcon, Portal: UiPortal, LiquidGlass: UiLiquidGlass, BottomSheet: UiBottomSheet, Actionsheet: UiActionsheet, ImageViewer: UiImageViewer, ChatAi: UiChatAi } = C;
33
33
  export const install = app => { for (const [n, c] of Object.entries(C)) app.component('Ui' + n, c); };
34
34
  export { fmt, setIconBase, rules } from '../core/index.js';
35
35
  export { useUiTheme } from '../theme.js';
package/types/react.d.ts CHANGED
@@ -5125,6 +5125,39 @@ export interface UiSnackbarProps {
5125
5125
  }
5126
5126
  export const UiSnackbar: ComponentType<UiSnackbarProps>;
5127
5127
 
5128
+ /**
5129
+ * Continue with Google and Apple buttons with an "or" divider. Place it under the sign-in form.
5130
+ * Note: The kit only renders the buttons. The OAuth flow itself is yours.
5131
+ */
5132
+ export interface UiSocialAuthProps {
5133
+ /**
5134
+ * Which buttons to show, in order.
5135
+ * @default ['google', 'apple']
5136
+ */
5137
+ providers?: ('google' | 'apple')[];
5138
+ /**
5139
+ * 'stack': full-width buttons with a label, one per row. 'icons': a row of square icon buttons.
5140
+ * @default 'stack'
5141
+ */
5142
+ variant?: 'stack' | 'icons';
5143
+ /**
5144
+ * Show the "or" line above the buttons.
5145
+ * @default 'true'
5146
+ */
5147
+ divider?: boolean;
5148
+ /** Provider names inserted into "Continue with {provider}". */
5149
+ labels?: { google?: string; apple?: string };
5150
+ /** Called with the clicked provider. Start your OAuth flow here. */
5151
+ onSelect?: (provider: 'google' | 'apple') => void;
5152
+ /**
5153
+ * Scales padding, text and avatars.
5154
+ * @default 'md'
5155
+ */
5156
+ size?: Size;
5157
+ children?: ReactNode;
5158
+ }
5159
+ export const UiSocialAuth: ComponentType<UiSocialAuthProps>;
5160
+
5128
5161
  /**
5129
5162
  * Drag-and-drop reorderable list with grip handles and up/down buttons.
5130
5163
  * Note: Controlled: the parent must store the array from change and pass it back as items.
@@ -153,6 +153,7 @@ declare module 'vue' {
153
153
  UiSkeleton: typeof Ui.UiSkeleton;
154
154
  UiSlider: typeof Ui.UiSlider;
155
155
  UiSnackbar: typeof Ui.UiSnackbar;
156
+ UiSocialAuth: typeof Ui.UiSocialAuth;
156
157
  UiSortable: typeof Ui.UiSortable;
157
158
  UiSpinner: typeof Ui.UiSpinner;
158
159
  UiSplitLayout: typeof Ui.UiSplitLayout;
package/types/vue.d.ts CHANGED
@@ -4996,6 +4996,39 @@ export interface UiSnackbarSlots {
4996
4996
  }
4997
4997
  export const UiSnackbar: UiVueComponent<UiSnackbarProps, UiSnackbarSlots>;
4998
4998
 
4999
+ /**
5000
+ * Continue with Google and Apple buttons with an "or" divider. Place it under the sign-in form.
5001
+ * Note: The kit only renders the buttons. The OAuth flow itself is yours.
5002
+ */
5003
+ export interface UiSocialAuthProps {
5004
+ /**
5005
+ * Which buttons to show, in order.
5006
+ * @default ['google', 'apple']
5007
+ */
5008
+ providers?: ('google' | 'apple')[];
5009
+ /**
5010
+ * 'stack': full-width buttons with a label, one per row. 'icons': a row of square icon buttons.
5011
+ * @default 'stack'
5012
+ */
5013
+ variant?: 'stack' | 'icons';
5014
+ /**
5015
+ * Show the "or" line above the buttons.
5016
+ * @default 'true'
5017
+ */
5018
+ divider?: boolean;
5019
+ /** Provider names inserted into "Continue with {provider}". */
5020
+ labels?: { google?: string; apple?: string };
5021
+ /** Called with the clicked provider. Start your OAuth flow here. */
5022
+ onSelect?: (provider: 'google' | 'apple') => void;
5023
+ /**
5024
+ * Scales padding, text and avatars.
5025
+ * @default 'md'
5026
+ */
5027
+ size?: Size;
5028
+ }
5029
+ export interface UiSocialAuthSlots {}
5030
+ export const UiSocialAuth: UiVueComponent<UiSocialAuthProps, UiSocialAuthSlots>;
5031
+
4999
5032
  /**
5000
5033
  * Drag-and-drop reorderable list with grip handles and up/down buttons.
5001
5034
  * Note: Controlled: the parent must store the array from change and pass it back as items.