@roxyapi/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.
Files changed (153) hide show
  1. package/README.md +1 -1
  2. package/dist/cdn/components/ashtakavarga-grid.js +3 -362
  3. package/dist/cdn/components/ashtakavarga-grid.js.map +2 -2
  4. package/dist/cdn/components/biorhythm-chart.js +2 -225
  5. package/dist/cdn/components/biorhythm-chart.js.map +2 -2
  6. package/dist/cdn/components/choghadiya-grid.js +2 -231
  7. package/dist/cdn/components/choghadiya-grid.js.map +2 -2
  8. package/dist/cdn/components/compatibility-card.js +2 -230
  9. package/dist/cdn/components/compatibility-card.js.map +2 -2
  10. package/dist/cdn/components/dasha-timeline.js +3 -283
  11. package/dist/cdn/components/dasha-timeline.js.map +4 -4
  12. package/dist/cdn/components/data.js +3 -230
  13. package/dist/cdn/components/data.js.map +2 -2
  14. package/dist/cdn/components/divisional-chart.js +3 -356
  15. package/dist/cdn/components/divisional-chart.js.map +4 -4
  16. package/dist/cdn/components/dosha-card.js +2 -225
  17. package/dist/cdn/components/dosha-card.js.map +2 -2
  18. package/dist/cdn/components/endpoint-form.js +2 -243
  19. package/dist/cdn/components/endpoint-form.js.map +2 -2
  20. package/dist/cdn/components/guna-milan.js +2 -269
  21. package/dist/cdn/components/guna-milan.js.map +2 -2
  22. package/dist/cdn/components/hexagram.js +3 -247
  23. package/dist/cdn/components/hexagram.js.map +2 -2
  24. package/dist/cdn/components/horoscope-card.js +3 -281
  25. package/dist/cdn/components/horoscope-card.js.map +2 -2
  26. package/dist/cdn/components/kp-chart.js +2 -277
  27. package/dist/cdn/components/kp-chart.js.map +2 -2
  28. package/dist/cdn/components/kp-planets-table.js +2 -195
  29. package/dist/cdn/components/kp-planets-table.js.map +2 -2
  30. package/dist/cdn/components/kp-ruling-planets.js +2 -240
  31. package/dist/cdn/components/kp-ruling-planets.js.map +2 -2
  32. package/dist/cdn/components/location-search.js +2 -240
  33. package/dist/cdn/components/location-search.js.map +2 -2
  34. package/dist/cdn/components/moon-phase.js +3 -223
  35. package/dist/cdn/components/moon-phase.js.map +2 -2
  36. package/dist/cdn/components/nakshatra-card.js +2 -200
  37. package/dist/cdn/components/nakshatra-card.js.map +2 -2
  38. package/dist/cdn/components/natal-chart.js +3 -563
  39. package/dist/cdn/components/natal-chart.js.map +4 -4
  40. package/dist/cdn/components/numerology-card.js +2 -232
  41. package/dist/cdn/components/numerology-card.js.map +2 -2
  42. package/dist/cdn/components/panchang-table.js +3 -220
  43. package/dist/cdn/components/panchang-table.js.map +2 -2
  44. package/dist/cdn/components/shadbala-table.js +3 -284
  45. package/dist/cdn/components/shadbala-table.js.map +2 -2
  46. package/dist/cdn/components/synastry-chart.js +2 -398
  47. package/dist/cdn/components/synastry-chart.js.map +2 -2
  48. package/dist/cdn/components/tarot-card.js +3 -261
  49. package/dist/cdn/components/tarot-card.js.map +2 -2
  50. package/dist/cdn/components/tarot-spread.js +2 -248
  51. package/dist/cdn/components/tarot-spread.js.map +2 -2
  52. package/dist/cdn/components/transits-table.js +3 -382
  53. package/dist/cdn/components/transits-table.js.map +4 -4
  54. package/dist/cdn/components/vedic-kundli.js +3 -305
  55. package/dist/cdn/components/vedic-kundli.js.map +4 -4
  56. package/dist/cdn/components/vedic-planets-table.js +2 -202
  57. package/dist/cdn/components/vedic-planets-table.js.map +2 -2
  58. package/dist/cdn/components/western-planets-table.js +3 -192
  59. package/dist/cdn/components/western-planets-table.js.map +2 -2
  60. package/dist/cdn/components/yoga-list.js +2 -305
  61. package/dist/cdn/components/yoga-list.js.map +2 -2
  62. package/dist/cdn/roxy-ui.js +3 -5102
  63. package/dist/cdn/roxy-ui.js.map +4 -4
  64. package/dist/cdn/widgets.js +1 -114
  65. package/dist/components/ashtakavarga-grid.js +1 -577
  66. package/dist/components/ashtakavarga-grid.js.map +3 -3
  67. package/dist/components/biorhythm-chart.js +1 -378
  68. package/dist/components/biorhythm-chart.js.map +3 -3
  69. package/dist/components/choghadiya-grid.js +1 -397
  70. package/dist/components/choghadiya-grid.js.map +3 -3
  71. package/dist/components/compatibility-card.js +1 -359
  72. package/dist/components/compatibility-card.js.map +3 -3
  73. package/dist/components/dasha-timeline.d.ts.map +1 -1
  74. package/dist/components/dasha-timeline.js +1 -447
  75. package/dist/components/dasha-timeline.js.map +4 -4
  76. package/dist/components/data.js +1 -408
  77. package/dist/components/data.js.map +3 -3
  78. package/dist/components/divisional-chart.d.ts.map +1 -1
  79. package/dist/components/divisional-chart.js +1 -932
  80. package/dist/components/divisional-chart.js.map +4 -4
  81. package/dist/components/dosha-card.js +1 -339
  82. package/dist/components/dosha-card.js.map +3 -3
  83. package/dist/components/endpoint-form.js +1 -505
  84. package/dist/components/endpoint-form.js.map +3 -3
  85. package/dist/components/guna-milan.js +1 -420
  86. package/dist/components/guna-milan.js.map +3 -3
  87. package/dist/components/hexagram.js +1 -426
  88. package/dist/components/hexagram.js.map +3 -3
  89. package/dist/components/horoscope-card.js +1 -427
  90. package/dist/components/horoscope-card.js.map +3 -3
  91. package/dist/components/kp-chart.js +1 -441
  92. package/dist/components/kp-chart.js.map +3 -3
  93. package/dist/components/kp-planets-table.js +1 -292
  94. package/dist/components/kp-planets-table.js.map +3 -3
  95. package/dist/components/kp-ruling-planets.js +1 -334
  96. package/dist/components/kp-ruling-planets.js.map +3 -3
  97. package/dist/components/location-search.js +1 -461
  98. package/dist/components/location-search.js.map +3 -3
  99. package/dist/components/moon-phase.js +1 -373
  100. package/dist/components/moon-phase.js.map +3 -3
  101. package/dist/components/nakshatra-card.js +1 -290
  102. package/dist/components/nakshatra-card.js.map +3 -3
  103. package/dist/components/natal-chart.d.ts +0 -1
  104. package/dist/components/natal-chart.d.ts.map +1 -1
  105. package/dist/components/natal-chart.js +1 -1086
  106. package/dist/components/natal-chart.js.map +4 -4
  107. package/dist/components/numerology-card.js +1 -361
  108. package/dist/components/numerology-card.js.map +3 -3
  109. package/dist/components/panchang-table.js +1 -396
  110. package/dist/components/panchang-table.js.map +3 -3
  111. package/dist/components/shadbala-table.js +1 -459
  112. package/dist/components/shadbala-table.js.map +3 -3
  113. package/dist/components/synastry-chart.js +1 -704
  114. package/dist/components/synastry-chart.js.map +3 -3
  115. package/dist/components/tarot-card.js +1 -379
  116. package/dist/components/tarot-card.js.map +3 -3
  117. package/dist/components/tarot-spread.js +1 -356
  118. package/dist/components/tarot-spread.js.map +3 -3
  119. package/dist/components/transits-table.d.ts +2 -0
  120. package/dist/components/transits-table.d.ts.map +1 -1
  121. package/dist/components/transits-table.js +1 -594
  122. package/dist/components/transits-table.js.map +4 -4
  123. package/dist/components/vedic-kundli.d.ts.map +1 -1
  124. package/dist/components/vedic-kundli.js +1 -848
  125. package/dist/components/vedic-kundli.js.map +4 -4
  126. package/dist/components/vedic-planets-table.js +1 -414
  127. package/dist/components/vedic-planets-table.js.map +3 -3
  128. package/dist/components/western-planets-table.js +1 -409
  129. package/dist/components/western-planets-table.js.map +3 -3
  130. package/dist/components/yoga-list.js +1 -429
  131. package/dist/components/yoga-list.js.map +3 -3
  132. package/dist/index.cjs +1 -8726
  133. package/dist/index.cjs.map +4 -4
  134. package/dist/index.js +1 -8706
  135. package/dist/index.js.map +4 -4
  136. package/dist/utils/disclosure.d.ts +16 -0
  137. package/dist/utils/disclosure.d.ts.map +1 -0
  138. package/dist/utils/kundli-render.d.ts.map +1 -1
  139. package/dist/utils/kundli-styles.d.ts.map +1 -1
  140. package/dist/utils/tablist.d.ts +44 -0
  141. package/dist/utils/tablist.d.ts.map +1 -0
  142. package/dist/version.d.ts +1 -1
  143. package/package.json +3 -1
  144. package/src/components/dasha-timeline.ts +10 -1
  145. package/src/components/divisional-chart.ts +2 -0
  146. package/src/components/natal-chart.ts +37 -62
  147. package/src/components/transits-table.ts +45 -18
  148. package/src/components/vedic-kundli.ts +2 -1
  149. package/src/utils/disclosure.ts +62 -0
  150. package/src/utils/kundli-render.ts +21 -35
  151. package/src/utils/kundli-styles.ts +0 -31
  152. package/src/utils/tablist.ts +124 -0
  153. package/src/version.ts +1 -1
@@ -1,506 +1,2 @@
1
- var __defProp = Object.defineProperty;
2
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
- var __decorateClass = (decorators, target, key, kind) => {
4
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
- if (decorator = decorators[i])
7
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
- if (kind && result) __defProp(target, key, result);
9
- return result;
10
- };
11
-
12
- // packages/ui/src/components/endpoint-form.ts
13
- import { css as css2, html, LitElement, nothing } from "lit";
14
- import { customElement, property, state } from "lit/decorators.js";
15
-
16
- // packages/ui/src/utils/base-styles.ts
17
- import { css } from "lit";
18
- var baseStyles = css`
19
- :host {
20
- display: block;
21
- container-type: inline-size;
22
- font-family: var(
23
- --roxy-font-sans,
24
- system-ui,
25
- -apple-system,
26
- BlinkMacSystemFont,
27
- 'Segoe UI',
28
- Roboto,
29
- sans-serif
30
- );
31
- color: var(--roxy-fg, #0a0a0a);
32
- background: transparent;
33
- font-size: var(--roxy-text-base, 1rem);
34
- line-height: var(--roxy-leading-normal, 1.5);
35
- animation: roxy-fade-in var(--roxy-motion-duration, 200ms)
36
- var(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;
37
- }
38
-
39
- *,
40
- *::before,
41
- *::after {
42
- box-sizing: border-box;
43
- }
44
-
45
- @keyframes roxy-fade-in {
46
- from {
47
- opacity: 0;
48
- transform: translateY(2px);
49
- }
50
- to {
51
- opacity: 1;
52
- transform: translateY(0);
53
- }
54
- }
55
-
56
- @media (prefers-reduced-motion: reduce) {
57
- :host {
58
- animation: none;
59
- }
60
- }
61
-
62
- .roxy-skeleton {
63
- background: linear-gradient(
64
- 90deg,
65
- var(--roxy-border, #e4e4e7) 0%,
66
- color-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,
67
- var(--roxy-border, #e4e4e7) 100%
68
- );
69
- background-size: 200% 100%;
70
- animation: roxy-shimmer 1.4s ease-in-out infinite;
71
- border-radius: var(--roxy-radius-md, 8px);
72
- }
73
-
74
- @keyframes roxy-shimmer {
75
- 0% {
76
- background-position: 200% 0;
77
- }
78
- 100% {
79
- background-position: -200% 0;
80
- }
81
- }
82
-
83
- @media (prefers-reduced-motion: reduce) {
84
- .roxy-skeleton {
85
- animation: none;
86
- }
87
- }
88
-
89
- .roxy-empty {
90
- padding: var(--roxy-space-lg, 1.5rem);
91
- color: var(--roxy-muted, #71717a);
92
- text-align: center;
93
- font-size: var(--roxy-text-sm, 0.875rem);
94
- }
95
-
96
- :host(:focus-within) .roxy-card {
97
- outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
98
- outline-offset: 2px;
99
- }
100
-
101
- /* Force the text-style variant on every Unicode glyph in the component.
102
- * macOS and iOS substitute coloured emoji glyphs for the planetary and
103
- * gender Unicode code points (Mars, Venus, Mercury, etc.) when the
104
- * system colour-emoji font wins font selection. The text-style variant
105
- * keeps glyphs monochrome so they inherit the surrounding fill colour
106
- * and match the brand palette consistently across platforms.
107
- *
108
- * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,
109
- * Firefox 139+). On older browsers the rule is silently ignored.
110
- */
111
- :host {
112
- font-variant-emoji: text;
113
- }
114
- `;
115
-
116
- // packages/ui/src/utils/string.ts
117
- function humanize(s) {
118
- return s.replace(/[_-]+/g, " ").replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^\w/, (c) => c.toUpperCase());
119
- }
120
-
121
- // packages/ui/src/components/endpoint-form.ts
122
- var specCache = /* @__PURE__ */ new Map();
123
- async function loadSpec(url) {
124
- let pending = specCache.get(url);
125
- if (!pending) {
126
- pending = fetch(url).then(async (res) => {
127
- if (!res.ok) throw new Error(`HTTP ${res.status}`);
128
- return await res.json();
129
- }).catch((err) => {
130
- specCache.delete(url);
131
- throw err;
132
- });
133
- specCache.set(url, pending);
134
- }
135
- return pending;
136
- }
137
- var RoxyEndpointForm = class extends LitElement {
138
- constructor() {
139
- super(...arguments);
140
- this.endpoint = "vedic-astrology/birth-chart";
141
- this.method = "POST";
142
- this.specUrl = "https://roxyapi.com/api/v2/openapi.json";
143
- this.submitLabel = "Submit";
144
- this.fields = [];
145
- this.values = {};
146
- this.hasLocation = false;
147
- this.loaded = false;
148
- this.specError = null;
149
- this.retryLoadSchema = () => {
150
- this.loaded = false;
151
- this.specError = null;
152
- void this.loadSchema();
153
- };
154
- this.onLocation = (e) => {
155
- const detail = e.detail;
156
- if (detail) {
157
- this.values = {
158
- ...this.values,
159
- latitude: detail.latitude,
160
- longitude: detail.longitude,
161
- timezone: detail.timezone ?? detail.utcOffset
162
- };
163
- }
164
- };
165
- this.onSubmit = (e) => {
166
- e.preventDefault();
167
- const missing = this.fields.filter((f) => f.required).filter(
168
- (f) => this.values[f.name] === void 0 || this.values[f.name] === ""
169
- );
170
- if (missing.length > 0) {
171
- this.dispatchEvent(
172
- new CustomEvent("roxy-validation-error", {
173
- detail: { missing: missing.map((m) => m.name) },
174
- bubbles: true,
175
- composed: true
176
- })
177
- );
178
- return;
179
- }
180
- this.dispatchEvent(
181
- new CustomEvent("roxy-submit", {
182
- detail: { endpoint: this.endpoint, values: this.values },
183
- bubbles: true,
184
- composed: true
185
- })
186
- );
187
- };
188
- }
189
- connectedCallback() {
190
- super.connectedCallback();
191
- void this.loadSchema();
192
- }
193
- async loadSchema() {
194
- this.specError = null;
195
- try {
196
- const spec = await loadSpec(this.specUrl);
197
- const path = `/${this.endpoint.replace(/^\//, "")}`;
198
- const op = spec.paths?.[path]?.[this.method.toLowerCase()];
199
- if (!op) {
200
- throw new Error(
201
- `Endpoint ${this.method} ${path} not found in OpenAPI spec`
202
- );
203
- }
204
- const schemas = spec.components?.schemas ?? {};
205
- const fields = [];
206
- let bodySchema;
207
- if (op.requestBody) {
208
- const ref = op.requestBody.content?.["application/json"]?.schema;
209
- bodySchema = this.resolve(ref, schemas);
210
- }
211
- if (bodySchema?.properties) {
212
- const required = new Set(bodySchema.required ?? []);
213
- for (const [name, sub] of Object.entries(bodySchema.properties)) {
214
- const resolved = this.resolve(sub, schemas) ?? {};
215
- fields.push({
216
- name,
217
- type: this.fieldType(resolved),
218
- required: required.has(name),
219
- description: resolved.description,
220
- enum: resolved.enum,
221
- min: resolved.minimum,
222
- max: resolved.maximum,
223
- default: resolved.default
224
- });
225
- }
226
- }
227
- for (const param of op.parameters ?? []) {
228
- if (param.in === "path" || param.in === "query") {
229
- const resolved = this.resolve(param.schema, schemas) ?? {};
230
- fields.push({
231
- name: param.name,
232
- type: this.fieldType(resolved),
233
- required: !!param.required,
234
- description: resolved.description,
235
- enum: resolved.enum,
236
- default: resolved.default
237
- });
238
- }
239
- }
240
- this.fields = fields;
241
- this.hasLocation = fields.some((f) => f.name === "latitude") && fields.some((f) => f.name === "longitude") && fields.some((f) => f.name === "timezone");
242
- const init = {};
243
- for (const f of fields) {
244
- if (f.default !== void 0) init[f.name] = f.default;
245
- }
246
- this.values = init;
247
- this.loaded = true;
248
- } catch (err) {
249
- const message = err instanceof Error ? err.message : String(err);
250
- this.specError = message;
251
- this.loaded = true;
252
- this.dispatchEvent(
253
- new CustomEvent("roxy-spec-error", {
254
- detail: { url: this.specUrl, message },
255
- bubbles: true,
256
- composed: true
257
- })
258
- );
259
- }
260
- }
261
- resolve(schema, all) {
262
- if (!schema) return void 0;
263
- if ("$ref" in schema && schema.$ref) {
264
- const name = schema.$ref.split("/").pop();
265
- return name ? all[name] : void 0;
266
- }
267
- return schema;
268
- }
269
- fieldType(s) {
270
- if (s.enum) return "enum";
271
- if (s.format === "date") return "date";
272
- if (s.format === "time") return "time";
273
- if (s.format === "date-time") return "datetime";
274
- if (s.type === "integer" || s.type === "number") return "number";
275
- return "text";
276
- }
277
- setValue(name, value) {
278
- this.values = { ...this.values, [name]: value };
279
- }
280
- render() {
281
- if (!this.loaded) {
282
- return html`<form><div class="roxy-skeleton" style="height: 8rem"></div></form>`;
283
- }
284
- if (this.specError) {
285
- return html`<div class="spec-error" role="alert">
286
- Schema load failed: ${this.specError}
287
- <button type="button" class="submit" @click=${this.retryLoadSchema}>Retry</button>
288
- </div>`;
289
- }
290
- const renderField = (f) => {
291
- if (this.hasLocation && (f.name === "latitude" || f.name === "longitude" || f.name === "timezone")) {
292
- return nothing;
293
- }
294
- const inputId = `roxy-form-${f.name}`;
295
- return html`<div class="field">
296
- <label for=${inputId}>
297
- ${humanize(f.name)}${f.required ? html`<span class="req" aria-hidden="true">*</span>` : nothing}
298
- </label>
299
- ${f.enum ? html`<select
300
- id=${inputId}
301
- ?required=${f.required}
302
- @change=${(e) => this.setValue(f.name, e.target.value)}
303
- >
304
- <option value="">Choose</option>
305
- ${f.enum.map(
306
- (opt) => html`<option value=${opt} ?selected=${this.values[f.name] === opt}>
307
- ${opt}
308
- </option>`
309
- )}
310
- </select>` : html`<input
311
- id=${inputId}
312
- type=${this.htmlType(f.type)}
313
- ?required=${f.required}
314
- min=${f.min ?? ""}
315
- max=${f.max ?? ""}
316
- step=${f.type === "number" ? "any" : ""}
317
- .value=${this.values[f.name] ?? ""}
318
- @input=${(e) => this.setValue(
319
- f.name,
320
- this.coerce(f.type, e.target.value)
321
- )}
322
- />`}
323
- ${f.description ? html`<small class="help">${f.description}</small>` : nothing}
324
- </div>`;
325
- };
326
- return html`<form @submit=${this.onSubmit}>
327
- <h2 class="title">${humanize(this.endpoint.split("/").pop() ?? "")}</h2>
328
- ${this.hasLocation ? html`<div class="location-block">
329
- <label>Birth location</label>
330
- <roxy-location-search
331
- @roxy-location-select=${this.onLocation}
332
- placeholder="City of birth"
333
- ></roxy-location-search>
334
- <small class="help">
335
- Required: latitude, longitude, timezone. Pick a city to autofill.
336
- </small>
337
- </div>` : nothing}
338
- <div class="fields">
339
- ${this.fields.map((f) => renderField(f))}
340
- </div>
341
- <button class="submit" type="submit">${this.submitLabel}</button>
342
- </form>`;
343
- }
344
- htmlType(t) {
345
- switch (t) {
346
- case "date":
347
- return "date";
348
- case "time":
349
- return "time";
350
- case "datetime":
351
- return "datetime-local";
352
- case "number":
353
- return "number";
354
- default:
355
- return "text";
356
- }
357
- }
358
- coerce(t, v) {
359
- if (v === "") return void 0;
360
- if (t === "number") {
361
- const n = Number(v);
362
- return Number.isFinite(n) ? n : void 0;
363
- }
364
- return v;
365
- }
366
- };
367
- RoxyEndpointForm.styles = [
368
- baseStyles,
369
- css2`
370
- form {
371
- display: grid;
372
- gap: var(--roxy-space-md, 1rem);
373
- background: var(--roxy-bg, #fff);
374
- border: 1px solid var(--roxy-border, #e4e4e7);
375
- border-radius: var(--roxy-radius-md, 8px);
376
- padding: var(--roxy-space-lg, 1.5rem);
377
- box-shadow: var(--roxy-shadow-sm);
378
- }
379
- .title {
380
- margin: 0;
381
- font-size: var(--roxy-text-lg, 1.125rem);
382
- font-weight: var(--roxy-weight-bold, 600);
383
- }
384
- .fields {
385
- display: grid;
386
- grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
387
- align-items: start;
388
- gap: var(--roxy-space-md, 1rem);
389
- }
390
- .field {
391
- display: flex;
392
- flex-direction: column;
393
- gap: var(--roxy-space-xs, 0.25rem);
394
- min-width: 0;
395
- }
396
- label {
397
- font-size: var(--roxy-text-sm, 0.875rem);
398
- color: var(--roxy-secondary, #475569);
399
- }
400
- label .req {
401
- color: var(--roxy-danger-fg, #991b1b);
402
- margin-left: 4px;
403
- }
404
- input,
405
- select {
406
- width: 100%;
407
- box-sizing: border-box;
408
- padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);
409
- font-size: var(--roxy-text-base, 1rem);
410
- font-family: inherit;
411
- color: var(--roxy-fg, #0a0a0a);
412
- background: var(--roxy-bg, #fff);
413
- border: 1px solid var(--roxy-border, #e4e4e7);
414
- border-radius: var(--roxy-radius-md, 8px);
415
- }
416
- input:focus,
417
- select:focus {
418
- outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
419
- outline-offset: 2px;
420
- border-color: var(--roxy-accent-fg, #b45309);
421
- }
422
- .help {
423
- color: var(--roxy-muted, #71717a);
424
- font-size: var(--roxy-text-xs, 0.75rem);
425
- }
426
- .location-block {
427
- display: grid;
428
- gap: var(--roxy-space-xs, 0.25rem);
429
- grid-column: 1 / -1;
430
- }
431
- .coords {
432
- display: grid;
433
- grid-template-columns: repeat(3, 1fr);
434
- gap: var(--roxy-space-sm, 0.5rem);
435
- }
436
- .coords input {
437
- font-size: var(--roxy-text-sm, 0.875rem);
438
- }
439
- button.submit {
440
- justify-self: start;
441
- background: var(--roxy-accent-fg, #b45309);
442
- color: var(--roxy-bg, #fff);
443
- border: 0;
444
- border-radius: var(--roxy-radius-md, 8px);
445
- padding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-lg, 1.5rem);
446
- font-size: var(--roxy-text-base, 1rem);
447
- font-weight: var(--roxy-weight-bold, 600);
448
- cursor: pointer;
449
- transition:
450
- transform var(--roxy-motion-duration, 200ms)
451
- var(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));
452
- }
453
- button.submit:hover {
454
- transform: scale(1.02);
455
- }
456
- button.submit:focus-visible {
457
- outline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));
458
- outline-offset: 2px;
459
- }
460
- .spec-error {
461
- display: grid;
462
- gap: var(--roxy-space-md, 1rem);
463
- justify-items: start;
464
- background: var(--roxy-bg, #fff);
465
- border: 1px solid var(--roxy-danger, #dc2626);
466
- border-radius: var(--roxy-radius-md, 8px);
467
- padding: var(--roxy-space-lg, 1.5rem);
468
- color: var(--roxy-danger-fg, #991b1b);
469
- font-size: var(--roxy-text-sm, 0.875rem);
470
- }
471
- `
472
- ];
473
- __decorateClass([
474
- property({ type: String, attribute: "data-endpoint" })
475
- ], RoxyEndpointForm.prototype, "endpoint", 2);
476
- __decorateClass([
477
- property({ type: String })
478
- ], RoxyEndpointForm.prototype, "method", 2);
479
- __decorateClass([
480
- property({ type: String, attribute: "spec-url" })
481
- ], RoxyEndpointForm.prototype, "specUrl", 2);
482
- __decorateClass([
483
- property({ type: String, attribute: "submit-label" })
484
- ], RoxyEndpointForm.prototype, "submitLabel", 2);
485
- __decorateClass([
486
- state()
487
- ], RoxyEndpointForm.prototype, "fields", 2);
488
- __decorateClass([
489
- state()
490
- ], RoxyEndpointForm.prototype, "values", 2);
491
- __decorateClass([
492
- state()
493
- ], RoxyEndpointForm.prototype, "hasLocation", 2);
494
- __decorateClass([
495
- state()
496
- ], RoxyEndpointForm.prototype, "loaded", 2);
497
- __decorateClass([
498
- state()
499
- ], RoxyEndpointForm.prototype, "specError", 2);
500
- RoxyEndpointForm = __decorateClass([
501
- customElement("roxy-endpoint-form")
502
- ], RoxyEndpointForm);
503
- export {
504
- RoxyEndpointForm
505
- };
1
+ var $=Object.defineProperty;var w=Object.getOwnPropertyDescriptor;var d=(l,o,r,e)=>{for(var t=e>1?void 0:e?w(o,r):o,a=l.length-1,s;a>=0;a--)(s=l[a])&&(t=(e?s(o,r,t):s(t))||t);return e&&t&&$(o,r,t),t};import{css as O,html as m,LitElement as z,nothing as h}from"lit";import{customElement as A,property as b,state as p}from"lit/decorators.js";import{css as k}from"lit";var x=k`:host{font-family:var(--roxy-font-sans,system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);color:var(--roxy-fg,#0a0a0a);font-size:var(--roxy-text-base,1rem);line-height:var(--roxy-leading-normal,1.5);animation:roxy-fade-in var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1)) both;background:0 0;display:block;container-type:inline-size}*,:before,:after{box-sizing:border-box}@keyframes roxy-fade-in{0%{opacity:0;transform:translateY(2px)}to{opacity:1;transform:translateY(0)}}@media (prefers-reduced-motion:reduce){:host{animation:none}}.roxy-skeleton{background:linear-gradient(90deg, var(--roxy-border,#e4e4e7) 0%, color-mix(in srgb, var(--roxy-border,#e4e4e7) 60%, transparent) 50%, var(--roxy-border,#e4e4e7) 100%);border-radius:var(--roxy-radius-md,8px);background-size:200% 100%;animation:1.4s ease-in-out infinite roxy-shimmer}@keyframes roxy-shimmer{0%{background-position:200% 0}to{background-position:-200% 0}}@media (prefers-reduced-motion:reduce){.roxy-skeleton{animation:none}}.roxy-empty{padding:var(--roxy-space-lg,1.5rem);color:var(--roxy-muted,#71717a);text-align:center;font-size:var(--roxy-text-sm,.875rem)}:host(:focus-within) .roxy-card{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px}:host{font-variant-emoji:text}`;function g(l){return l.replace(/[_-]+/g," ").replace(/([a-z])([A-Z])/g,"$1 $2").replace(/^\w/,o=>o.toUpperCase())}var y=new Map;async function q(l){let o=y.get(l);return o||(o=fetch(l).then(async r=>{if(!r.ok)throw new Error(`HTTP ${r.status}`);return await r.json()}).catch(r=>{throw y.delete(l),r}),y.set(l,o)),o}var n=class extends z{constructor(){super(...arguments);this.endpoint="vedic-astrology/birth-chart";this.method="POST";this.specUrl="https://roxyapi.com/api/v2/openapi.json";this.submitLabel="Submit";this.fields=[];this.values={};this.hasLocation=!1;this.loaded=!1;this.specError=null;this.retryLoadSchema=()=>{this.loaded=!1,this.specError=null,this.loadSchema()};this.onLocation=r=>{let e=r.detail;e&&(this.values={...this.values,latitude:e.latitude,longitude:e.longitude,timezone:e.timezone??e.utcOffset})};this.onSubmit=r=>{r.preventDefault();let e=this.fields.filter(t=>t.required).filter(t=>this.values[t.name]===void 0||this.values[t.name]==="");if(e.length>0){this.dispatchEvent(new CustomEvent("roxy-validation-error",{detail:{missing:e.map(t=>t.name)},bubbles:!0,composed:!0}));return}this.dispatchEvent(new CustomEvent("roxy-submit",{detail:{endpoint:this.endpoint,values:this.values},bubbles:!0,composed:!0}))}}connectedCallback(){super.connectedCallback(),this.loadSchema()}async loadSchema(){this.specError=null;try{let r=await q(this.specUrl),e=`/${this.endpoint.replace(/^\//,"")}`,t=r.paths?.[e]?.[this.method.toLowerCase()];if(!t)throw new Error(`Endpoint ${this.method} ${e} not found in OpenAPI spec`);let a=r.components?.schemas??{},s=[],f;if(t.requestBody){let i=t.requestBody.content?.["application/json"]?.schema;f=this.resolve(i,a)}if(f?.properties){let i=new Set(f.required??[]);for(let[c,S]of Object.entries(f.properties)){let u=this.resolve(S,a)??{};s.push({name:c,type:this.fieldType(u),required:i.has(c),description:u.description,enum:u.enum,min:u.minimum,max:u.maximum,default:u.default})}}for(let i of t.parameters??[])if(i.in==="path"||i.in==="query"){let c=this.resolve(i.schema,a)??{};s.push({name:i.name,type:this.fieldType(c),required:!!i.required,description:c.description,enum:c.enum,default:c.default})}this.fields=s,this.hasLocation=s.some(i=>i.name==="latitude")&&s.some(i=>i.name==="longitude")&&s.some(i=>i.name==="timezone");let v={};for(let i of s)i.default!==void 0&&(v[i.name]=i.default);this.values=v,this.loaded=!0}catch(r){let e=r instanceof Error?r.message:String(r);this.specError=e,this.loaded=!0,this.dispatchEvent(new CustomEvent("roxy-spec-error",{detail:{url:this.specUrl,message:e},bubbles:!0,composed:!0}))}}resolve(r,e){if(r){if("$ref"in r&&r.$ref){let t=r.$ref.split("/").pop();return t?e[t]:void 0}return r}}fieldType(r){return r.enum?"enum":r.format==="date"?"date":r.format==="time"?"time":r.format==="date-time"?"datetime":r.type==="integer"||r.type==="number"?"number":"text"}setValue(r,e){this.values={...this.values,[r]:e}}render(){if(!this.loaded)return m`<form><div class="roxy-skeleton" style="height:8rem"></div></form>`;if(this.specError)return m`<div class="spec-error" role="alert">Schema load failed: ${this.specError} <button type="button" class="submit" @click="${this.retryLoadSchema}">Retry</button></div>`;let r=e=>{if(this.hasLocation&&(e.name==="latitude"||e.name==="longitude"||e.name==="timezone"))return h;let t=`roxy-form-${e.name}`;return m`<div class="field"><label for="${t}">${g(e.name)}${e.required?m`<span class="req" aria-hidden="true">*</span>`:h}</label> ${e.enum?m`<select id="${t}" ?required="${e.required}" @change="${a=>this.setValue(e.name,a.target.value)}"><option value="">Choose</option>${e.enum.map(a=>m`<option value="${a}" ?selected="${this.values[e.name]===a}">${a}</option>`)}</select>`:m`<input id="${t}" type="${this.htmlType(e.type)}" ?required="${e.required}" min="${e.min??""}" max="${e.max??""}" step="${e.type==="number"?"any":""}" .value="${this.values[e.name]??""}" @input="${a=>this.setValue(e.name,this.coerce(e.type,a.target.value))}">`} ${e.description?m`<small class="help">${e.description}</small>`:h}</div>`};return m`<form @submit="${this.onSubmit}"><h2 class="title">${g(this.endpoint.split("/").pop()??"")}</h2>${this.hasLocation?m`<div class="location-block"><label>Birth location</label><roxy-location-search @roxy-location-select="${this.onLocation}" placeholder="City of birth"></roxy-location-search><small class="help">Required: latitude, longitude, timezone. Pick a city to autofill.</small></div>`:h}<div class="fields">${this.fields.map(e=>r(e))}</div><button class="submit" type="submit">${this.submitLabel}</button></form>`}htmlType(r){switch(r){case"date":return"date";case"time":return"time";case"datetime":return"datetime-local";case"number":return"number";default:return"text"}}coerce(r,e){if(e!==""){if(r==="number"){let t=Number(e);return Number.isFinite(t)?t:void 0}return e}}};n.styles=[x,O`form{gap:var(--roxy-space-md,1rem);background:var(--roxy-bg,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);box-shadow:var(--roxy-shadow-sm);display:grid}.title{font-size:var(--roxy-text-lg,1.125rem);font-weight:var(--roxy-weight-bold,600);margin:0}.fields{align-items:start;gap:var(--roxy-space-md,1rem);grid-template-columns:repeat(auto-fit,minmax(12rem,1fr));display:grid}.field{gap:var(--roxy-space-xs,.25rem);flex-direction:column;min-width:0;display:flex}label{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569)}label .req{color:var(--roxy-danger-fg,#991b1b);margin-left:4px}input,select{box-sizing:border-box;width:100%;padding:var(--roxy-space-sm,.5rem) var(--roxy-space-md,1rem);font-size:var(--roxy-text-base,1rem);color:var(--roxy-fg,#0a0a0a);background:var(--roxy-bg,#fff);border:1px solid var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-md,8px);font-family:inherit}input:focus,select:focus{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px;border-color:var(--roxy-accent-fg,#b45309)}.help{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-xs,.75rem)}.location-block{gap:var(--roxy-space-xs,.25rem);grid-column:1/-1;display:grid}.coords{gap:var(--roxy-space-sm,.5rem);grid-template-columns:repeat(3,1fr);display:grid}.coords input{font-size:var(--roxy-text-sm,.875rem)}button.submit{background:var(--roxy-accent-fg,#b45309);color:var(--roxy-bg,#fff);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-sm,.5rem) var(--roxy-space-lg,1.5rem);font-size:var(--roxy-text-base,1rem);font-weight:var(--roxy-weight-bold,600);cursor:pointer;transition:transform var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));border:0;justify-self:start}button.submit:hover{transform:scale(1.02)}button.submit:focus-visible{outline:2px solid var(--roxy-ring,#f59e0b66);outline-offset:2px}.spec-error{gap:var(--roxy-space-md,1rem);background:var(--roxy-bg,#fff);border:1px solid var(--roxy-danger,#dc2626);border-radius:var(--roxy-radius-md,8px);padding:var(--roxy-space-lg,1.5rem);color:var(--roxy-danger-fg,#991b1b);font-size:var(--roxy-text-sm,.875rem);justify-items:start;display:grid}`],d([b({type:String,attribute:"data-endpoint"})],n.prototype,"endpoint",2),d([b({type:String})],n.prototype,"method",2),d([b({type:String,attribute:"spec-url"})],n.prototype,"specUrl",2),d([b({type:String,attribute:"submit-label"})],n.prototype,"submitLabel",2),d([p()],n.prototype,"fields",2),d([p()],n.prototype,"values",2),d([p()],n.prototype,"hasLocation",2),d([p()],n.prototype,"loaded",2),d([p()],n.prototype,"specError",2),n=d([A("roxy-endpoint-form")],n);export{n as RoxyEndpointForm};
506
2
  //# sourceMappingURL=endpoint-form.js.map