@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,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/components/endpoint-form.ts", "../../src/utils/base-styles.ts", "../../src/utils/string.ts"],
4
- "sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\ninterface OpenApiSchemaRef {\n\t$ref?: string;\n}\n\ninterface OpenApiSchema extends OpenApiSchemaRef {\n\ttype?: string;\n\tformat?: string;\n\tdescription?: string;\n\tenum?: string[];\n\tdefault?: unknown;\n\tminimum?: number;\n\tmaximum?: number;\n\tproperties?: Record<string, OpenApiSchema>;\n\trequired?: string[];\n\titems?: OpenApiSchema;\n\texample?: unknown;\n}\n\ninterface FieldDef {\n\tname: string;\n\ttype: string;\n\trequired: boolean;\n\tdescription?: string;\n\tenum?: string[];\n\tmin?: number;\n\tmax?: number;\n\tdefault?: unknown;\n}\n\ninterface OpenApiDoc {\n\tpaths?: Record<string, Record<string, unknown>>;\n\tcomponents?: { schemas?: Record<string, OpenApiSchema> };\n}\n\nconst specCache = new Map<string, Promise<OpenApiDoc>>();\n\nasync function loadSpec(url: string): Promise<OpenApiDoc> {\n\tlet pending = specCache.get(url);\n\tif (!pending) {\n\t\tpending = fetch(url)\n\t\t\t.then(async (res) => {\n\t\t\t\tif (!res.ok) throw new Error(`HTTP ${res.status}`);\n\t\t\t\treturn (await res.json()) as OpenApiDoc;\n\t\t\t})\n\t\t\t.catch((err) => {\n\t\t\t\t// Evict the rejected promise BEFORE rethrowing so subsequent\n\t\t\t\t// callers (the user clicking Retry, a remount) hit the network\n\t\t\t\t// again instead of replaying the cached failure forever.\n\t\t\t\tspecCache.delete(url);\n\t\t\t\tthrow err;\n\t\t\t});\n\t\tspecCache.set(url, pending);\n\t}\n\treturn pending;\n}\n\n/**\n * Schema-driven form. Pass `endpoint` (e.g. \"vedic-astrology/birth-chart\").\n * The form introspects the cached OpenAPI spec, slots a roxy-location-search\n * when latitude+longitude+timezone fields are present, and emits a\n * `roxy-submit` CustomEvent with the validated payload on submit. The caller\n * decides what to do (call the SDK, render a chart, navigate).\n *\n * Build-time hints (x-roxy-ui formGroups) are read by scripts/build.ts and\n * baked into a static map. At runtime the component falls back to runtime\n * fetch of /api/v2/openapi.json when no map is provided.\n */\n@customElement('roxy-endpoint-form')\nexport class RoxyEndpointForm extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`\n\t\t\tform {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tbox-shadow: var(--roxy-shadow-sm);\n\t\t\t}\n\t\t\t.title {\n\t\t\t\tmargin: 0;\n\t\t\t\tfont-size: var(--roxy-text-lg, 1.125rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t}\n\t\t\t.fields {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));\n\t\t\t\talign-items: start;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t}\n\t\t\t.field {\n\t\t\t\tdisplay: flex;\n\t\t\t\tflex-direction: column;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t\tmin-width: 0;\n\t\t\t}\n\t\t\tlabel {\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t\tcolor: var(--roxy-secondary, #475569);\n\t\t\t}\n\t\t\tlabel .req {\n\t\t\t\tcolor: var(--roxy-danger-fg, #991b1b);\n\t\t\t\tmargin-left: 4px;\n\t\t\t}\n\t\t\tinput,\n\t\t\tselect {\n\t\t\t\twidth: 100%;\n\t\t\t\tbox-sizing: border-box;\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-md, 1rem);\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t\tfont-family: inherit;\n\t\t\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-border, #e4e4e7);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t}\n\t\t\tinput:focus,\n\t\t\tselect:focus {\n\t\t\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\t\t\toutline-offset: 2px;\n\t\t\t\tborder-color: var(--roxy-accent-fg, #b45309);\n\t\t\t}\n\t\t\t.help {\n\t\t\t\tcolor: var(--roxy-muted, #71717a);\n\t\t\t\tfont-size: var(--roxy-text-xs, 0.75rem);\n\t\t\t}\n\t\t\t.location-block {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-xs, 0.25rem);\n\t\t\t\tgrid-column: 1 / -1;\n\t\t\t}\n\t\t\t.coords {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgrid-template-columns: repeat(3, 1fr);\n\t\t\t\tgap: var(--roxy-space-sm, 0.5rem);\n\t\t\t}\n\t\t\t.coords input {\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t\tbutton.submit {\n\t\t\t\tjustify-self: start;\n\t\t\t\tbackground: var(--roxy-accent-fg, #b45309);\n\t\t\t\tcolor: var(--roxy-bg, #fff);\n\t\t\t\tborder: 0;\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tpadding: var(--roxy-space-sm, 0.5rem) var(--roxy-space-lg, 1.5rem);\n\t\t\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\t\t\tfont-weight: var(--roxy-weight-bold, 600);\n\t\t\t\tcursor: pointer;\n\t\t\t\ttransition:\n\t\t\t\t\ttransform var(--roxy-motion-duration, 200ms)\n\t\t\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));\n\t\t\t}\n\t\t\tbutton.submit:hover {\n\t\t\t\ttransform: scale(1.02);\n\t\t\t}\n\t\t\tbutton.submit:focus-visible {\n\t\t\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\t\t\toutline-offset: 2px;\n\t\t\t}\n\t\t\t.spec-error {\n\t\t\t\tdisplay: grid;\n\t\t\t\tgap: var(--roxy-space-md, 1rem);\n\t\t\t\tjustify-items: start;\n\t\t\t\tbackground: var(--roxy-bg, #fff);\n\t\t\t\tborder: 1px solid var(--roxy-danger, #dc2626);\n\t\t\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t\t\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\t\t\tcolor: var(--roxy-danger-fg, #991b1b);\n\t\t\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t\t\t}\n\t\t`,\n\t];\n\n\t@property({ type: String, attribute: 'data-endpoint' })\n\tendpoint = 'vedic-astrology/birth-chart';\n\n\t@property({ type: String })\n\tmethod: 'GET' | 'POST' = 'POST';\n\n\t@property({ type: String, attribute: 'spec-url' })\n\tspecUrl = 'https://roxyapi.com/api/v2/openapi.json';\n\n\t@property({ type: String, attribute: 'submit-label' })\n\tsubmitLabel = 'Submit';\n\n\t@state()\n\tprivate fields: FieldDef[] = [];\n\n\t@state()\n\tprivate values: Record<string, unknown> = {};\n\n\t@state()\n\tprivate hasLocation = false;\n\n\t@state()\n\tprivate loaded = false;\n\n\t@state()\n\tprivate specError: string | null = null;\n\n\tconnectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tvoid this.loadSchema();\n\t}\n\n\tprivate async loadSchema() {\n\t\tthis.specError = null;\n\t\ttry {\n\t\t\tconst spec = await loadSpec(this.specUrl);\n\t\t\tconst path = `/${this.endpoint.replace(/^\\//, '')}`;\n\t\t\tconst op = spec.paths?.[path]?.[this.method.toLowerCase()] as\n\t\t\t\t| {\n\t\t\t\t\t\trequestBody?: {\n\t\t\t\t\t\t\tcontent?: Record<\n\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\t{ schema?: OpenApiSchema | OpenApiSchemaRef }\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t};\n\t\t\t\t\t\tparameters?: Array<{\n\t\t\t\t\t\t\tname: string;\n\t\t\t\t\t\t\tin: string;\n\t\t\t\t\t\t\trequired?: boolean;\n\t\t\t\t\t\t\tschema?: OpenApiSchema;\n\t\t\t\t\t\t}>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!op) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Endpoint ${this.method} ${path} not found in OpenAPI spec`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst schemas = spec.components?.schemas ?? {};\n\t\t\tconst fields: FieldDef[] = [];\n\t\t\tlet bodySchema: OpenApiSchema | undefined;\n\n\t\t\tif (op.requestBody) {\n\t\t\t\tconst ref = op.requestBody.content?.['application/json']?.schema;\n\t\t\t\tbodySchema = this.resolve(ref, schemas);\n\t\t\t}\n\n\t\t\tif (bodySchema?.properties) {\n\t\t\t\tconst required = new Set(bodySchema.required ?? []);\n\t\t\t\tfor (const [name, sub] of Object.entries(bodySchema.properties)) {\n\t\t\t\t\tconst resolved = this.resolve(sub, schemas) ?? {};\n\t\t\t\t\tfields.push({\n\t\t\t\t\t\tname,\n\t\t\t\t\t\ttype: this.fieldType(resolved),\n\t\t\t\t\t\trequired: required.has(name),\n\t\t\t\t\t\tdescription: resolved.description,\n\t\t\t\t\t\tenum: resolved.enum,\n\t\t\t\t\t\tmin: resolved.minimum,\n\t\t\t\t\t\tmax: resolved.maximum,\n\t\t\t\t\t\tdefault: resolved.default,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const param of op.parameters ?? []) {\n\t\t\t\tif (param.in === 'path' || param.in === 'query') {\n\t\t\t\t\tconst resolved = this.resolve(param.schema, schemas) ?? {};\n\t\t\t\t\tfields.push({\n\t\t\t\t\t\tname: param.name,\n\t\t\t\t\t\ttype: this.fieldType(resolved),\n\t\t\t\t\t\trequired: !!param.required,\n\t\t\t\t\t\tdescription: resolved.description,\n\t\t\t\t\t\tenum: resolved.enum,\n\t\t\t\t\t\tdefault: resolved.default,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.fields = fields;\n\t\t\tthis.hasLocation =\n\t\t\t\tfields.some((f) => f.name === 'latitude') &&\n\t\t\t\tfields.some((f) => f.name === 'longitude') &&\n\t\t\t\tfields.some((f) => f.name === 'timezone');\n\n\t\t\t// Pre-fill defaults\n\t\t\tconst init: Record<string, unknown> = {};\n\t\t\tfor (const f of fields) {\n\t\t\t\tif (f.default !== undefined) init[f.name] = f.default;\n\t\t\t}\n\t\t\tthis.values = init;\n\t\t\tthis.loaded = true;\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthis.specError = message;\n\t\t\tthis.loaded = true;\n\t\t\tthis.dispatchEvent(\n\t\t\t\tnew CustomEvent('roxy-spec-error', {\n\t\t\t\t\tdetail: { url: this.specUrl, message },\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcomposed: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate retryLoadSchema = () => {\n\t\tthis.loaded = false;\n\t\tthis.specError = null;\n\t\tvoid this.loadSchema();\n\t};\n\n\tprivate resolve(\n\t\tschema: OpenApiSchema | OpenApiSchemaRef | undefined,\n\t\tall: Record<string, OpenApiSchema>,\n\t): OpenApiSchema | undefined {\n\t\tif (!schema) return undefined;\n\t\tif ('$ref' in schema && schema.$ref) {\n\t\t\tconst name = schema.$ref.split('/').pop();\n\t\t\treturn name ? all[name] : undefined;\n\t\t}\n\t\treturn schema as OpenApiSchema;\n\t}\n\n\tprivate fieldType(s: OpenApiSchema): string {\n\t\tif (s.enum) return 'enum';\n\t\tif (s.format === 'date') return 'date';\n\t\tif (s.format === 'time') return 'time';\n\t\tif (s.format === 'date-time') return 'datetime';\n\t\tif (s.type === 'integer' || s.type === 'number') return 'number';\n\t\treturn 'text';\n\t}\n\n\tprivate setValue(name: string, value: unknown) {\n\t\tthis.values = { ...this.values, [name]: value };\n\t}\n\n\tprivate onLocation = (e: Event) => {\n\t\tconst detail = (e as CustomEvent).detail as {\n\t\t\tlatitude?: number;\n\t\t\tlongitude?: number;\n\t\t\ttimezone?: string;\n\t\t\tutcOffset?: number;\n\t\t};\n\t\tif (detail) {\n\t\t\tthis.values = {\n\t\t\t\t...this.values,\n\t\t\t\tlatitude: detail.latitude,\n\t\t\t\tlongitude: detail.longitude,\n\t\t\t\ttimezone: detail.timezone ?? detail.utcOffset,\n\t\t\t};\n\t\t}\n\t};\n\n\tprivate onSubmit = (e: Event) => {\n\t\te.preventDefault();\n\t\tconst missing = this.fields\n\t\t\t.filter((f) => f.required)\n\t\t\t.filter(\n\t\t\t\t(f) => this.values[f.name] === undefined || this.values[f.name] === '',\n\t\t\t);\n\t\tif (missing.length > 0) {\n\t\t\tthis.dispatchEvent(\n\t\t\t\tnew CustomEvent('roxy-validation-error', {\n\t\t\t\t\tdetail: { missing: missing.map((m) => m.name) },\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcomposed: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-submit', {\n\t\t\t\tdetail: { endpoint: this.endpoint, values: this.values },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t};\n\n\trender() {\n\t\tif (!this.loaded) {\n\t\t\treturn html`<form><div class=\"roxy-skeleton\" style=\"height: 8rem\"></div></form>`;\n\t\t}\n\n\t\tif (this.specError) {\n\t\t\treturn html`<div class=\"spec-error\" role=\"alert\">\n\t\t\t\tSchema load failed: ${this.specError}\n\t\t\t\t<button type=\"button\" class=\"submit\" @click=${this.retryLoadSchema}>Retry</button>\n\t\t\t</div>`;\n\t\t}\n\n\t\tconst renderField = (f: FieldDef) => {\n\t\t\tif (\n\t\t\t\tthis.hasLocation &&\n\t\t\t\t(f.name === 'latitude' ||\n\t\t\t\t\tf.name === 'longitude' ||\n\t\t\t\t\tf.name === 'timezone')\n\t\t\t) {\n\t\t\t\treturn nothing;\n\t\t\t}\n\t\t\tconst inputId = `roxy-form-${f.name}`;\n\t\t\treturn html`<div class=\"field\">\n\t\t\t\t<label for=${inputId}>\n\t\t\t\t\t${humanize(f.name)}${f.required ? html`<span class=\"req\" aria-hidden=\"true\">*</span>` : nothing}\n\t\t\t\t</label>\n\t\t\t\t${\n\t\t\t\t\tf.enum\n\t\t\t\t\t\t? html`<select\n\t\t\t\t\t\t\tid=${inputId}\n\t\t\t\t\t\t\t?required=${f.required}\n\t\t\t\t\t\t\t@change=${(e: Event) => this.setValue(f.name, (e.target as HTMLSelectElement).value)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<option value=\"\">Choose</option>\n\t\t\t\t\t\t\t${f.enum.map(\n\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\topt,\n\t\t\t\t\t\t\t\t) => html`<option value=${opt} ?selected=${this.values[f.name] === opt}>\n\t\t\t\t\t\t\t\t\t${opt}\n\t\t\t\t\t\t\t\t</option>`,\n\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t</select>`\n\t\t\t\t\t\t: html`<input\n\t\t\t\t\t\t\tid=${inputId}\n\t\t\t\t\t\t\ttype=${this.htmlType(f.type)}\n\t\t\t\t\t\t\t?required=${f.required}\n\t\t\t\t\t\t\tmin=${f.min ?? ''}\n\t\t\t\t\t\t\tmax=${f.max ?? ''}\n\t\t\t\t\t\t\tstep=${f.type === 'number' ? 'any' : ''}\n\t\t\t\t\t\t\t.value=${(this.values[f.name] ?? '') as string}\n\t\t\t\t\t\t\t@input=${(e: Event) =>\n\t\t\t\t\t\t\t\tthis.setValue(\n\t\t\t\t\t\t\t\t\tf.name,\n\t\t\t\t\t\t\t\t\tthis.coerce(f.type, (e.target as HTMLInputElement).value),\n\t\t\t\t\t\t\t\t)}\n\t\t\t\t\t\t/>`\n\t\t\t\t}\n\t\t\t\t${f.description ? html`<small class=\"help\">${f.description}</small>` : nothing}\n\t\t\t</div>`;\n\t\t};\n\n\t\treturn html`<form @submit=${this.onSubmit}>\n\t\t\t<h2 class=\"title\">${humanize(this.endpoint.split('/').pop() ?? '')}</h2>\n\t\t\t${\n\t\t\t\tthis.hasLocation\n\t\t\t\t\t? html`<div class=\"location-block\">\n\t\t\t\t\t\t<label>Birth location</label>\n\t\t\t\t\t\t<roxy-location-search\n\t\t\t\t\t\t\t@roxy-location-select=${this.onLocation}\n\t\t\t\t\t\t\tplaceholder=\"City of birth\"\n\t\t\t\t\t\t></roxy-location-search>\n\t\t\t\t\t\t<small class=\"help\">\n\t\t\t\t\t\t\tRequired: latitude, longitude, timezone. Pick a city to autofill.\n\t\t\t\t\t\t</small>\n\t\t\t\t\t</div>`\n\t\t\t\t\t: nothing\n\t\t\t}\n\t\t\t<div class=\"fields\">\n\t\t\t\t${this.fields.map((f) => renderField(f))}\n\t\t\t</div>\n\t\t\t<button class=\"submit\" type=\"submit\">${this.submitLabel}</button>\n\t\t</form>`;\n\t}\n\n\tprivate htmlType(t: string): string {\n\t\tswitch (t) {\n\t\t\tcase 'date':\n\t\t\t\treturn 'date';\n\t\t\tcase 'time':\n\t\t\t\treturn 'time';\n\t\t\tcase 'datetime':\n\t\t\t\treturn 'datetime-local';\n\t\t\tcase 'number':\n\t\t\t\treturn 'number';\n\t\t\tdefault:\n\t\t\t\treturn 'text';\n\t\t}\n\t}\n\n\tprivate coerce(t: string, v: string): unknown {\n\t\tif (v === '') return undefined;\n\t\tif (t === 'number') {\n\t\t\tconst n = Number(v);\n\t\t\treturn Number.isFinite(n) ? n : undefined;\n\t\t}\n\t\treturn v;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-endpoint-form': RoxyEndpointForm;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`\n\t:host {\n\t\tdisplay: block;\n\t\tcontainer-type: inline-size;\n\t\tfont-family: var(\n\t\t\t--roxy-font-sans,\n\t\t\tsystem-ui,\n\t\t\t-apple-system,\n\t\t\tBlinkMacSystemFont,\n\t\t\t'Segoe UI',\n\t\t\tRoboto,\n\t\t\tsans-serif\n\t\t);\n\t\tcolor: var(--roxy-fg, #0a0a0a);\n\t\tbackground: transparent;\n\t\tfont-size: var(--roxy-text-base, 1rem);\n\t\tline-height: var(--roxy-leading-normal, 1.5);\n\t\tanimation: roxy-fade-in var(--roxy-motion-duration, 200ms)\n\t\t\tvar(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1)) both;\n\t}\n\n\t*,\n\t*::before,\n\t*::after {\n\t\tbox-sizing: border-box;\n\t}\n\n\t@keyframes roxy-fade-in {\n\t\tfrom {\n\t\t\topacity: 0;\n\t\t\ttransform: translateY(2px);\n\t\t}\n\t\tto {\n\t\t\topacity: 1;\n\t\t\ttransform: translateY(0);\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t:host {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-skeleton {\n\t\tbackground: linear-gradient(\n\t\t\t90deg,\n\t\t\tvar(--roxy-border, #e4e4e7) 0%,\n\t\t\tcolor-mix(in srgb, var(--roxy-border, #e4e4e7) 60%, transparent) 50%,\n\t\t\tvar(--roxy-border, #e4e4e7) 100%\n\t\t);\n\t\tbackground-size: 200% 100%;\n\t\tanimation: roxy-shimmer 1.4s ease-in-out infinite;\n\t\tborder-radius: var(--roxy-radius-md, 8px);\n\t}\n\n\t@keyframes roxy-shimmer {\n\t\t0% {\n\t\t\tbackground-position: 200% 0;\n\t\t}\n\t\t100% {\n\t\t\tbackground-position: -200% 0;\n\t\t}\n\t}\n\n\t@media (prefers-reduced-motion: reduce) {\n\t\t.roxy-skeleton {\n\t\t\tanimation: none;\n\t\t}\n\t}\n\n\t.roxy-empty {\n\t\tpadding: var(--roxy-space-lg, 1.5rem);\n\t\tcolor: var(--roxy-muted, #71717a);\n\t\ttext-align: center;\n\t\tfont-size: var(--roxy-text-sm, 0.875rem);\n\t}\n\n\t:host(:focus-within) .roxy-card {\n\t\toutline: 2px solid var(--roxy-ring, rgba(245, 158, 11, 0.4));\n\t\toutline-offset: 2px;\n\t}\n\n\t/* Force the text-style variant on every Unicode glyph in the component.\n\t * macOS and iOS substitute coloured emoji glyphs for the planetary and\n\t * gender Unicode code points (Mars, Venus, Mercury, etc.) when the\n\t * system colour-emoji font wins font selection. The text-style variant\n\t * keeps glyphs monochrome so they inherit the surrounding fill colour\n\t * and match the brand palette consistently across platforms.\n\t *\n\t * font-variant-emoji is part of CSS Fonts 4 (Safari 17+, Chrome 134+,\n\t * Firefox 139+). On older browsers the rule is silently ignored.\n\t */\n\t:host {\n\t\tfont-variant-emoji: text;\n\t}\n`;\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n"],
5
- "mappings": "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",
6
- "names": ["css", "css"]
4
+ "sourcesContent": ["import { css, html, LitElement, nothing } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\nimport { baseStyles } from '../utils/base-styles.js';\nimport { humanize } from '../utils/string.js';\n\ninterface OpenApiSchemaRef {\n\t$ref?: string;\n}\n\ninterface OpenApiSchema extends OpenApiSchemaRef {\n\ttype?: string;\n\tformat?: string;\n\tdescription?: string;\n\tenum?: string[];\n\tdefault?: unknown;\n\tminimum?: number;\n\tmaximum?: number;\n\tproperties?: Record<string, OpenApiSchema>;\n\trequired?: string[];\n\titems?: OpenApiSchema;\n\texample?: unknown;\n}\n\ninterface FieldDef {\n\tname: string;\n\ttype: string;\n\trequired: boolean;\n\tdescription?: string;\n\tenum?: string[];\n\tmin?: number;\n\tmax?: number;\n\tdefault?: unknown;\n}\n\ninterface OpenApiDoc {\n\tpaths?: Record<string, Record<string, unknown>>;\n\tcomponents?: { schemas?: Record<string, OpenApiSchema> };\n}\n\nconst specCache = new Map<string, Promise<OpenApiDoc>>();\n\nasync function loadSpec(url: string): Promise<OpenApiDoc> {\n\tlet pending = specCache.get(url);\n\tif (!pending) {\n\t\tpending = fetch(url)\n\t\t\t.then(async (res) => {\n\t\t\t\tif (!res.ok) throw new Error(`HTTP ${res.status}`);\n\t\t\t\treturn (await res.json()) as OpenApiDoc;\n\t\t\t})\n\t\t\t.catch((err) => {\n\t\t\t\t// Evict the rejected promise BEFORE rethrowing so subsequent\n\t\t\t\t// callers (the user clicking Retry, a remount) hit the network\n\t\t\t\t// again instead of replaying the cached failure forever.\n\t\t\t\tspecCache.delete(url);\n\t\t\t\tthrow err;\n\t\t\t});\n\t\tspecCache.set(url, pending);\n\t}\n\treturn pending;\n}\n\n/**\n * Schema-driven form. Pass `endpoint` (e.g. \"vedic-astrology/birth-chart\").\n * The form introspects the cached OpenAPI spec, slots a roxy-location-search\n * when latitude+longitude+timezone fields are present, and emits a\n * `roxy-submit` CustomEvent with the validated payload on submit. The caller\n * decides what to do (call the SDK, render a chart, navigate).\n *\n * Build-time hints (x-roxy-ui formGroups) are read by scripts/build.ts and\n * baked into a static map. At runtime the component falls back to runtime\n * fetch of /api/v2/openapi.json when no map is provided.\n */\n@customElement('roxy-endpoint-form')\nexport class RoxyEndpointForm extends LitElement {\n\tstatic styles = [\n\t\tbaseStyles,\n\t\tcss`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}`,\n\t];\n\n\t@property({ type: String, attribute: 'data-endpoint' })\n\tendpoint = 'vedic-astrology/birth-chart';\n\n\t@property({ type: String })\n\tmethod: 'GET' | 'POST' = 'POST';\n\n\t@property({ type: String, attribute: 'spec-url' })\n\tspecUrl = 'https://roxyapi.com/api/v2/openapi.json';\n\n\t@property({ type: String, attribute: 'submit-label' })\n\tsubmitLabel = 'Submit';\n\n\t@state()\n\tprivate fields: FieldDef[] = [];\n\n\t@state()\n\tprivate values: Record<string, unknown> = {};\n\n\t@state()\n\tprivate hasLocation = false;\n\n\t@state()\n\tprivate loaded = false;\n\n\t@state()\n\tprivate specError: string | null = null;\n\n\tconnectedCallback(): void {\n\t\tsuper.connectedCallback();\n\t\tvoid this.loadSchema();\n\t}\n\n\tprivate async loadSchema() {\n\t\tthis.specError = null;\n\t\ttry {\n\t\t\tconst spec = await loadSpec(this.specUrl);\n\t\t\tconst path = `/${this.endpoint.replace(/^\\//, '')}`;\n\t\t\tconst op = spec.paths?.[path]?.[this.method.toLowerCase()] as\n\t\t\t\t| {\n\t\t\t\t\t\trequestBody?: {\n\t\t\t\t\t\t\tcontent?: Record<\n\t\t\t\t\t\t\t\tstring,\n\t\t\t\t\t\t\t\t{ schema?: OpenApiSchema | OpenApiSchemaRef }\n\t\t\t\t\t\t\t>;\n\t\t\t\t\t\t};\n\t\t\t\t\t\tparameters?: Array<{\n\t\t\t\t\t\t\tname: string;\n\t\t\t\t\t\t\tin: string;\n\t\t\t\t\t\t\trequired?: boolean;\n\t\t\t\t\t\t\tschema?: OpenApiSchema;\n\t\t\t\t\t\t}>;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\tif (!op) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Endpoint ${this.method} ${path} not found in OpenAPI spec`,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst schemas = spec.components?.schemas ?? {};\n\t\t\tconst fields: FieldDef[] = [];\n\t\t\tlet bodySchema: OpenApiSchema | undefined;\n\n\t\t\tif (op.requestBody) {\n\t\t\t\tconst ref = op.requestBody.content?.['application/json']?.schema;\n\t\t\t\tbodySchema = this.resolve(ref, schemas);\n\t\t\t}\n\n\t\t\tif (bodySchema?.properties) {\n\t\t\t\tconst required = new Set(bodySchema.required ?? []);\n\t\t\t\tfor (const [name, sub] of Object.entries(bodySchema.properties)) {\n\t\t\t\t\tconst resolved = this.resolve(sub, schemas) ?? {};\n\t\t\t\t\tfields.push({\n\t\t\t\t\t\tname,\n\t\t\t\t\t\ttype: this.fieldType(resolved),\n\t\t\t\t\t\trequired: required.has(name),\n\t\t\t\t\t\tdescription: resolved.description,\n\t\t\t\t\t\tenum: resolved.enum,\n\t\t\t\t\t\tmin: resolved.minimum,\n\t\t\t\t\t\tmax: resolved.maximum,\n\t\t\t\t\t\tdefault: resolved.default,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const param of op.parameters ?? []) {\n\t\t\t\tif (param.in === 'path' || param.in === 'query') {\n\t\t\t\t\tconst resolved = this.resolve(param.schema, schemas) ?? {};\n\t\t\t\t\tfields.push({\n\t\t\t\t\t\tname: param.name,\n\t\t\t\t\t\ttype: this.fieldType(resolved),\n\t\t\t\t\t\trequired: !!param.required,\n\t\t\t\t\t\tdescription: resolved.description,\n\t\t\t\t\t\tenum: resolved.enum,\n\t\t\t\t\t\tdefault: resolved.default,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.fields = fields;\n\t\t\tthis.hasLocation =\n\t\t\t\tfields.some((f) => f.name === 'latitude') &&\n\t\t\t\tfields.some((f) => f.name === 'longitude') &&\n\t\t\t\tfields.some((f) => f.name === 'timezone');\n\n\t\t\t// Pre-fill defaults\n\t\t\tconst init: Record<string, unknown> = {};\n\t\t\tfor (const f of fields) {\n\t\t\t\tif (f.default !== undefined) init[f.name] = f.default;\n\t\t\t}\n\t\t\tthis.values = init;\n\t\t\tthis.loaded = true;\n\t\t} catch (err) {\n\t\t\tconst message = err instanceof Error ? err.message : String(err);\n\t\t\tthis.specError = message;\n\t\t\tthis.loaded = true;\n\t\t\tthis.dispatchEvent(\n\t\t\t\tnew CustomEvent('roxy-spec-error', {\n\t\t\t\t\tdetail: { url: this.specUrl, message },\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcomposed: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t}\n\t}\n\n\tprivate retryLoadSchema = () => {\n\t\tthis.loaded = false;\n\t\tthis.specError = null;\n\t\tvoid this.loadSchema();\n\t};\n\n\tprivate resolve(\n\t\tschema: OpenApiSchema | OpenApiSchemaRef | undefined,\n\t\tall: Record<string, OpenApiSchema>,\n\t): OpenApiSchema | undefined {\n\t\tif (!schema) return undefined;\n\t\tif ('$ref' in schema && schema.$ref) {\n\t\t\tconst name = schema.$ref.split('/').pop();\n\t\t\treturn name ? all[name] : undefined;\n\t\t}\n\t\treturn schema as OpenApiSchema;\n\t}\n\n\tprivate fieldType(s: OpenApiSchema): string {\n\t\tif (s.enum) return 'enum';\n\t\tif (s.format === 'date') return 'date';\n\t\tif (s.format === 'time') return 'time';\n\t\tif (s.format === 'date-time') return 'datetime';\n\t\tif (s.type === 'integer' || s.type === 'number') return 'number';\n\t\treturn 'text';\n\t}\n\n\tprivate setValue(name: string, value: unknown) {\n\t\tthis.values = { ...this.values, [name]: value };\n\t}\n\n\tprivate onLocation = (e: Event) => {\n\t\tconst detail = (e as CustomEvent).detail as {\n\t\t\tlatitude?: number;\n\t\t\tlongitude?: number;\n\t\t\ttimezone?: string;\n\t\t\tutcOffset?: number;\n\t\t};\n\t\tif (detail) {\n\t\t\tthis.values = {\n\t\t\t\t...this.values,\n\t\t\t\tlatitude: detail.latitude,\n\t\t\t\tlongitude: detail.longitude,\n\t\t\t\ttimezone: detail.timezone ?? detail.utcOffset,\n\t\t\t};\n\t\t}\n\t};\n\n\tprivate onSubmit = (e: Event) => {\n\t\te.preventDefault();\n\t\tconst missing = this.fields\n\t\t\t.filter((f) => f.required)\n\t\t\t.filter(\n\t\t\t\t(f) => this.values[f.name] === undefined || this.values[f.name] === '',\n\t\t\t);\n\t\tif (missing.length > 0) {\n\t\t\tthis.dispatchEvent(\n\t\t\t\tnew CustomEvent('roxy-validation-error', {\n\t\t\t\t\tdetail: { missing: missing.map((m) => m.name) },\n\t\t\t\t\tbubbles: true,\n\t\t\t\t\tcomposed: true,\n\t\t\t\t}),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\t\tthis.dispatchEvent(\n\t\t\tnew CustomEvent('roxy-submit', {\n\t\t\t\tdetail: { endpoint: this.endpoint, values: this.values },\n\t\t\t\tbubbles: true,\n\t\t\t\tcomposed: true,\n\t\t\t}),\n\t\t);\n\t};\n\n\trender() {\n\t\tif (!this.loaded) {\n\t\t\treturn html`<form><div class=\"roxy-skeleton\" style=\"height:8rem\"></div></form>`;\n\t\t}\n\n\t\tif (this.specError) {\n\t\t\treturn html`<div class=\"spec-error\" role=\"alert\">Schema load failed: ${this.specError} <button type=\"button\" class=\"submit\" @click=\"${this.retryLoadSchema}\">Retry</button></div>`;\n\t\t}\n\n\t\tconst renderField = (f: FieldDef) => {\n\t\t\tif (\n\t\t\t\tthis.hasLocation &&\n\t\t\t\t(f.name === 'latitude' ||\n\t\t\t\t\tf.name === 'longitude' ||\n\t\t\t\t\tf.name === 'timezone')\n\t\t\t) {\n\t\t\t\treturn nothing;\n\t\t\t}\n\t\t\tconst inputId = `roxy-form-${f.name}`;\n\t\t\treturn html`<div class=\"field\"><label for=\"${inputId}\">${humanize(f.name)}${f.required ? html`<span class=\"req\" aria-hidden=\"true\">*</span>` : nothing}</label> ${\n\t\t\t\t\tf.enum\n\t\t\t\t\t\t? html`<select id=\"${inputId}\" ?required=\"${f.required}\" @change=\"${(e: Event) => this.setValue(f.name, (e.target as HTMLSelectElement).value)}\"><option value=\"\">Choose</option>${f.enum.map(\n\t\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\t\topt,\n\t\t\t\t\t\t\t\t) => html`<option value=\"${opt}\" ?selected=\"${this.values[f.name] === opt}\">${opt}</option>`,\n\t\t\t\t\t\t\t)}</select>`\n\t\t\t\t\t\t: html`<input id=\"${inputId}\" type=\"${this.htmlType(f.type)}\" ?required=\"${f.required}\" min=\"${f.min ?? ''}\" max=\"${f.max ?? ''}\" step=\"${f.type === 'number' ? 'any' : ''}\" .value=\"${(this.values[f.name] ?? '') as string}\" @input=\"${(e: Event) =>\n\t\t\t\t\t\t\t\tthis.setValue(\n\t\t\t\t\t\t\t\t\tf.name,\n\t\t\t\t\t\t\t\t\tthis.coerce(f.type, (e.target as HTMLInputElement).value),\n\t\t\t\t\t\t\t\t)}\">`\n\t\t\t\t} ${f.description ? html`<small class=\"help\">${f.description}</small>` : nothing}</div>`;\n\t\t};\n\n\t\treturn html`<form @submit=\"${this.onSubmit}\"><h2 class=\"title\">${humanize(this.endpoint.split('/').pop() ?? '')}</h2>${\n\t\t\t\tthis.hasLocation\n\t\t\t\t\t? html`<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>`\n\t\t\t\t\t: nothing\n\t\t\t}<div class=\"fields\">${this.fields.map((f) => renderField(f))}</div><button class=\"submit\" type=\"submit\">${this.submitLabel}</button></form>`;\n\t}\n\n\tprivate htmlType(t: string): string {\n\t\tswitch (t) {\n\t\t\tcase 'date':\n\t\t\t\treturn 'date';\n\t\t\tcase 'time':\n\t\t\t\treturn 'time';\n\t\t\tcase 'datetime':\n\t\t\t\treturn 'datetime-local';\n\t\t\tcase 'number':\n\t\t\t\treturn 'number';\n\t\t\tdefault:\n\t\t\t\treturn 'text';\n\t\t}\n\t}\n\n\tprivate coerce(t: string, v: string): unknown {\n\t\tif (v === '') return undefined;\n\t\tif (t === 'number') {\n\t\t\tconst n = Number(v);\n\t\t\treturn Number.isFinite(n) ? n : undefined;\n\t\t}\n\t\treturn v;\n\t}\n}\n\ndeclare global {\n\tinterface HTMLElementTagNameMap {\n\t\t'roxy-endpoint-form': RoxyEndpointForm;\n\t}\n}\n", "import { css } from 'lit';\n\n/**\n * Shared host styles every component pulls in. Sets default font, color,\n * container query support, and the entry fade-in.\n */\nexport const baseStyles = css`: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}`;\n", "/**\n * Shared string helpers used across components. Single source of truth so the\n * same formatting rules apply to every key/label/title that surfaces in the\n * shadow tree.\n *\n * - `capitalize`: title-cases the first character, lowercases the rest. Used\n * when matching API-supplied planet/sign names against the glyph maps in\n * `tokens/index.ts`, which use canonical TitleCase keys.\n * - `humanize`: turns an API key (`birth_date`, `birthDate`, `mahadasha-end`)\n * into a label suitable for display (\"Birth date\", \"Mahadasha end\").\n */\n\nexport function capitalize(s: string): string {\n\tif (!s) return '';\n\treturn s.charAt(0).toUpperCase() + s.slice(1).toLowerCase();\n}\n\nexport function humanize(s: string): string {\n\treturn s\n\t\t.replace(/[_-]+/g, ' ')\n\t\t.replace(/([a-z])([A-Z])/g, '$1 $2')\n\t\t.replace(/^\\w/, (c) => c.toUpperCase());\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["css", "html", "LitElement", "nothing", "customElement", "property", "state", "css", "baseStyles", "humanize", "s", "c", "specCache", "loadSpec", "url", "pending", "res", "err", "RoxyEndpointForm", "LitElement", "e", "detail", "missing", "f", "m", "spec", "path", "op", "schemas", "fields", "bodySchema", "ref", "required", "name", "sub", "resolved", "param", "init", "message", "schema", "all", "s", "value", "html", "renderField", "nothing", "inputId", "humanize", "opt", "t", "v", "n", "baseStyles", "css", "__decorateClass", "property", "state", "customElement"]
7
7
  }
@@ -1,421 +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/guna-milan.ts
13
- import { css as css2, html, LitElement, nothing } from "lit";
14
- import { customElement, property } 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/format.ts
117
- function formatNumber(value, dp = 1) {
118
- if (typeof value !== "number" || !Number.isFinite(value)) return "";
119
- return value.toFixed(dp).replace(/\.?0+$/, "");
120
- }
121
- function formatPercent(value, dp = 1) {
122
- const n = formatNumber(value, dp);
123
- return n ? `${n}%` : "";
124
- }
125
-
126
- // packages/ui/src/utils/markup-data.ts
127
- var ROXY_DATA_CLASS = "roxy-data";
128
- function isJsonScript(el) {
129
- return el.nodeName === "SCRIPT" && el.getAttribute("type") === "application/json";
130
- }
131
- var MarkupDataController = class {
132
- constructor(host) {
133
- this.host = host;
134
- host.addController(this);
135
- }
136
- hostConnected() {
137
- if (this.host.data != null) return;
138
- const parsed = this.read();
139
- if (parsed === void 0) return;
140
- this.host.data = parsed;
141
- this.host.requestUpdate();
142
- }
143
- /**
144
- * Resolve the embedded payload. Returns `undefined` when there is nothing valid to read so the caller can leave `host.data` untouched.
145
- */
146
- read() {
147
- const inline = this.findInlineScript();
148
- return inline ? this.parse(inline.textContent) : void 0;
149
- }
150
- /**
151
- * Direct-child `<script type="application/json" class="roxy-data">`. Scoped to immediate children so a nested data-driven component never has its script read by an ancestor, and so sibling fallback markup is ignored.
152
- */
153
- findInlineScript() {
154
- for (const child of Array.from(this.host.children)) {
155
- if (isJsonScript(child) && child.classList.contains(ROXY_DATA_CLASS)) {
156
- return child;
157
- }
158
- }
159
- return null;
160
- }
161
- parse(text) {
162
- if (!text?.trim()) return void 0;
163
- try {
164
- return JSON.parse(text);
165
- } catch {
166
- return void 0;
167
- }
168
- }
169
- };
170
-
171
- // packages/ui/src/components/guna-milan.ts
172
- var STANDARD_CATEGORIES = [
173
- "Varna",
174
- "Vasya",
175
- "Tara",
176
- "Yoni",
177
- "Maitri",
178
- "Gana",
179
- "Bhakoot",
180
- "Nadi"
181
- ];
182
- var RoxyGunaMilan = class extends LitElement {
183
- constructor() {
184
- super();
185
- this.data = null;
186
- new MarkupDataController(this);
187
- }
188
- render() {
189
- const d = this.data;
190
- if (!d)
191
- return html`<div class="roxy-empty" role="status">No Guna Milan data</div>`;
192
- const breakdown = (d.breakdown ?? []).filter(
193
- (b) => b?.category !== void 0
194
- );
195
- const score = d.total ?? 0;
196
- const max = d.maxScore ?? 36;
197
- const pct = score / max * 100;
198
- const trackColor = "color-mix(in srgb, var(--roxy-border) 50%, transparent)";
199
- const fillColor = pct >= 70 ? "var(--roxy-success)" : pct >= 50 ? "var(--roxy-warning)" : "var(--roxy-danger)";
200
- const dashFill = pct * 2.827;
201
- const dashGap = (100 - pct) * 2.827;
202
- return html`<article class="card" aria-label="Guna Milan score">
203
- <div class="score-header">
204
- <div class="score-info">
205
- <div class="score-bar">
206
- <div>
207
- <span class="total">${formatNumber(d.total, 1)}</span>
208
- <span class="over"> / ${d.maxScore}</span>
209
- ${typeof d.percentage === "number" ? html`<small style="margin-left: 0.5rem; color: var(--roxy-muted)">
210
- ${formatPercent(d.percentage, 1)}
211
- </small>` : nothing}
212
- </div>
213
- ${d.recommendation ? html`<span class="recommendation">${d.recommendation}</span>` : nothing}
214
- </div>
215
- </div>
216
- <div class="score-ring" role="meter" aria-label="Guna milan score" aria-valuemin="0" aria-valuemax="36" aria-valuenow="${score}">
217
- <svg viewBox="0 0 100 100" aria-hidden="true">
218
- <circle class="ring-track" cx="50" cy="50" r="45" fill="none" stroke="${trackColor}" stroke-width="8"/>
219
- <circle class="ring-fill" cx="50" cy="50" r="45" fill="none" stroke="${fillColor}" stroke-width="8"
220
- stroke-dasharray="${dashFill},${dashGap}" stroke-linecap="round"
221
- transform="rotate(-90 50 50)"/>
222
- <text x="50" y="50" text-anchor="middle" dominant-baseline="central" class="ring-text">${score}</text>
223
- <text x="50" y="64" text-anchor="middle" dominant-baseline="central" class="ring-max">/${max}</text>
224
- </svg>
225
- </div>
226
- </div>
227
-
228
- ${breakdown.length > 0 ? html`<table>
229
- <thead>
230
- <tr>
231
- <th>Category</th>
232
- <th>Progress</th>
233
- <th class="score">Score</th>
234
- </tr>
235
- </thead>
236
- <tbody>
237
- ${breakdown.map((b) => {
238
- const score2 = b.score ?? 0;
239
- const maxScore = b.maxScore ?? defaultMax(b.category);
240
- const pct2 = maxScore ? score2 / maxScore * 100 : 0;
241
- return html`<tr>
242
- <td>${b.category}</td>
243
- <td class="bar-cell">
244
- <div class="mini-bar">
245
- <span style="width: ${pct2}%"></span>
246
- </div>
247
- </td>
248
- <td class="score">${formatNumber(score2, 1)} / ${maxScore}</td>
249
- </tr>`;
250
- })}
251
- </tbody>
252
- </table>` : nothing}
253
- ${(d.doshas?.length ?? 0) > 0 || (d.doshaCancellations?.length ?? 0) > 0 ? html`<div class="tags">
254
- ${d.doshas?.map((x) => html`<span class="dosha">${x}</span>`)}
255
- ${d.doshaCancellations?.map(
256
- (x) => html`<span class="cancel" title=${x.reason}>${x.dosha} cancelled</span>`
257
- )}
258
- </div>` : nothing}
259
- </article>`;
260
- }
261
- };
262
- RoxyGunaMilan.styles = [
263
- baseStyles,
264
- css2`
265
- .card {
266
- background: var(--roxy-bg, #fff);
267
- border: 1px solid var(--roxy-border, #e4e4e7);
268
- border-radius: var(--roxy-radius-md, 8px);
269
- padding: var(--roxy-space-lg, 1.5rem);
270
- box-shadow: var(--roxy-shadow-sm);
271
- display: grid;
272
- gap: var(--roxy-space-md, 1rem);
273
- }
274
-
275
- .score-header {
276
- display: flex;
277
- align-items: center;
278
- gap: 1rem;
279
- }
280
- .score-info {
281
- flex: 1;
282
- }
283
- .score-bar {
284
- display: grid;
285
- grid-template-columns: 1fr auto;
286
- align-items: center;
287
- gap: var(--roxy-space-md, 1rem);
288
- }
289
- .total {
290
- font-size: 2.25rem;
291
- font-weight: var(--roxy-weight-bold, 600);
292
- color: var(--roxy-accent-fg, #b45309);
293
- font-variant-numeric: tabular-nums;
294
- line-height: 1;
295
- }
296
- .over {
297
- color: var(--roxy-muted, #71717a);
298
- font-size: var(--roxy-text-base, 1rem);
299
- }
300
- .recommendation {
301
- font-size: var(--roxy-text-sm, 0.875rem);
302
- color: var(--roxy-secondary, #475569);
303
- }
304
- .score-ring {
305
- width: 120px;
306
- height: 120px;
307
- flex-shrink: 0;
308
- }
309
- .score-ring svg {
310
- width: 100%;
311
- height: 100%;
312
- }
313
- .score-ring .ring-text {
314
- font-size: 22px;
315
- font-weight: 700;
316
- fill: var(--roxy-fg, #0a0a0a);
317
- font-family: var(--roxy-font-sans);
318
- }
319
- .score-ring .ring-max {
320
- font-size: 10px;
321
- fill: var(--roxy-muted, #71717a);
322
- font-family: var(--roxy-font-sans);
323
- }
324
-
325
- table {
326
- width: 100%;
327
- border-collapse: collapse;
328
- font-size: var(--roxy-text-sm, 0.875rem);
329
- }
330
- th,
331
- td {
332
- padding: var(--roxy-space-sm, 0.5rem);
333
- border-bottom: 1px solid var(--roxy-border, #e4e4e7);
334
- text-align: left;
335
- }
336
- th {
337
- color: var(--roxy-muted, #71717a);
338
- font-weight: var(--roxy-weight-bold, 600);
339
- text-transform: uppercase;
340
- font-size: var(--roxy-text-xs, 0.75rem);
341
- letter-spacing: 0.06em;
342
- }
343
- td.score {
344
- text-align: right;
345
- font-variant-numeric: tabular-nums;
346
- color: var(--roxy-fg, #0a0a0a);
347
- font-weight: var(--roxy-weight-bold, 600);
348
- }
349
- td.bar-cell {
350
- width: 30%;
351
- }
352
- .mini-bar {
353
- height: 8px;
354
- background: var(--roxy-border, #e4e4e7);
355
- border-radius: var(--roxy-radius-full, 9999px);
356
- overflow: hidden;
357
- }
358
- .mini-bar > span {
359
- display: block;
360
- height: 100%;
361
- background: var(--roxy-accent, #f59e0b);
362
- transition:
363
- width var(--roxy-motion-duration, 200ms)
364
- var(--roxy-motion-easing, cubic-bezier(0.4, 0, 0.2, 1));
365
- }
366
-
367
- .tags {
368
- display: flex;
369
- flex-wrap: wrap;
370
- gap: var(--roxy-space-xs, 0.25rem);
371
- }
372
- .tags span {
373
- padding: 2px 8px;
374
- border-radius: var(--roxy-radius-full, 9999px);
375
- font-size: var(--roxy-text-xs, 0.75rem);
376
- }
377
- .tags .dosha {
378
- background: color-mix(in srgb, var(--roxy-danger, #dc2626) 16%, transparent);
379
- color: var(--roxy-danger-fg, #991b1b);
380
- }
381
- .tags .cancel {
382
- background: color-mix(in srgb, var(--roxy-success, #16a34a) 18%, transparent);
383
- color: var(--roxy-success-fg, #166534);
384
- }
385
- `
386
- ];
387
- __decorateClass([
388
- property({ attribute: false })
389
- ], RoxyGunaMilan.prototype, "data", 2);
390
- RoxyGunaMilan = __decorateClass([
391
- customElement("roxy-guna-milan")
392
- ], RoxyGunaMilan);
393
- function defaultMax(name) {
394
- if (!name) return 1;
395
- switch (name.toLowerCase()) {
396
- case "varna":
397
- return 1;
398
- case "vasya":
399
- return 2;
400
- case "tara":
401
- return 3;
402
- case "yoni":
403
- return 4;
404
- case "maitri":
405
- return 5;
406
- case "gana":
407
- return 6;
408
- case "bhakoot":
409
- return 7;
410
- case "nadi":
411
- return 8;
412
- default:
413
- return 1;
414
- }
415
- }
416
- var GUNA_CATEGORIES = STANDARD_CATEGORIES;
417
- export {
418
- GUNA_CATEGORIES,
419
- RoxyGunaMilan
420
- };
1
+ var $=Object.defineProperty;var S=Object.getOwnPropertyDescriptor;var f=(t,r,e,i)=>{for(var a=i>1?void 0:i?S(r,e):r,c=t.length-1,s;c>=0;c--)(s=t[c])&&(a=(i?s(r,e,a):s(a))||a);return i&&a&&$(r,e,a),a};import{css as N,html as n,LitElement as A,nothing as x}from"lit";import{customElement as E,property as D}from"lit/decorators.js";import{css as T}from"lit";var g=T`: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 l(t,r=1){return typeof t!="number"||!Number.isFinite(t)?"":t.toFixed(r).replace(/\.?0+$/,"")}function y(t,r=1){let e=l(t,r);return e?`${e}%`:""}var C="roxy-data";function z(t){return t.nodeName==="SCRIPT"&&t.getAttribute("type")==="application/json"}var m=class{constructor(r){this.host=r,r.addController(this)}hostConnected(){if(this.host.data!=null)return;let r=this.read();r!==void 0&&(this.host.data=r,this.host.requestUpdate())}read(){let r=this.findInlineScript();return r?this.parse(r.textContent):void 0}findInlineScript(){for(let r of Array.from(this.host.children))if(z(r)&&r.classList.contains(C))return r;return null}parse(r){if(r?.trim())try{return JSON.parse(r)}catch{return}}};var L=["Varna","Vasya","Tara","Yoni","Maitri","Gana","Bhakoot","Nadi"],d=class extends A{constructor(){super();this.data=null;new m(this)}render(){let e=this.data;if(!e)return n`<div class="roxy-empty" role="status">No Guna Milan data</div>`;let i=(e.breakdown??[]).filter(o=>o?.category!==void 0),a=e.total??0,c=e.maxScore??36,s=a/c*100,h="color-mix(in srgb, var(--roxy-border) 50%, transparent)",v=s>=70?"var(--roxy-success)":s>=50?"var(--roxy-warning)":"var(--roxy-danger)",b=s*2.827,w=(100-s)*2.827;return n`<article class="card" aria-label="Guna Milan score"><div class="score-header"><div class="score-info"><div class="score-bar"><div><span class="total">${l(e.total,1)}</span> <span class="over">/ ${e.maxScore}</span> ${typeof e.percentage=="number"?n`<small style="margin-left:.5rem;color:var(--roxy-muted)">${y(e.percentage,1)}</small>`:x}</div>${e.recommendation?n`<span class="recommendation">${e.recommendation}</span>`:x}</div></div><div class="score-ring" role="meter" aria-label="Guna milan score" aria-valuemin="0" aria-valuemax="36" aria-valuenow="${a}"><svg viewBox="0 0 100 100" aria-hidden="true"><circle class="ring-track" cx="50" cy="50" r="45" fill="none" stroke="${h}" stroke-width="8"/><circle class="ring-fill" cx="50" cy="50" r="45" fill="none" stroke="${v}" stroke-width="8" stroke-dasharray="${b},${w}" stroke-linecap="round" transform="rotate(-90 50 50)"/><text x="50" y="50" text-anchor="middle" dominant-baseline="central" class="ring-text">${a}</text><text x="50" y="64" text-anchor="middle" dominant-baseline="central" class="ring-max">/${c}</text></svg></div></div>${i.length>0?n`<table><thead><tr><th>Category</th><th>Progress</th><th class="score">Score</th></tr></thead><tbody>${i.map(o=>{let p=o.score??0,u=o.maxScore??R(o.category),k=u?p/u*100:0;return n`<tr><td>${o.category}</td><td class="bar-cell"><div class="mini-bar"><span style="width:${k}%"></span></div></td><td class="score">${l(p,1)} / ${u}</td></tr>`})}</tbody></table>`:x} ${(e.doshas?.length??0)>0||(e.doshaCancellations?.length??0)>0?n`<div class="tags">${e.doshas?.map(o=>n`<span class="dosha">${o}</span>`)} ${e.doshaCancellations?.map(o=>n`<span class="cancel" title="${o.reason}">${o.dosha} cancelled</span>`)}</div>`:x}</article>`}};d.styles=[g,N`.card{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);gap:var(--roxy-space-md,1rem);display:grid}.score-header{align-items:center;gap:1rem;display:flex}.score-info{flex:1}.score-bar{align-items:center;gap:var(--roxy-space-md,1rem);grid-template-columns:1fr auto;display:grid}.total{font-size:2.25rem;font-weight:var(--roxy-weight-bold,600);color:var(--roxy-accent-fg,#b45309);font-variant-numeric:tabular-nums;line-height:1}.over{color:var(--roxy-muted,#71717a);font-size:var(--roxy-text-base,1rem)}.recommendation{font-size:var(--roxy-text-sm,.875rem);color:var(--roxy-secondary,#475569)}.score-ring{flex-shrink:0;width:120px;height:120px}.score-ring svg{width:100%;height:100%}.score-ring .ring-text{fill:var(--roxy-fg,#0a0a0a);font-size:22px;font-weight:700;font-family:var(--roxy-font-sans)}.score-ring .ring-max{fill:var(--roxy-muted,#71717a);font-size:10px;font-family:var(--roxy-font-sans)}table{border-collapse:collapse;width:100%;font-size:var(--roxy-text-sm,.875rem)}th,td{padding:var(--roxy-space-sm,.5rem);border-bottom:1px solid var(--roxy-border,#e4e4e7);text-align:left}th{color:var(--roxy-muted,#71717a);font-weight:var(--roxy-weight-bold,600);text-transform:uppercase;font-size:var(--roxy-text-xs,.75rem);letter-spacing:.06em}td.score{text-align:right;font-variant-numeric:tabular-nums;color:var(--roxy-fg,#0a0a0a);font-weight:var(--roxy-weight-bold,600)}td.bar-cell{width:30%}.mini-bar{background:var(--roxy-border,#e4e4e7);border-radius:var(--roxy-radius-full,9999px);height:8px;overflow:hidden}.mini-bar>span{background:var(--roxy-accent,#f59e0b);height:100%;transition:width var(--roxy-motion-duration,.2s) var(--roxy-motion-easing,cubic-bezier(.4, 0, .2, 1));display:block}.tags{gap:var(--roxy-space-xs,.25rem);flex-wrap:wrap;display:flex}.tags span{border-radius:var(--roxy-radius-full,9999px);font-size:var(--roxy-text-xs,.75rem);padding:2px 8px}.tags .dosha{background:color-mix(in srgb, var(--roxy-danger,#dc2626) 16%, transparent);color:var(--roxy-danger-fg,#991b1b)}.tags .cancel{background:color-mix(in srgb, var(--roxy-success,#16a34a) 18%, transparent);color:var(--roxy-success-fg,#166534)}`],f([D({attribute:!1})],d.prototype,"data",2),d=f([E("roxy-guna-milan")],d);function R(t){if(!t)return 1;switch(t.toLowerCase()){case"varna":return 1;case"vasya":return 2;case"tara":return 3;case"yoni":return 4;case"maitri":return 5;case"gana":return 6;case"bhakoot":return 7;case"nadi":return 8;default:return 1}}var q=L;export{q as GUNA_CATEGORIES,d as RoxyGunaMilan};
421
2
  //# sourceMappingURL=guna-milan.js.map