@fpkit/acss 0.6.2 → 1.0.0-beta.1

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 (109) hide show
  1. package/libs/components/alert/alert.css +1 -1
  2. package/libs/components/alert/alert.css.map +1 -1
  3. package/libs/components/alert/alert.min.css +2 -2
  4. package/libs/components/badge/badge.css +1 -1
  5. package/libs/components/badge/badge.css.map +1 -1
  6. package/libs/components/badge/badge.min.css +2 -2
  7. package/libs/components/breadcrumbs/breadcrumb.css +1 -1
  8. package/libs/components/breadcrumbs/breadcrumb.css.map +1 -1
  9. package/libs/components/breadcrumbs/breadcrumb.min.css +2 -2
  10. package/libs/components/buttons/button.css +1 -1
  11. package/libs/components/buttons/button.css.map +1 -1
  12. package/libs/components/buttons/button.min.css +2 -2
  13. package/libs/components/cards/card.css +1 -1
  14. package/libs/components/cards/card.css.map +1 -1
  15. package/libs/components/cards/card.min.css +2 -2
  16. package/libs/components/details/details.css +1 -1
  17. package/libs/components/details/details.css.map +1 -1
  18. package/libs/components/details/details.min.css +2 -2
  19. package/libs/components/dialog/dialog.css +1 -1
  20. package/libs/components/dialog/dialog.css.map +1 -1
  21. package/libs/components/dialog/dialog.min.css +2 -2
  22. package/libs/components/form/form.css +1 -1
  23. package/libs/components/form/form.css.map +1 -1
  24. package/libs/components/form/form.min.css +2 -2
  25. package/libs/components/icons/icon.d.cts +32 -32
  26. package/libs/components/icons/icon.d.ts +32 -32
  27. package/libs/components/images/img.css +1 -1
  28. package/libs/components/images/img.css.map +1 -1
  29. package/libs/components/images/img.min.css +2 -2
  30. package/libs/components/layout/landmarks.css +1 -1
  31. package/libs/components/layout/landmarks.css.map +1 -1
  32. package/libs/components/layout/landmarks.min.css +2 -2
  33. package/libs/components/link/link.css +1 -1
  34. package/libs/components/link/link.css.map +1 -1
  35. package/libs/components/link/link.min.css +2 -2
  36. package/libs/components/nav/nav.css +1 -1
  37. package/libs/components/nav/nav.css.map +1 -1
  38. package/libs/components/nav/nav.min.css +2 -2
  39. package/libs/components/progress/progress.css +1 -1
  40. package/libs/components/progress/progress.css.map +1 -1
  41. package/libs/components/progress/progress.min.css +2 -2
  42. package/libs/components/tag/tag.css +1 -1
  43. package/libs/components/tag/tag.css.map +1 -1
  44. package/libs/components/tag/tag.min.css +2 -2
  45. package/libs/index.css +1 -1
  46. package/libs/index.css.map +1 -1
  47. package/package.json +1 -1
  48. package/src/components/alert/alert.scss +4 -4
  49. package/src/components/alert/alert.scss.backup +184 -0
  50. package/src/components/alert/alert.stories.tsx +53 -2
  51. package/src/components/badge/badge.scss +2 -2
  52. package/src/components/badge/badge.scss.backup +39 -0
  53. package/src/components/badge/badge.stories.tsx +40 -0
  54. package/src/components/breadcrumbs/breadcrumb.scss +5 -5
  55. package/src/components/breadcrumbs/breadcrumb.scss.backup +35 -0
  56. package/src/components/breadcrumbs/breadcrumb.stories.tsx +17 -1
  57. package/src/components/buttons/button.scss +27 -27
  58. package/src/components/buttons/button.scss.backup +145 -0
  59. package/src/components/buttons/button.stories.tsx +188 -2
  60. package/src/components/cards/card.scss +39 -5
  61. package/src/components/cards/card.scss.backup +67 -0
  62. package/src/components/cards/card.stories.tsx +183 -0
  63. package/src/components/details/details.scss +14 -14
  64. package/src/components/details/details.scss.backup +126 -0
  65. package/src/components/details/details.stories.tsx +40 -0
  66. package/src/components/dialog/dialog.scss +3 -3
  67. package/src/components/dialog/dialog.scss.backup +126 -0
  68. package/src/components/form/form.scss +25 -9
  69. package/src/components/form/form.scss.backup +87 -0
  70. package/src/components/form/form.stories.tsx +271 -0
  71. package/src/components/form/input.stories.tsx +158 -0
  72. package/src/components/images/figure.stories.tsx +41 -1
  73. package/src/components/images/img.scss +8 -8
  74. package/src/components/images/img.scss.backup +59 -0
  75. package/src/components/layout/_header.scss +14 -14
  76. package/src/components/layout/_header.scss.backup +72 -0
  77. package/src/components/layout/landmarks.scss +7 -7
  78. package/src/components/layout/landmarks.scss.backup +51 -0
  79. package/src/components/layout/landmarks.stories.tsx +42 -0
  80. package/src/components/link/link.scss +5 -5
  81. package/src/components/link/link.scss.backup +145 -0
  82. package/src/components/link/link.stories.tsx +38 -2
  83. package/src/components/nav/nav.scss +17 -17
  84. package/src/components/nav/nav.scss.backup +123 -0
  85. package/src/components/nav/nav.stories.tsx +35 -1
  86. package/src/components/progress/progress.scss +7 -7
  87. package/src/components/progress/progress.scss.backup +70 -0
  88. package/src/components/tag/tag.scss +10 -10
  89. package/src/components/tag/tag.scss.backup +130 -0
  90. package/src/components/tag/tag.stories.tsx +23 -2
  91. package/src/styles/alert/alert.css +4 -4
  92. package/src/styles/badge/badge.css +2 -2
  93. package/src/styles/breadcrumbs/breadcrumb.css +5 -5
  94. package/src/styles/buttons/button.css +26 -27
  95. package/src/styles/buttons/button.css.map +1 -1
  96. package/src/styles/cards/card.css +35 -5
  97. package/src/styles/cards/card.css.map +1 -1
  98. package/src/styles/details/details.css +14 -14
  99. package/src/styles/dialog/dialog.css +3 -3
  100. package/src/styles/form/form.css +20 -10
  101. package/src/styles/form/form.css.map +1 -1
  102. package/src/styles/images/img.css +8 -8
  103. package/src/styles/index.css +170 -131
  104. package/src/styles/index.css.map +1 -1
  105. package/src/styles/layout/landmarks.css +21 -21
  106. package/src/styles/link/link.css +5 -5
  107. package/src/styles/nav/nav.css +17 -17
  108. package/src/styles/progress/progress.css +6 -6
  109. package/src/styles/tag/tag.css +4 -4
@@ -628,3 +628,274 @@ export const WithOnEnterHandler: Story = {
628
628
  });
629
629
  },
630
630
  };
631
+
632
+ /**
633
+ * CSS Variable Customization
634
+ *
635
+ * Demonstrates how to customize form/input appearance using the new standardized
636
+ * CSS custom property naming convention.
637
+ *
638
+ * New variable naming patterns:
639
+ * - Logical properties: `--input-padding-inline`, `--input-padding-block`
640
+ * - Full property names: `--input-width`, `--input-radius`, `--input-border`
641
+ * - Approved abbreviations: `--input-fs` (font-size), `--input-bg` (background)
642
+ * - State variables: `--input-focus-outline`, `--input-disabled-bg`
643
+ */
644
+ export const Customization: Story = {
645
+ render: () => (
646
+ <div style={{ display: 'flex', flexDirection: 'column', gap: '2rem' }}>
647
+ {/* Custom input styling */}
648
+ <div>
649
+ <h4>Custom Input Styling</h4>
650
+ <FormComponent aria-label="Custom input example">
651
+ <FormComponent.Field label="Name" labelFor="custom-name">
652
+ <FormComponent.Input
653
+ id="custom-name"
654
+ name="name"
655
+ placeholder="Enter your name"
656
+ styles={{
657
+ "--input-padding-inline": "1.5rem",
658
+ "--input-padding-block": "0.75rem",
659
+ "--input-fs": "1.125rem",
660
+ "--input-radius": "0.5rem",
661
+ "--input-border": "2px solid #0066cc",
662
+ }}
663
+ />
664
+ </FormComponent.Field>
665
+ </FormComponent>
666
+ </div>
667
+
668
+ {/* Compact form */}
669
+ <div>
670
+ <h4>Compact Form</h4>
671
+ <FormComponent aria-label="Compact form example">
672
+ <FormComponent.Field label="Email" labelFor="compact-email">
673
+ <FormComponent.Input
674
+ id="compact-email"
675
+ name="email"
676
+ type="email"
677
+ styles={{
678
+ "--input-padding-inline": "0.75rem",
679
+ "--input-padding-block": "0.5rem",
680
+ "--input-fs": "0.875rem",
681
+ "--input-radius": "0.25rem",
682
+ }}
683
+ />
684
+ </FormComponent.Field>
685
+ </FormComponent>
686
+ </div>
687
+
688
+ {/* Custom focus states */}
689
+ <div>
690
+ <h4>Custom Focus States</h4>
691
+ <FormComponent aria-label="Focus state example">
692
+ <FormComponent.Field label="Username" labelFor="focus-username">
693
+ <FormComponent.Input
694
+ id="focus-username"
695
+ name="username"
696
+ placeholder="Try focusing this input"
697
+ styles={{
698
+ "--input-focus-outline": "3px solid #0066cc",
699
+ "--input-focus-outline-offset": "2px",
700
+ "--input-border": "2px solid #ddd",
701
+ }}
702
+ />
703
+ </FormComponent.Field>
704
+ </FormComponent>
705
+ </div>
706
+
707
+ {/* Custom textarea */}
708
+ <div>
709
+ <h4>Custom Textarea</h4>
710
+ <FormComponent aria-label="Textarea example">
711
+ <FormComponent.Field label="Message" labelFor="custom-message">
712
+ <FormComponent.Textarea
713
+ id="custom-message"
714
+ name="message"
715
+ placeholder="Enter your message"
716
+ rows={4}
717
+ styles={{
718
+ "--input-padding-inline": "1rem",
719
+ "--input-padding-block": "1rem",
720
+ "--input-fs": "1rem",
721
+ "--input-radius": "0.75rem",
722
+ "--input-border": "1px solid #ccc",
723
+ "--input-width": "100%",
724
+ }}
725
+ />
726
+ </FormComponent.Field>
727
+ </FormComponent>
728
+ </div>
729
+
730
+ {/* Custom select */}
731
+ <div>
732
+ <h4>Custom Select</h4>
733
+ <FormComponent aria-label="Select example">
734
+ <FormComponent.Field label="Country" labelFor="custom-country">
735
+ <FormComponent.Select
736
+ id="custom-country"
737
+ name="country"
738
+ styles={{
739
+ "--input-padding-inline": "1.25rem",
740
+ "--input-padding-block": "0.625rem",
741
+ "--input-fs": "1rem",
742
+ "--input-radius": "0.5rem",
743
+ "--input-border": "2px solid #28a745",
744
+ "--input-bg": "#f0f9f4",
745
+ }}
746
+ >
747
+ <FormComponent.Select.Option value="">Select country</FormComponent.Select.Option>
748
+ <FormComponent.Select.Option value="us">United States</FormComponent.Select.Option>
749
+ <FormComponent.Select.Option value="ca">Canada</FormComponent.Select.Option>
750
+ <FormComponent.Select.Option value="uk">United Kingdom</FormComponent.Select.Option>
751
+ </FormComponent.Select>
752
+ </FormComponent.Field>
753
+ </FormComponent>
754
+ </div>
755
+
756
+ {/* Dark theme example */}
757
+ <div
758
+ style={{
759
+ background: "#1a1a1a",
760
+ padding: "1.5rem",
761
+ borderRadius: "0.5rem",
762
+ }}
763
+ >
764
+ <h4 style={{ color: "white", marginTop: 0 }}>Dark Theme Example</h4>
765
+ <FormComponent aria-label="Dark theme form">
766
+ <FormComponent.Field label="Email" labelFor="dark-email">
767
+ <FormComponent.Input
768
+ id="dark-email"
769
+ name="email"
770
+ type="email"
771
+ placeholder="email@example.com"
772
+ styles={{
773
+ "--input-bg": "#2a2a2a",
774
+ "--input-color": "#e5e7eb",
775
+ "--input-border": "1px solid #4b5563",
776
+ "--input-padding-inline": "1rem",
777
+ "--input-padding-block": "0.75rem",
778
+ "--input-radius": "0.5rem",
779
+ "--input-focus-outline": "2px solid #3b82f6",
780
+ "--placeholder-color": "#9ca3af",
781
+ }}
782
+ />
783
+ </FormComponent.Field>
784
+ <FormComponent.Field label="Comments" labelFor="dark-comments" style={{ marginTop: "1rem" }}>
785
+ <FormComponent.Textarea
786
+ id="dark-comments"
787
+ name="comments"
788
+ placeholder="Your feedback..."
789
+ rows={3}
790
+ styles={{
791
+ "--input-bg": "#2a2a2a",
792
+ "--input-color": "#e5e7eb",
793
+ "--input-border": "1px solid #4b5563",
794
+ "--input-padding-inline": "1rem",
795
+ "--input-padding-block": "0.75rem",
796
+ "--input-radius": "0.5rem",
797
+ "--input-focus-outline": "2px solid #3b82f6",
798
+ "--placeholder-color": "#9ca3af",
799
+ }}
800
+ />
801
+ </FormComponent.Field>
802
+ </FormComponent>
803
+ </div>
804
+
805
+ {/* Disabled state customization */}
806
+ <div>
807
+ <h4>Custom Disabled State</h4>
808
+ <FormComponent aria-label="Disabled state example">
809
+ <FormComponent.Field label="Disabled Input" labelFor="disabled-custom">
810
+ <FormComponent.Input
811
+ id="disabled-custom"
812
+ name="disabled"
813
+ disabled
814
+ value="This input is disabled"
815
+ styles={{
816
+ "--input-disabled-bg": "#f5f5f5",
817
+ "--input-disabled-opacity": "0.6",
818
+ "--input-padding-inline": "1rem",
819
+ "--input-padding-block": "0.75rem",
820
+ }}
821
+ />
822
+ </FormComponent.Field>
823
+ </FormComponent>
824
+ </div>
825
+ </div>
826
+ ),
827
+ parameters: {
828
+ docs: {
829
+ description: {
830
+ story: `
831
+ ## Available CSS Variables
832
+
833
+ ### Base Properties
834
+ - \`--input-padding-inline\`: Horizontal padding (logical property)
835
+ - \`--input-padding-block\`: Vertical padding (logical property)
836
+ - \`--input-width\`: Input width
837
+ - \`--input-radius\`: Border radius
838
+ - \`--input-color\`: Text color
839
+ - \`--input-bg\`: Background color
840
+ - \`--input-border\`: Border style
841
+
842
+ ### Typography (Approved Abbreviations)
843
+ - \`--input-fs\`: Font size
844
+
845
+ ### Focus State Variables
846
+ - \`--input-focus-outline\`: Outline on focus
847
+ - \`--input-focus-outline-offset\`: Outline offset on focus
848
+
849
+ ### Disabled State Variables
850
+ - \`--input-disabled-bg\`: Background color when disabled
851
+ - \`--input-disabled-opacity\`: Opacity when disabled
852
+
853
+ ### Placeholder Variables
854
+ - \`--placeholder-fs\`: Placeholder font size
855
+ - \`--placeholder-color\`: Placeholder text color
856
+
857
+ ### Migration from Old Names
858
+ - ❌ \`--input-px\` → ✅ \`--input-padding-inline\`
859
+ - ❌ \`--input-py\` → ✅ \`--input-padding-block\`
860
+ - ❌ \`--input-w\` → ✅ \`--input-width\`
861
+
862
+ ## Usage Examples
863
+
864
+ ### Custom Input
865
+ \`\`\`tsx
866
+ <Form.Input
867
+ styles={{
868
+ "--input-padding-inline": "1.5rem",
869
+ "--input-padding-block": "0.75rem",
870
+ "--input-fs": "1.125rem",
871
+ "--input-radius": "0.5rem",
872
+ }}
873
+ />
874
+ \`\`\`
875
+
876
+ ### Custom Focus State
877
+ \`\`\`tsx
878
+ <Form.Input
879
+ styles={{
880
+ "--input-focus-outline": "3px solid #0066cc",
881
+ "--input-focus-outline-offset": "2px",
882
+ }}
883
+ />
884
+ \`\`\`
885
+
886
+ ### Dark Theme Input
887
+ \`\`\`tsx
888
+ <Form.Input
889
+ styles={{
890
+ "--input-bg": "#2a2a2a",
891
+ "--input-color": "#e5e7eb",
892
+ "--input-border": "1px solid #4b5563",
893
+ "--input-focus-outline": "2px solid #3b82f6",
894
+ }}
895
+ />
896
+ \`\`\`
897
+ `,
898
+ },
899
+ },
900
+ },
901
+ } as Story;
@@ -221,3 +221,161 @@ export const UrlInput: Story = {
221
221
  expect(input).toHaveValue("https://example.com");
222
222
  },
223
223
  } as Story;
224
+
225
+ /**
226
+ * CSS Variable Customization
227
+ *
228
+ * Demonstrates how to customize input appearance using the new standardized
229
+ * CSS custom property naming convention.
230
+ *
231
+ * New variable naming patterns:
232
+ * - Logical properties: `--input-padding-inline`, `--input-padding-block`
233
+ * - Full property names: `--input-width`, `--input-radius`, `--input-border`
234
+ * - Focus state variables: `--input-focus-outline`, `--input-focus-outline-offset`
235
+ * - Disabled state variables: `--input-disabled-bg`, `--input-disabled-opacity`
236
+ * - Approved abbreviations: `--input-fs` (font-size)
237
+ */
238
+ export const Customization: Story = {
239
+ render: () => (
240
+ <div style={{ display: "flex", flexDirection: "column", gap: "2rem", maxWidth: "600px" }}>
241
+ {/* Custom brand styling */}
242
+ <div>
243
+ <h4>Custom Brand Styling</h4>
244
+ <Input
245
+ type="text"
246
+ placeholder="Enter your email"
247
+ styles={{
248
+ "--input-padding-inline": "1rem",
249
+ "--input-padding-block": "0.75rem",
250
+ "--input-border": "2px solid #0066cc",
251
+ "--input-radius": "0.5rem",
252
+ "--input-fs": "1rem",
253
+ }}
254
+ />
255
+ </div>
256
+
257
+ {/* Custom focus indicator (WCAG compliant) */}
258
+ <div>
259
+ <h4>Custom Focus Indicator (WCAG AA Compliant)</h4>
260
+ <Input
261
+ type="text"
262
+ placeholder="Focus me to see custom outline"
263
+ styles={{
264
+ "--input-focus-outline": "3px solid #0066cc",
265
+ "--input-focus-outline-offset": "2px",
266
+ "--input-border": "1px solid #ccc",
267
+ }}
268
+ />
269
+ </div>
270
+
271
+ {/* Custom disabled state */}
272
+ <div>
273
+ <h4>Custom Disabled State</h4>
274
+ <Input
275
+ type="text"
276
+ disabled={true}
277
+ placeholder="Disabled input"
278
+ value="Cannot edit"
279
+ styles={{
280
+ "--input-disabled-bg": "#ffe6e6",
281
+ "--input-disabled-opacity": "0.7",
282
+ "--input-border": "1px dashed #999",
283
+ }}
284
+ />
285
+ </div>
286
+
287
+ {/* Compact input */}
288
+ <div>
289
+ <h4>Compact Input (Logical Properties)</h4>
290
+ <Input
291
+ type="text"
292
+ placeholder="Compact"
293
+ styles={{
294
+ "--input-padding-inline": "0.5rem",
295
+ "--input-padding-block": "0.25rem",
296
+ "--input-fs": "0.875rem",
297
+ "--input-width": "200px",
298
+ }}
299
+ />
300
+ </div>
301
+
302
+ {/* Spacious input */}
303
+ <div>
304
+ <h4>Spacious Input</h4>
305
+ <Input
306
+ type="text"
307
+ placeholder="Spacious"
308
+ styles={{
309
+ "--input-padding-inline": "1.5rem",
310
+ "--input-padding-block": "1rem",
311
+ "--input-fs": "1.125rem",
312
+ "--input-radius": "0.75rem",
313
+ }}
314
+ />
315
+ </div>
316
+
317
+ {/* Dark theme example */}
318
+ <div
319
+ style={{
320
+ background: "#1a1a1a",
321
+ padding: "1.5rem",
322
+ borderRadius: "0.5rem",
323
+ }}
324
+ >
325
+ <h4 style={{ color: "white", marginTop: 0 }}>Dark Theme Example</h4>
326
+ <Input
327
+ type="text"
328
+ placeholder="Search..."
329
+ styles={{
330
+ "--input-bg": "#2a2a2a",
331
+ "--input-color": "white",
332
+ "--input-border": "1px solid #4b5563",
333
+ "--input-focus-outline": "2px solid #3b82f6",
334
+ "--input-focus-outline-offset": "0",
335
+ "--placeholder-color": "#9ca3af",
336
+ }}
337
+ />
338
+ </div>
339
+ </div>
340
+ ),
341
+ parameters: {
342
+ docs: {
343
+ description: {
344
+ story: `
345
+ ## Available CSS Variables
346
+
347
+ ### Base Properties
348
+ - \`--input-padding-inline\`: Horizontal padding (logical property)
349
+ - \`--input-padding-block\`: Vertical padding (logical property)
350
+ - \`--input-width\`: Input width (default: clamp(200px, 100%, 500px))
351
+ - \`--input-border\`: Border style
352
+ - \`--input-radius\`: Border radius
353
+ - \`--input-bg\`: Background color
354
+ - \`--input-outline\`: Default outline
355
+
356
+ ### Typography (Approved Abbreviation)
357
+ - \`--input-fs\`: Font size
358
+
359
+ ### Focus State Variables (NEW)
360
+ - \`--input-focus-outline\`: Outline when focused
361
+ - \`--input-focus-outline-offset\`: Outline offset (for WCAG compliance)
362
+
363
+ ### Disabled State Variables (NEW)
364
+ - \`--input-disabled-bg\`: Background when disabled
365
+ - \`--input-disabled-opacity\`: Opacity when disabled
366
+ - \`--input-disabled-cursor\`: Cursor style when disabled
367
+
368
+ ### Placeholder Variables
369
+ - \`--placeholder-color\`: Placeholder text color
370
+ - \`--placeholder-fs\`: Placeholder font size
371
+ - \`--placeholder-style\`: Placeholder font style (italic)
372
+
373
+ ### Migration from Old Names
374
+ - ❌ \`--input-px\` → ✅ \`--input-padding-inline\`
375
+ - ❌ \`--input-py\` → ✅ \`--input-padding-block\`
376
+ - ❌ \`--input-w\` → ✅ \`--input-width\`
377
+ `,
378
+ },
379
+ },
380
+ },
381
+ } as Story;
@@ -11,7 +11,47 @@ const meta: Meta<typeof Figure> = {
11
11
  actions: { argTypesRegex: "^on.*" },
12
12
  docs: {
13
13
  description: {
14
- component: "Figure description here...",
14
+ component: `A semantic figure component for displaying images with captions, using CSS custom properties for flexible styling.
15
+
16
+ ## CSS Variables
17
+
18
+ Customize the Figure and Image appearance using CSS custom properties:
19
+
20
+ ### Image Variables (img[alt])
21
+ - \`--img-max-width\`: Maximum width (default: \`100%\`)
22
+ - \`--img-height\`: Height value (default: \`auto\`)
23
+ - \`--img-display\`: Display type (default: \`inline-block\`)
24
+ - \`--img-object-fit\`: Object fit mode (default: \`cover\`)
25
+ - \`--img-object-position\`: Object position (default: \`center\`)
26
+ - \`--img-aspect-ratio\`: Aspect ratio (default: \`auto 2/3\`)
27
+
28
+ ### Figure Variables (figure:has(img[alt]))
29
+ - \`--fig-display\`: Display type (default: \`flex\`)
30
+ - \`--fig-padding\`: Figure padding (default: \`0.5rem\`)
31
+ - \`--fig-bg\`: Background color (default: \`rgba(245, 245, 245, 0.683)\`)
32
+ - \`--fig-width\`: Max width constraint (default: \`fit-content\`)
33
+ - \`--fig-bottom\`: Figcaption bottom offset (default: \`var(--fig-padding)\`)
34
+ - \`--fig-left\`: Figcaption left offset (default: \`var(--fig-padding)\`)
35
+ - \`--fig-right\`: Figcaption right offset (default: \`var(--fig-padding)\`)
36
+
37
+ ### Figcaption Variables
38
+ - \`--caption-padding\`: Caption padding (default: \`var(--spc-3)\`)
39
+
40
+ **Example:**
41
+ \`\`\`css
42
+ figure:has(img[alt]) {
43
+ --fig-padding: 1rem;
44
+ --fig-bg: #f5f5f5;
45
+ --fig-width: 40rem;
46
+ --caption-padding: 1.5rem;
47
+ }
48
+
49
+ img[alt] {
50
+ --img-max-width: 100%;
51
+ --img-object-fit: contain;
52
+ --img-aspect-ratio: 16/9;
53
+ }
54
+ \`\`\``,
15
55
  },
16
56
  },
17
57
  },
@@ -39,20 +39,20 @@ img[alt] {
39
39
  figure {
40
40
  &:has(img[alt]) {
41
41
  --fig-display: flex;
42
- --fig-p: 0.5rem;
42
+ --fig-padding: 0.5rem;
43
43
  --fig-bg: rgba(245, 245, 245, 0.683);
44
- --fig-w: fit-content;
44
+ --fig-width: fit-content;
45
45
  display: var(--fig-display);
46
46
  position: relative;
47
- padding: var(--fig-p);
47
+ padding: var(--fig-padding);
48
48
  background-color: var(--fig-bg);
49
- max-width: var(--fig-w);
49
+ max-width: var(--fig-width);
50
50
  > figcaption {
51
51
  position: absolute;
52
- bottom: var(--fig-bottom, var(--fig-p));
53
- left: var(--fig-left, var(--fig-p));
54
- right: var(--fig-right, var(--fig-p));
55
- padding: var(--caption-p, var(--spc-3));
52
+ bottom: var(--fig-bottom, var(--fig-padding));
53
+ left: var(--fig-left, var(--fig-padding));
54
+ right: var(--fig-right, var(--fig-padding));
55
+ padding: var(--caption-padding, var(--spc-3));
56
56
  background-color: var(--fig-bg);
57
57
  }
58
58
  }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Image component styles
3
+ *
4
+ * Applies to all images with alt attribute (both decorative alt="" and semantic).
5
+ * Uses CSS custom properties for flexible theming and responsive behavior.
6
+ */
7
+ img[alt] {
8
+ /* CSS Custom Properties - Override these for customization */
9
+ --img-max-width: 100%;
10
+ --img-height: auto;
11
+ --img-object-fit: cover;
12
+ --img-object-position: center;
13
+ --img-aspect-ratio: auto 2/3;
14
+ --img-display: inline-block;
15
+
16
+ /* Layout - Responsive by default */
17
+ max-width: var(--img-max-width);
18
+ max-inline-size: var(--img-max-width); /* Logical property for i18n */
19
+ block-size: var(--img-height);
20
+ display: var(--img-display);
21
+ vertical-align: middle;
22
+
23
+ /* Object fitting for responsive images */
24
+ object-fit: var(--img-object-fit);
25
+ object-position: var(--img-object-position);
26
+ aspect-ratio: var(--img-aspect-ratio);
27
+
28
+ /* Accessibility - Italic font for broken image alt text */
29
+ font-style: italic;
30
+
31
+ /* Background for loading state */
32
+ background-size: cover;
33
+ background-repeat: no-repeat;
34
+
35
+ /* Shape margin for text wrapping */
36
+ shape-margin: var(--spc-3);
37
+ }
38
+
39
+ figure {
40
+ &:has(img[alt]) {
41
+ --fig-display: flex;
42
+ --fig-p: 0.5rem;
43
+ --fig-bg: rgba(245, 245, 245, 0.683);
44
+ --fig-w: fit-content;
45
+ display: var(--fig-display);
46
+ position: relative;
47
+ padding: var(--fig-p);
48
+ background-color: var(--fig-bg);
49
+ max-width: var(--fig-w);
50
+ > figcaption {
51
+ position: absolute;
52
+ bottom: var(--fig-bottom, var(--fig-p));
53
+ left: var(--fig-left, var(--fig-p));
54
+ right: var(--fig-right, var(--fig-p));
55
+ padding: var(--caption-p, var(--spc-3));
56
+ background-color: var(--fig-bg);
57
+ }
58
+ }
59
+ }
@@ -9,24 +9,24 @@ header,
9
9
  --overlay-display: grid;
10
10
  // Overlay padding
11
11
  --overlay-padding: 2rem;
12
- --overlay-w: 100%;
13
- --overlay-h: 40vh;
14
- --overlay-max-h: 500px;
12
+ --overlay-width: 100%;
13
+ --overlay-height: 40vh;
14
+ --overlay-max-height: 500px;
15
15
  --overlay-color: currentColor;
16
- --overlay-content-w: 80%;
16
+ --overlay-content-width: 80%;
17
17
  --overlay-gap: 2rem;
18
18
  --overlay-bg: whitesmoke;
19
- --overlay-px: auto;
20
- --overlay-py: auto;
21
- --overlay-mx: auto;
22
- --overlay-my: auto;
19
+ --overlay-padding-inline: auto;
20
+ --overlay-padding-block: auto;
21
+ --overlay-margin-inline: auto;
22
+ --overlay-margin-block: auto;
23
23
 
24
24
  grid-template-areas: 'overlay';
25
25
  display: var(--overlay-display);
26
26
  place-items: var(--overlay-placement);
27
27
  align-items: var(--overlay-placement);
28
- min-height: var(--overlay-h);
29
- width: var(--overlay-w);
28
+ min-height: var(--overlay-height);
29
+ width: var(--overlay-width);
30
30
  color: var(--overlay-color);
31
31
  background-color: var(--overlay-bg);
32
32
  min-width: 20rem;
@@ -34,16 +34,16 @@ header,
34
34
  grid-area: overlay;
35
35
  }
36
36
  > img {
37
- width: var(--overlay-w);
37
+ width: var(--overlay-width);
38
38
  // height: auto;
39
39
  background-size: contain;
40
40
  }
41
41
  > div,
42
42
  > section {
43
43
  --overlay-display: flex;
44
- max-width: var(--overlay-content-w);
44
+ max-width: var(--overlay-content-width);
45
45
  padding-inline: var(--spc-4);
46
- margin-inline: var(--overlay-mx);
46
+ margin-inline: var(--overlay-margin-inline);
47
47
  gap: var(--overlay-gap);
48
48
  text-align: center;
49
49
  p {
@@ -54,7 +54,7 @@ header,
54
54
  }
55
55
  > h1,
56
56
  > h2 {
57
- line-height: var(--header-lh, 1.1);
57
+ line-height: var(--header-line-height, 1.1);
58
58
  font-weight: 500;
59
59
  }
60
60